Natural Aggregates vs Synthetic Aggregates

Friday, 20 August 2010 08:47 by ebenroux

In databases we have natural keys such as company code, client number, and order number.  Then we have synthetic keys that are typically globally unique identifiers (GUID) or auto-incrementing numbers (IDENTITY).

It seams to me that we may need to make this same natural and synthetic distinction when it comes to aggregates in domain-driven design (DDD).  The whole Aggregate Root (AR) concept makes it extremely difficult to define certain structures; especially when starting out with DDD.  I find the reason being that some entities don't work well as aggregate roots either:

  1. because the aggregate root seems to change depending on context; or
  2. the entity is not a natural fit for an aggregate root.

An example of a natural aggregate is something like Order and OrderLine.  An order line can never exist without an order.

  • Order has a Total that is calculated by summing the OrderLine Totals.
  • Total on order cannot mean anything other than the total of the order lines.

An example of a synthetic aggregate is something like GrapeBunch containing a GrapeStem and a GrapeBerry collection.

  • GrapeBunch can have a Weight that is calculated by summing the Weight of each GrapeBerry in the collection and adding the Weight of the GrapeStem.
  • The weight of the grape bunch cannot mean anything other than the sum of the grape berry weights and adding the weight of the grape stem.

An example of a problematic aggregate by using an aggregate root is GrapeStem with a GrapeBerry collection.

  • What does the Weight on GrapeStem mean?
  • We could have another mothed called TotalWeight but this is confusing.

So, although an aggregate root can be made to work it just does not feel very comfortable.

Categories:  
Actions:   E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

Entity vs. Value Object

Thursday, 19 August 2010 08:54 by ebenroux

This is another question that keeps popping up on the Domain-Driven Design group.  It seems to be a difficult task and some of the answers seem to complicate matters since they come from a technical context.

How do you use your object?

The same concept may very well be implemented as a value object in one context and as an entity in the next and depending on the type of object this distinction would be more, or less, pronounced.  So it is important to understand how you intend using the object.  If you are you interested in a very particular instance it is an entity and that's that.  An object like an Employee or an Invoice can immedsiately be identified as an entity since we are all familiar with these concepts and 'know' that we need to work with specific instances.  So we'll take something a bit more fluid like an Address

Now when would an Address need to be an entity?  Well, do we care about a specific instance?  Is our application (in our Bounded Context) interested in a particular address?

Example 1: Courier - Delivery Bounded Context

Let's imagine that we are couriers and when we receive a parcel we need to deliver it to a recipient at a particular address.  Since we specialise in same-day business delivery we frequently deliver to office blocks that have the same street address but may house many of our clients.  Here we care about a particlar Address and we link recipients to it.  The Address is an Entity.

Example 2: Courier - HR Bounded Context

In our courier company we also have an HR system so we store Employee objects.  Each employee has a home address stored as fields in the employee record in our database.  However, in our object model we have an Address object represented by the Employee.HomeAddress property (this is just for illustration so we won't split hairs as far as software design is concerned).  In this case it seems quite obvious that Address has to be a value object since it is purely a container.

So let's say this same Employee object can have a list of ways to contact the employee and we model a ContactMethod class.  In our data store we will have a one-to-many relationship between our Employee table and the ContactMethod table.  In fact, we go so far as to give ContactMethod an Id so that we can directly update the data in the database (for whatever reason).  ContactMethod would be aggregated with Employee so whenever we save the employee the contact methods are re-populated in the database (deleted and re-inserted).  The ContactMethod is still a value object.  Even though it may have its own life-cycle and identifier we do not care about a specifc instance in our application.  We will never, and can never, say "go and fetch me contact method... {what}".  So there is no way to uniquely identify a Value Object using the Ubiquitous Language for our domain even though it may have an identifier that is universally unique.  It is simply a synthetic key used for technical efficiency.

Immutable Value Objects

Some folks are of the opinion that value objects must be immutable.  This is not necessarily so.  As with our first address example an immutable value object would mean we need to create a new instance to make simple changes such as fixing a spelling mistake.  It is perfectly acceptable to use immutable objects but there is also no reason why we can't change the properties of the same object instance.  The only time that an immutable value object would be required is when the object instance is shared.  But the only time you would share a value object in this way is when you are implementing the flywieght pattern and those cases are pretty rare.

 

 

How easy is ORM?

Tuesday, 10 August 2010 09:22 by ebenroux

I subscribe to Code Project newsletters.  So this morning I receive one with the following blog post:

Mixing Table Per Hierarchy and Entity Splitting

And all I can ask myself is how this makes anything easier?

Just do your own mapping and be done with it already.

Categories:  
Actions:   E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

Aggregate Roots vs. Single Responsibility (and other issues)

Tuesday, 27 July 2010 10:34 by ebenroux

It is interesting to note how many questions there are around Aggregate Roots.  Every-so-often someone will post a question on the Domain-Driven Design Group regarding how to structure the Aggregate Roots.  Now, I may be no genius but there are too many questions for my liking.  It indicates that something is hard to understand; and when something is hard to understand it probably highlighting a larger problem.

Aggregate vs. Aggregate Root

"Cluster ENTITIES and VALUE OBJECTS into AGGREGATES and define boundaries around each.  Choose one ENTITY to be the root of the AGGREGATE, and control all access to the objects inside the boundary through the root." (Evans, p. 129)

In one of Eric's presentations he touches on this; stating the difference between an Aggregate and an Aggregate Root.  I have mentioned Eric's bunch of grapes example in a previous post so I will not re-hash it here.

The gang of four has two principles of object-oriented design:

  1. "Program to an interface, not an implementation." (Gamma et. al. p. 18)
  2. "Favor object composition over class inheritance." (Gamma et. al. p. 20)

So what's the point?  At first glance it seems that we are working with composition for both the Aggregate and the Aggregate Root.  On page 128 of Eric's blue book there is a class diagram modelling a car.  The car class is adorned with two stereotypes: <<Entity>> and <<Aggregate Root>>.

Single Responsibility?

So is an Aggregate Root called Car sticking to the Single Resonsibility Principle?  It is responsible for Car behaviour; but also for the consistency within the Aggregate since it now represents an Aggregate with the Car entity as the Root.  It seems as though the Car is doing more than it should and I think that this leads to many issues.

Could it be that the Car Aggregate Root concept is a specialisation of the Car entity?  So, following this reasoning it is actually inheritance.  The reason we do not see it is because it is flattened into the Car entity and, therefore, the car no longer adheres to SRP.  My reasoning could be flawed so I am open to persuasion.

Does the Aggregate Root change depending on the use case?

The problem the Aggregate Root concept is trying to solve is consistency.  It groups objects together to ensure that they are used as a unit.  When one looks at the philosophy behind Data-Context-Interaction (DCI) it appears as though the context is pushed into the root entity.  When a different context (use-case) enters the fray that also makes use of the same Aggregate Root it appears as though the Aggregate Root is changing.

There has been some discussion around the issue of the Aggregate Root changing depending on the use case, i.e. a different entity is regarded as the root depending on the use case.  Now some folks state that the Aggregate Root isn't really changing but the fact that it appears to be changing should be an indication that you are working with different Bounded Context.  Now this is probably true; especially since the word context make an appearance.

A quick note on Bounded Contexts:

Let's stay with the Car example.  Let's say we have a car rental company and we have our own workshop.  Now our car could do something along the lines of Car.ScheduleMaintenance(dependencies) and Car.MakeBooking(dependencies).

This is where issues start creeping into the design.  The maintenance management folks don't give two hoots about rentals and, likewise, the rental folks are not too interested in maintenance; they only want to know whether the car is available for rental.  Enter the Bounded Context (BC).  We have a Maintenance Management BC and Rental Administration BC.  Of course we would probably also need a Fleet Management BC with e.g Car.Commission() and Car.Decommission().

The particular Car is the same car in the real world.  Just look at the registration number.  However, the context within which it is used changes.  It is, in OO terms, a specialization of a Car class to incorporate the context.  This inevitably leads to data duplication of sorts since the data for each BC will probably be stored in different databases.

Assuming we view this as a problem, how could we solve this?  As proposed by the GoF we could try composition.  In DCI terms the context can aggregate the different entities.  I previously blogged about an aneamic use-case model and the context looks an awful lot like a use-case.  I have not played around with how to get these concepts into code but we'll get there.

Repositories return Aggregate Roots?

Now this one is rather weird.  I have no idea where this comes from.  For those that have the Domain-Driven Design book by Eric Evans it is a simple case of opening the front cover and having a look at the diagram printed on the inside where it clearly shows two arrows that point to Repositories.  One comes from Entities and the other from Aggregates (note: not Aggregate Root), like so:

  • [Entities] --- access with --> [Repositories]
  • [Aggregates] --- access with --> [Repositories]

Now if you subscribe to the fallacy that repositories only return aggregate roots then you are really restricting your design.

WCF issues

Friday, 28 May 2010 12:42 by ebenroux

I installed a WCF client on a test machine this morning.  Since it is using message encryption I installed the relevant certificate in the TrustedPeople store.

When the application started I received the following exception:

X509InvalidUsageTime

Turns out that the machines date was incorrect and fell outside of the certificate's valid period.  A quick date change fixed that.

All was still not well as I swiftly moved on to the following exception:

MessageSecurityException

After some investigation and searching the Net it turned out that the time was way off too and that threw something out of joint.  Setting the time to something more relevant sorted that.

So do make sure that you have your servers and workstations more-or-less synchronised.

Tags:  
Categories:   WCF
Actions:   E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

"Silo, where are you!"

Thursday, 27 May 2010 09:19 by ebenroux

I just read an interesting article.

The reason I say it is interesting is that silos have been denounced for quite some time now, and they should be.  Yet, here is someone that appears to be a proponent thereof:

"Silos are the only way to manage increasingly complex concepts"

Almost well said.  I would paraphrase and say:

"Bounded Contexts are the only way to manage increasingly complex concepts"

But bounded contexts do not solve complexity on their own.  You definitely need a sprinkling of communication between them.  A lack of communication is what leads to silos.  Communication is a broad term but in this sense is simply means we need a publish / subscribe mechanism between the bounded contexts so that relevant parties are notified when a particularly interesting event takes place.

Without such communication systems duplicate data that does not directly relate to the core of that system.  In this way systems get bloated, difficult to maintain, and complex to integrate with other systems.  Eventually someone will come up with the grand idea of a single, unified system to represent everything in the organistion.  Enter the über silo.  At this point we can say hello to a 3 to 5 year project and after the first 90% the second 90% can begin.

Don't do it!

There is an aggregate root in my soup!

Thursday, 8 April 2010 10:01 by ebenroux

So there is another discussion around value objects and repositories on the domain driven design yahoo group.  In this case it revolves around a the definition of a Country.

Firstly, a repository should return an entity; never a value object.  Well, so the definition goes.  One may want to break that rule but it probably is not necessary.  Now the definition of a value object vs. an entity has been rehashed to a point of boredom but another way to look at a value object is a value (albeit a composite value) that never changes.  The date '27 April' never changes.

But getting back to a country: one would hear an argument along the lines of the name of a country being able to change.  Actually, no.  It doesn't.  A new country comes into being.  The fact that Rhodesia became Zimbabwe does not mean that the country of Rhodesia no longer exists (as a value object that we care about).  It may not be any use in the present or ever again in the future but it definitely did exist.  The capital Salisbury was never in Zimbabwe; it was in Rhodesia.

It may seem a bit confusing when a value object appears to have an identity; or even when is does have an identifier.  The fact of the matter is that there are different codes that countries may be referred to.  But the thing to note is that those codes do not change either.

Now if we make a country an entity suddenly 3 different databases can have 3 different IDs.  This happens quite readily when using synthetic keys for entities and aggregate roots; even though they may have some stable, unchanging natural key.  Something I'll discuss in another post.

Categories:  
Actions:   E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

More or less exactly the same

Tuesday, 2 March 2010 09:13 by ebenroux

In high school I had a maths teacher that would show us various problems with solutions and simply state that they are "More or less exactly the same".

I recently came across the Infinite Monkey Theorem.  This got me thinking about how we humans approach some things in a really weird way.  I mean, having a random number generator create the complete works of Shakespeare (or any body of work for that matter) is just plain silly.  The probability is somehow calculated.  Now, I believe some things are not possible, or even probable.

When one switches on a television that has not been tuned you see some form of Brownian Movement.  This seems quite random to me.  In fact, we can simulate the same thing using a computer and simply place dots all over the display; something, I'm sure, most programmers have done at some stage while learning to code.

Taking into account how many possible images exist one may expect that at some stage a recognizable image would appear.  It never will.  It seems strange to say that since the probability associated with a recognizable image is now a big fat 0.

What is the probability of taking a tour through the universe and digging through every single planet and finding a perfectly formed clay brick.  I mean, a simple brick.  Not something that looks like a brick.  Even that seems strange.

The big thing is that we have intelligence on our side.  Our DNA contains informattion that didn't appear at random.  Having a bunch of monkeys type up the text in the latest copy of People magazine seems trivial compared to that.

To summarise: saying something is so doesn't necesaarily make it so, even if you use a mathematical model.
Categories:   Personal | Religion
Actions:   E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

Why *I* think software fails

Friday, 12 February 2010 07:56 by ebenroux

Since the software industry has now been around for quite some time it is possible to look at the statistics around software failure.  Although a great deal has been written and said about software development failure there is probably not too much in the line of anything that can be done about it.  There should be.

Looking at the history of software development it is quite easy to blame the process or method used to manage the development.  Software development is a broad discipline encompassing quite a number of spheres so singling out any particular cause is quite difficult.  That is why there are so many lists specifying the reasons for software failure, e.g.:

There are even good suggestions in there as to what can be done.

Software fails because it sucks

Now that was simple.  But why does it suck?  What makes it suck?  I was watching a podcast by David Platt about his book on the subject and he said a very interesting thing:

"...that's using the computer to do what the computer is good at so the human can do what the human is good at."

This immediately stood out because it has been my experience that as soon as one tries to implement functionality in any system that is flexible it becomes extremely complex.  Anything flexible is not only easy for humans to grasp and do, but also very obvious.  Unfortunately, the geniuses in the chip-making industry have yet to come up with the 'obvious chip'.  That is why one would, as a software developer, explain a particularly complex problem to someone (like a business analyst or a domain expert) and get a response of "So what's the problem?".  They typically don't realize that the human brain is OK with fuzzy logic but that fuzzy logic cannot be represented very well by a simple algorithm.

Defining complexity

When I think about software complexity Roger Sessions always comes to mind.  From what I loosely recall he has mentioned that complexity in a system increases as the number of states increase and complexity between systems increases drastically as the number of connections between them increases.  And then, of course, within a system there is also the coupling aspect in terms of class interaction.

So the following are the main culprits in the complexity game:

  • Heuristic level required
  • Number of states
  • Coupling (intra- and inter-system)

How could we prevent the failures

I read Re-imagine! by Tom Peters a few years back and if memory serves that is where I read:

"Fail faster, succeed sooner."

Sounds very agile to me.  So the quicker we can prove that a specific technology, product, or development project is not going to work, the better.  Another approach would be to burn $10,000,000 of your client's money and keep on keeping on until your momentum runs out.  At *that* point there will be anger, finger-pointing, tears, blows, and in all probably a good measure of litigation.

Granted, there are definitely systems that require heuristics and it is a rather specialised area that may require expertise in areas that the normal run-of-the-mill software developer simply does not have.  It is hard enough keeping abreast of changes in technology.  Software developers are not accountants, pharmacists, inventory managers, logistics experts, statisticians, or mathematicians.  Yet we find ourselves in situations where we are simply given a vague direction to go in and 'since we are so sharp' we'll just figure it out.  Maybe.  Probably not.  That is why a domain expert is so crucial to software success.  A business analyst would find themselves in the same quandry as a programmer.  They document things but may not have the required extertise either (although some may).  This is why management commitment is also listed quite often in the lists of reasons for software failure.  Management needs to ensure that the domain experts are indeed available.

Technology to the rescue! Not.

Many companies are lead to believe that their problems are related to technology.  Now sometimes the latest technology would help and sometimes old technology simply becomes obsolete.  But more often than not it is a case of a vendor telling the client that they simply need to use a single platform along with all the merry products that are built there-on.  But a quick visit to the common sense center of the brain will tell the client that it may just be that they merge with another company in future and then there may be different technologies at play or they may purchase a product that relies on different technology altogether.

A homogenous technology environment will definitely not solve anything and is somewhat of a pipe dream in any but the simplest environments.

Products to the rescue!

OK, so we'll throw in a rules engine, workflow engine, CRM, CMS or any other COTS product and voilá!  We'll simply build on top of that.  The thing is: each product satisfies a specific need.  By the time most folks realise that there is no one ring to rule them all it has all gone south.

Heuristic level / Flexibility

Too many systems try to do too many things.  I once worked on a system that was, essentially, a loan management system.  It has been in development for over three years with a constant team of around twenty folks and I don't think it will see the light of day.  One thing the client does in their daily life is to authorise loans or extensions on loans based on a motivation.  Now this motivation document has traditionally been typed up in a word processor.  In one instance a loan of say $10,000 needs to be authorised to a small company.  Now, not much motivation required in this case since it is a small risk.  Half a page did the trick.  In another case a $20,000,000 loan needs to be scrutinized.  Here a decent document is required that contains the company structure along with directors and lists of securities, and so on and so forth.  This was put into the system along with all the input required to make this authorisation document work.  It is total unnecessary to do so.  Absolutely no value is gained by doing so.  Just link to the original document or scan it in.  Extreme complexity and cost was added for very little value.

Number of states

This part is actually slightly related to coupling anyway.  One of the examples used by Roger Sessions is that of a coin.  A coin has two sides: heads or tails.  So there are two states that one needs to test for in your system.  But how about two coins: heads-heads or heads-tails or tails-heads or tails-tails.  OK, that was only four.  But how about 3 coins.  Well, that would be eight combinations since it is 2 ^ 3.

Now to be honest that wasn't too bad.  But let's take a dice.  Six sides there, so six states.  Two dice would be 6 ^ 2 = 36 and 3 dice would be 6 ^ 3 = 216.

The only way to reduce this complexity is to reduce the states.  At least, we need to reduce the coupling of the states so that, in our dice example, we have 3 independent dice so the number of states is 6 + 6 + 6 = 18 ( a *lot* less that 216) if we could find a way to separate the states from each other.

Coupling

I have blogged about coupling before.  As software developers we need to identify different bounded contexts (as per Eric Evan's Domain-Driven Design) and implement them independently of each other and I have a sneaky suspicion that this is more-or-less what Roger Session does with his simple iterative partitions.  The problem here is: how?

Quite a few of the lists of reasons for software failure include skill level as a factor.  However, even highly skilled developers may get this wrong.  So the software will still fail.  A highly coupled system or enterprise solution is very, very fragile.

Service-Orientation and Tacit Knowledge

The key to decoupling bounded contexts or ending up with simple partitions is service-orientation.  But it has to be done right.  A service bus is all good-and-well but that other technology we need to talk to in our hetergenous environment is problematic.  A possible solution to that interaction is bridging between the various service bus implementations so that the systems remain unaware of the other systems.  Of course, most companies probably will not find themselves in such a position but it is a way to handle different technologies.

How would one actually go about stringing all these bits together?  The answer is obviously not that simple since all the knowledge and experience required cannot really be measured.  I think the reason for this is that it falls into the realm of tacit knowledge.

The best thing to do for companies is to keep trying new ideas on a small or experimental projects and then to see whether something useful can be produced.  Take the ideas developers and others have and give it a bash.  The Big-Bang kind of approach has proven itself to be a mistake time-and-time again so growing something in an organic way may be best.  There is also nothing wrong with 'shedding some pounds' as we move along.

A last word on Tasks vs. Functions

Over the years I have found that we as developers tend to develop software that is a real pain to use since we are not the ones using it.  Giving a user a bunch of loose ends does not help.  As an example I would like to use my Room2010 site that I actually developed for myself and then had to tweak:

Anyone can register a free accommodation listing.  At a later stage they may choose to upgrade to a premium listing.  They can then send me up to 10 images that I will upload.  So here is the problem:  I had a function in my system where I could mark a listing as premium.  I could then manage the images by browsing to the image locally on my disk and then uploading it.  I had to do this for each image received.  The only problem was that I received images of various sizes that all had to be scaled to 200 x 150.  So before uploading I had to use a graphics package to change the sizes.  Quite a tedious affair really. 

So I created a small Windows application where I simply specify the listing number to process.  The images I received would be stored in their original format in the relevant listing folder.  Once I say GO the system would talk to the website and set the listing to premium, the images would be resized, compressed and uploaded.  As a last step the site would be instructed to send an e-mail to the owner of the listing notifying them of the changes.

So a whole host of functions were grouped together to accomplish a simple task.

Our software needs to be simple to use.

How I got a context menu onto my Google Maps API V3

Tuesday, 9 February 2010 09:34 by ebenroux

I have a jquery context menu plug-in that I have been using for a while.  As things go the context menu is attached to the relevant element (my map div) like so:

$('#map-canvas').contextMenu('context-menu', {options});

This is all good-and-well except that when the map is rendered all kinds of magic happens that basically means my context menu is never displayed.  This is in all likelihood because the Google Maps populates the map canvas div with elements that obvious do not have my context menu attached.

So the approach I took was to somehow tell the context menu to pop up where I need it.  But then I couldn't find a context menu that had a simple Show or Display or PopUp method (maybe I just missed it).  So the next step was to trigger the 'contexmenu' event on the map-canvas div.

First I needed to add an event listener for the rightclick event on the map that would call the openContextMenu function.  However, the event object passed to the function by Google Maps is a MouseEvent class.  This only has a latLng property specifying the latitude and longitude.  From this I needed to get the XY pixel coordinates.  Fortunately there is a MapCanvasProjection object that can return a Point from the fromLatLngToContainerPixel method.  Unfortunately the MapCanvasProjection object cannot be returned from the map but rather from an overlay.  So after some googling I found a bit of code on StackOverflow that does just that.

If anyone has a more elegant way to achieve the same thing please let me know.

Here is the complete code:

var map;
var mapOverlay;
var contextMenuEvent;

$(document).ready(function() {
    var sw = new google.maps.LatLng(-34.80, 16.43);
    var ne = new google.maps.LatLng(-22.06, 32.75);
    var bounds = new google.maps.LatLngBounds(sw, ne);

    map = new google.maps.Map($("#map-canvas").get(0), { mapTypeId: google.maps.MapTypeId.ROADMAP });

    map.setCenter(bounds.getCenter());
    map.fitBounds(bounds);
    map.enableKeyDragZoom();

    mapOverlay = new MapOverlay(map);

    google.maps.event.addListener(map, "rightclick", openContextMenu);

    $.contextMenu.defaults(
      {
          menuStyle:
         {
             width: '200px'
         }
      });

    $('#map-canvas').contextMenu('context-menu', {
        bindings:
      {
          'context-menu-zoom-in': function(trigger) {
              map.setZoom(map.getZoom() + 1);
          },
          'context-menu-zoom-out': function(trigger) {
              map.setZoom(map.getZoom() - 1);
          },
          'context-menu-center-map': function(trigger) {
              map.setCenter(contextMenuEvent.latLng);
          }
      }
    });
});

function openContextMenu(e) {
    var ev = new jQuery.Event('contextmenu');

    var p = mapOverlay.getProjection().fromLatLngToContainerPixel(e.latLng);

    ev.pageX = p.x;
    ev.pageY = p.y;
   
    contextMenuEvent = e;

    $('#map-canvas').trigger(ev, [e.latLng]);
}

MapOverlay.prototype = new google.maps.OverlayView();
MapOverlay.prototype.onAdd = function() { }
MapOverlay.prototype.onRemove = function() { }
MapOverlay.prototype.draw = function() { }

function MapOverlay(map) { this.setMap(map); }

Tags:   ,
Categories:   Google Maps | jQuery
Actions:   E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed