DelftTools and DelftShell

A few days ago we had a very long discussion with Onno related to organization of classes in DelftTools Framework and DelftShell Gui, the result of discussion was that current organization of some classes / interfaces is a bit too coupled. Especially in Service interfaces which actually were introduced more as mix of Service and Controller in DelftTools.Gui and implemented in the DelftShell.Gui. The following was concluded:

  • Services were not Services but Contollers mixed with Service
  • IApplication has no Services and required to do all operations via IGui.AbcService - strange (warning)
  • Implementation of IApplication and IGui is mixed in one class - DelftShell and as result does not allow to use application intependently from gui, neither it allows to implement gui logic independently from application.
  • Gui and Application is mixed in DelftShell project.

Interfaces were organized in the following way:

  • DelftTools.Core project
    • IApplication
  • DelftTools.Gui project
    • IGui
    • Services/
      • IProjectGuiService
      • ITaskGuiService
      • IModelGuiService
      • IDataItemGuiService

... and before that Bert asked me a few quesitons related to organization of classes in the DelftShell which also puzzled me a little. So I had no other choice than to refactor it immediatelly (smile).

Also I had a short look on DDD book (Domain-Driven Design Quickly by Erik Evans) and some applications like MonoDevelop - they use Service principle, Resharper and a few others. Main conclusion from DDD book was:

...there are some actions in the domain, some verbs, which do not seem to belong to any object. They represent an important behavior of the domain, so they cannot be neglected or simply incorporated into some of the Entities or Value Objects. Adding such behavior to an object would spoil the object, making it stand for functionality which does not belong to it. Nonetheless, using an object-oriented language, we have to use an object for this purpose. We can't just have a separate function on its own. It has to be attached to some object. Often this kind of behavior functions across several objects, perhaps of different classes. For example, to transfer money from one account to another; should that function be in the sending account or the receiving account? It feels just as misplaced in either.
When such a behavior is recognized in the domain, the best practice is to declare it as a Service. Such an object does not have an internal state, and its purpose is to simply provide functionality for the domain. ...

  • Services are stateless - in our case means they won't remember objects given as parameters to their functions.
  • Services will help to work with our Entities, such as Project, Model, Task, etc.
  • It was logical to make these services independent from Gui - will provide better maintenability and faster response for changes.

As a result the following reorganisation of classes emerged:

As you can notice some of the service methods which have something to do with Gui, mainly those are parameter-less methods, were moved into GuiCommandHandler.

Interfaces shown on a class diagram contained in the following projects:

  • DelftTools.Core project
    • IApplication
    • Services/
      • IProjectService
      • ITaskService
      • IModelService
      • IDataItemService
  • DelftTools.Gui project
    • IGui
    • IGuiCommandHandler

After such a change it was logical to re-organize DelftShell project as well in one shot into DelftShell.Core and DelftShell.Gui:

And as result the same refactoring was applied to all AbcGuiService classes.

Interesting thing is that during this refactoring many non-logical pieces of code were found and refactored or removed so it is not only "moving code around" step but also overall code cleanup.

PS: there is still some crappy code left, mainly in GuiCommandHandler, but it will be much easier to clean it by moving non-gui related functionality into Service classes in DelftShell.Core.

SplashScreen

Another relatively small implementation I made is related to the SplashScreen, I noticed that it started to ... kind of ... hanging on 50% (warning). It was expected since first version implemented for Habitat, Verkenner used a bit get-it-work-fast approach. In short - approach has been changed and splash screen is now more inteligent, it has simple AI. It uses log4net to catch all log messages sent with a log level >= Info and also updates progress bar in a smart way. Algorithm implemented is based on the log messages and timing information from the previous application start-up which is stored in the: "C:\Documents and Settings\<user>\Local Settings\Application Data\Deltares\DelftShell\splash-screen-log-history.xml" file. Information is collected during the first application run. After that splash screen is able to update progress bar very precisely during all next runs of the application. Idea was suggested by Andre - thanks!

Design was also a little bit changed - feel free to criticize and suggest a better one (wink).

Update: 29-05-2008

  • No labels