Blog from February, 2010

Test news (confluence wiki problems)

Wiki problems fixed by relocating Delta Shell wiki to external server.

Integration of JIRA with Subversion

Arthur asked me if Subversion can be enabled in JIRA and it after playing a bit it seems to work!

I enabled JIRA for our project as shown on the following screenshot:

... after that I also found a nice plugin for TortoiseSVN (handy features). This plugin extends TortoiseSVN with JIRA support allowing to select issues instead of typing their names, so:

  1. Make sure to install SvnPluginInstall.msi.
  2. Enable it in TortoiseSVN using TortoiseSVN -> Settings -> Issue Tracker Integration. Click the "Add..." button and see if the provider "CSharpTest.Net.SvnPlugin.MyPlugin" appears. Type D:\src\delta-shell there or other path to you source code.

As result it should display a nice dialog showing list of JIRA issues.

Also it seems to work with filters defined in JIRA so we can define filter for every sprint!

Let's use it?

Implicit operator

The implicit keyword is used to declare an implicit user-defined type conversion operator.
In other words, this gives the power to your C# class, which can accepts any reasonably convertible data type without type casting. And such a kind of class can also be assigned to any convertible object or variable. e.g.

class MyType 
{
   public static implicit operator int(MyType m) 
   {
      // code to convert from MyType to int
   }
}

e.g. within DeltaShell

public string Path { get; set; }

public static implicit operator TestDataPath(string path)
{
     return new TestDataPath { Path = path };
}

public static class Plugins
{
     public static class Habitat
     {
         public static readonly TestDataPath DeltaShellPluginsImportersHabitatTests = "DeltaShell.Plugins.Habitat.Tests";
         public static readonly TestDataPath DeltaShellPluginsHabitatTests = "DeltaShell.Plugins.Habitat.Tests";
     }
}
New solution created in branch

New solution is in branches/new-layout (not 95% finished but must be tested first).

https://repos.deltares.nl/repos/delft-tools/branches/new-layout

Please avoid renaming / moving files or folders if you will work in the trunk/ until it is replaced by new-layout (Monday evening). Any changes will need to be merged manually.

NOTES:

1. Changed directory layout to:

build/ ........................ build scripts and build tools
    tools/
    ...
doc/ .......................... documentation
lib/ .......................... shared libraries (binaries)
src/ .......................... source code only (!)
test/ ......................... test projects, groupped in the same way as src
test-data/ .................... data used in tests

Files in the lib, src, test, test-data directories are groupped using the following rules:

  • All directories always use the same structure as an src
  • lib/ additionally contains some libraries at the top-level used by many products

2. Created temporary branch: new-layout

3. Moved folders and projects around ... a lot!!!

4. Renamed all folders and projects from DelftShell ... to DeltaShell (DelftTools.* remain the same)

5. Trying to fix solution,

TODO:

(plus) Found how to detect parent directory in DOS (awkward): "for %%a in (%PROJECT_DIR%\..) do set PLUGIN_TYPE_DIR=%%~nxa" plugin native resources should be copied fine now
(plus) Fixed many projects using ExternalDependencies (DeltaShell.proj):

    <ExternalDependencies>lib\DeltaShell\DeltaShell.Plugins.SharpMapGis</ExternalDependencies>

(plus) Fixed resource files (DeltaShell / DeltaShell - made consistent)

(minus) probably some projects should be moved from Common to default plugin level (avoid re-use by others) ...

(minus) Isolate Habitat1 dlls including Demis.MapControl (remove them, replace by dlls in lib compiled in Habitat1 branch)
(minus) Move Habitat 1 projects to branch\ and leave only required dlls in lib\Plugins\Habitat (old version)
(minus) Setup projects must be organized in accordance to plugins - IT'S A MESS NOW!!
(minus) Clean-up FitNesse tests (clean up unused tests)
(minus) REVIEW ALL TESTS DATA (too big)
1. Move data to test-data/ folder
2. Check if large data files used in integration tests can be compressed
(minus) MOVE src\Plugins\DelftModels\Externals\ds\common\packages\delft_model_data to test\ folder (not sources)
make it checkout only required C# projects on a higher level
(minus) Habitat proj file in build\ is not a good idea!!! move it to build/Plugins/Habitat.proj
(minus) Habitat inside DeltaShell\Product.wxs?!?! WTF!?!??
(minus) CommonToolsPlugin.wxs should be in DeltaShell/
(minus) DelftModels\Product.wxs is referencing ico from Habitat project!?!?!? WTF ?!@?
(minus) HabitatLogo.png in IJselmeerVerkenner ?!?? WTF?
(minus) Move OpenMI to standard DeltaShell plugins (after migration to 2.0)?
(minus) Why there is a "copy "$(SolutionDir)lib\DeltaShell\DeltaShell.Gui\license.lic" .\" in DeltaShell.Loader.csproj ?!? Sobek?
(minus) Make SharpMapTestUtils and DelftTools.TestUtils consistent (chose one convention)
(minus) INTRODUCE RULE: if you include project on a file system - it must be available in the solution, otherwise remove it from the file system as well!
(minus) ONE MORE RULE - NO HIDDEN FILES in projects!
(minus) NetTopologySuite.Extensions referencing NHibernate.dll WTF?!?
(minus) move lib\DeltaShell\DeltaShell.Plugins.SharpMapGis\ to lib\Common\SharpMap.Extensions?
(minus) The following projects need to be included into the solution (migrated) or deleted:
src\Plugins\Examples\DeltaShell.AutomationDemo
src\Plugins\Examples\DeltaShell.Plugins.TriangulatorPlugin
test\Plugins\Examples\DeltaShell.Plugins.DemoImportPlugin.Test
test\Plugins\Examples\DeltaShell.Plugins.TriangulatorPlugin.Tests
test\Plugins\Habitat\TransformOldCases
test\Plugins\Habitat\Habitat.Tests

(minus) DeltaShell.Plugins.SharpMapGis.csproj references NHibernate.dll - remove it!?
(minus) DeltaShell.Plugins.Series.csproj references NHibernate.dll
(minus) write test checking number of csproj in solution and on file system (should match (smile))
(minus) walk through ALL projects and remove PLUGIN -> PLUGIN dependencies!
(plus) WTF, why SharpMapGis plugin references DeltaShell.Core???
(plus) FIX ALL NAMESPACES
(minus) Loader is referencing Common projects so that they will be copied to Loader/bin/ - discuss!
(minus) FIX images, some are DeltaShell.* and also not used
(minus) REMOVE / MOVE TO OLD CODE DeltaShell.Plugins.Demis.MapControl ??? (not used in the current solution)
(minus) I had to comment some code to make everything work, check diff on revision when new-layout branch was created
(plus) Strange that it was necessary to re-reference NetTopologySuite, do we have it as DLL somewhere??
(minus) REMOVE reference to DeltaShell.Plugins.SharpMapGis in SharpMap.UI.Tests!
(minus) make SharpMap.Extensions.Xml work (current excluded), migrate from plugin (pull-up)
(minus) search all project for DelftShell and fix it (some dirs, files need to be renamed)
(minus) check ALL hidded files not included into project and clean-up!
(minus) Rename DeltaShell.Plugins.KRWVerkenner in source code tree to something more intuitive for all users (including non-Dutch), e.g.: DeltaShell.Plugins.BasinModels (basin management), move it into DelftModels

(minus) DON'T just blindly merge all tests - look at dependencies! DelftTools.Tests contains tests of Functions, Hydro, Controle.Swf - too many dependencies in test projects
(minus) RENAME all DelftShell namespaces to DeltaShell where required (all except Common/DelftTools.*)
(minus) FunctionPoint.cs - Huh?

(minus) Ask Arno if we can remove DeltaVerkenner plugin (leaving only GIS functionality he uses)
(minus) Do we need to support MWell in DeltaShell.sln (is it used??) Ask Bary/Tom

(minus) NetworkEditor is a HydroNetworkEditor, right? Maybe we need Hydro plugin containing various edtors (Basin, HydroNetwork, etc.)
(minus) Strange properties in DeltaShell.Loader resources, e.g.: "DelftShellFolderFileFilter: Delta Shell Folder File (.folder)|*.folder" - check where they are used and remove

Open-source projects switching to SharpTestEx (aka NUnitEx)

See this thread: http://groups.google.com/group/nhibernate-development/browse_thread/thread/fa265875404f96f4

They don't do it with existing tests but will use it to write new tests.

  • Macro to generate boundary condition and run model
  • Generate macro to create selected model (using menu, Macro -> Generate Create Macro for Selection)
  • Focus on very simple solutions
  • Create networks based on another network which has only small changes (e.g. weir parameters)
  • Run multiple models on different servers from a single GUI
Suggested solution structure

After discussion with the team we agreed that Delta Shell solution structure will be changed to:

Advantages of the new structure are:

  • Much more clear separation of concepts
    • Common Domain Libraries - mainly libraries containing interfaces plus various reusable components
    • Delta Shell - includes environment, graphical user interface and common plugins such as file format, netcdf, project explorer
    • Application Plugins - high-level application plugins such as Habitat, River Flow Model 1D etc.

Why it is better?

  • Current structure does not make clear separation on common and application plugins
  • Common libraries are not located in one place
  • Stimulates stabilization of the common libraries - all what becomes domain-related tends to move up to the Common, otherwise stays on the application plugin level
  • Default Delta Shell plugins are located next to Delta Shell.

The following was also concluded:

  • Dependencies between plugins are forbidden - if you need it - add it to some common library on a plugin level or later on a higher Common level
  • Common goal is to stabilize Common libraries, boyscout rule applies 100% here: leave the code a little cleaner than you found it. ... simpler, more tested, more correct.
  • In a bit longer term Common probably should include only facade / interface classes and implementation can be hidden and accessible only using Container Libraries (IoC, DI).

Actions to be taken during the first step:

  • A lot of subversion move actions
  • A lot of project file text editing actions
  • Making sure everything still compiles and runs
  • Removing unnecessary dependencies (while playing with projects I've detected ~10 wrong dependencies!)
Preventing memory leaks with NHibernateProjectRepository objects

NHibernateProjectRepository creates and manages NHibernate SessionFactory objects. A SessionFactory object has a Dispose method that must be called to clean up resources. Otherwise, the SessionFactory objects will remain in memory and will not be garbage collected.

NHibernateProjectRepository, IProjectRepository and (I)ProjectService all have a Dispose method, to make sure all resources are cleaened up.

If you use NHibernateProjectRepository or ProjectService in your tests, always call the Dispose method when you're finished! Otherwise, you will get memory leaks and possibly other tests failing because of out of memory errors!

 

Gena:

Here are 2 code snippets:

[TestFixture]
public class ProjectIntegrationTest
{
    [Test]
    [Category("DataAccess")]
    public void SaveProject()
    {
            using (var repository = new NHibernateProjectRepository()) // <== Disposed() automatically
            {
                var project = new Project();

                repository.Create(path);
                repository.SaveOrUpdate(project);

                using (var repository2 = new NHibernateProjectRepository()) // <== Disposed() automatically
                {
                    repository2.Open();

                    retrievedProject = repository2.GetProject();

                    // ... asserts ...
                }
            }
      }
}

Another way, if test class has a lot of such integration tests:

[TestFixture]
[Category("DataAccess")]
public class ProjectDataAccessTest
{
    NHibernateProjectRepository repository;

    [SetUp]
    public void SetUp()
    {
        repository = new NHibernateProjectRepository();
    }

    [TearDown]
    public void TearDown()
    {
        repository.Dispose();
    }

    [Test]
    public void SaveProject()
    {
            var project = new Project();

            repository.Create(path);
            repository.SaveOrUpdate(project);

            using (var repository2 = new NHibernateProjectRepository()) // <== Disposed() automatically
            {
                repository2.Open();

                retrievedProject = repository2.GetProject();

                // ... asserts ...
            }
      }
}

... or just make sure you call it explicitly (smile)

DataItemSet refactoring

Today DataItemSet got a lot simpler (smile) It no longer keeps track of an internallist but instead
provides a AsEventedList<T>() method which you can use to get an adapted 'list' version of the set.

This works by returning an adapter which implement IEventedList<T> but redericts all calls to a list
of dataitems. Changes in the dataitems are propagated as changes in the list and ideally the model-developer only uses the list.

Breaking changes:

  • No longer can use Value as a hook to get the internallist ...there is no internal list.
More about test driven development, unit testing, and mock objects

Some useful articles on test driven development, unit testing, and mock objects:

I came across some interesting articles about technical dept and the design of death which we may encounter during development on the DeltaShell parts.

"You have a piece of functionality that you need to add to your system. You see two ways to do it, one is quick to do but is messy - you are sure that it will make further changes harder in the future. The other results in a cleaner design, but will take longer to put in place.
Technical Debt is a wonderful metaphor developed by Ward Cunningham to help us think about this problem. In this metaphor, doing things the quick and dirty way sets us up with a technical debt, which is similar to a financial debt. Like a financial debt, the technical debt incurs interest payments, which come in the form of the extra effort that we have to do in future development because of the quick and dirty design choice. We can choose to continue paying the interest, or we can pay down the principal by refactoring the quick and dirty design into the better design. Although it costs to pay down the principal, we gain by reduced interest payments in the future." Martin Fowler: Technical Dept

Other good articles about this topic:
Eric Ries: Lessons learned:Embrace technical depth
Kane Mar: Technical Debt and Design Death
Dave Laribee: Using Agile Techniques to Pay Back Technical Debt and 9 Useful Tactics for Paying Back Technical Debt

Don't forget this one:
software-debt

Product owner links