Sunday, February 23, 2014

Strategic DDD in a nutshell

There are two big parts to Domain Driven Design; strategy and tactics. Strategy helps setting out a high-level grand design, while tactics enable us to execute on the strategy.

Practicing strategic design, we generally first try to list all of the different parts that make our business a whole; these are sub-domains. When you look at a supermarket chain, you would find sub-domains like real estate management, advertising, suppliers, stock, sales, human resources, finance, security and so on. Sub-domains will often relate to existing structures like departments and functions.

Once you've defined your sub-domains, it's useful to determine how important of a role they play. First of all, you should figure out which sub-domain is most important to your business; the core domain. This is the sub-domain that differentiates you from other businesses, or more bluntly put; this is where the money is at. For our super market chain, this might not be that obvious for an outsider. A first uneducated guess would be sales, but if you gave it some more thought, you would realize that sales are very similar for most supermarkets. Digging deeper, we would find that supermarkets really compete with each other by squeezing the last bit of value out of suppliers and by collecting data to use for targeted advertising. Supplier management and advertising can't stand on their own though; they need other sub-domains like stock and sales. These are supporting sub-domains; they are not core, but our business couldn't do without them either - they still add a bunch of value. Other sub-domains like property management, human resources or security are generic sub-domains; these problems have been widely addressed and solving them yourself won't make you any money.

Having a map of which areas are most important to your business makes it easy to distribute brain power accordingly. Make sure your core domain gets the most capable team assigned, before any other supporting sub-domain. Try to buy solutions of the shelve for generic sub-domains.

The concept of sub-domains lives in the problem space. The solution space on the other hand is where bounded contexts are at. Domain Driven Design tries to define natural boundaries between parts of your solution by putting the language first. These boundaries allow us to keep a language and model consistent inside of them, protecting conceptual integrity.
If you would ask a marketer what a product is, he would talk about images, campaigns, weekly promotions and so on. If you'd ask sales on the other hand, they would only mention price, quantity and loyalty points. The same concept can turn into something completely different depending on how you look at it. Bounded contexts enable us to build a ubiquitous understanding of concepts in a clearly defined context.

Mapping a bounded context to exactly one sub-domain would be DDD nirvana; addressing one problem with one focused solution. In the real world, things are more messy though. There will always be systems out of our control; for example legacy and third party software. As our understanding of the business grows, keeping our software aligned can be hard too. If we would lay out a map of sub-domains and bounded contexts we would see lots of overlap.

Bounded contexts will often be worthless on their own though; most useful systems exist of interconnected parts. If you have worked in the enterprise, you know how complex communication between teams and departments can be. This isn't very different while integrating bounded contexts; you need to consider politics. This is where concepts like up-stream, down-stream, bandwidth, partnership, shared kernel, customer-supplier, conformist, anti-corruption layer etc come into play. The activity of thinking about and capturing how all these systems play together is called context mapping.
In our example, we notice that supplier- and stock management would fail or succeed together; they have a partnership where the bandwidth is very high - the teams sit across the hall from each other. Human resources and security on the other hand have a very different relationship. A product was bought for human resources, while a solution for security was outsourced. Security relies quite heavily on what the human resources' open host service is exposing. If a product version bump changes those exposed contracts, security needs to comply as soon as possible; security is down-stream from human resources - shit floats down-stream.

For me, strategic DDD in one sentence, is the constant exercise of trying to see and understand your business at large, and aligning your software as efficiently as possible.   

Sunday, February 16, 2014

DDDBE slides on the Ubiquitous Language

Monday, I and four others did a DDDBE session on the strategic side of Domain Driven Design.

My talk covered the Ubiquitous Language, and can be found on Slideshare or embedded below. I might end up writing down the content of the talk as well - some images are meaningless without words. 

Evaluating feedback, I think the biggest mistake we made was keeping some things too abstract - curse of knowledge at work. If we get the chance to repeat the session, we need to make sure to weave a practical story through our talks to make them stick.

Sunday, February 9, 2014

Reading an EventStore stream using JavaScript

Over Christmas break, I set out three days to play with the EventStore. One of the things I wanted to do was visualize the timeline of a stream in the browser. Since the EventStore exposes its event streams over atom in JSON, I could directly consume them from JavaScript.

An event stream can contain quite a few events. Since caching parts of that stream benefits all components in the system, the atom feed is split in multiple pages - where all full pages are cacheable. Thus if you want to read the entire event stream, you should work your way through all pages. What confused me at first, but what actually is quite logical, is that the last entry on the last page contains the first event. If you want to read the entire stream, you need to start at the last page, and work your way forward following the link to the previous page until there are no pages left to read.


I came up with something like this.
StreamFeedReader : function(feedUri) {   

    if (!feedUri) {
        throw new Error('feedUri missing.');
    }        
    
    var readLastFromHead = function (streamName) {                                        
        var dfd = $.Deferred();

        $.ajax({
            url : feedUri + streamName + '?embed=body'
        }).done(function (data) {                
            var lastLinks = data.links.filter(function(link) { 
                return link.relation === 'last'; 
            });                       

            if (lastLinks.length > 0) {               
                dfd.resolve(lastLinks[0].uri);           
            } else {
                dfd.resolve(feedUri + streamName);
            }
        }).fail(function() {                           
            dfd.reject();
        });

        return dfd.promise();
    };              

    var traverseToFirst = function (uri, entries, dfd) {                                                       
        $.ajax({
            url: uri + '?embed=body'
        }).done( function (data) {       
            var reversedEntries = data.entries.reverse();

            for (var i = 0; i < reversedEntries.length; i++) {
                entries.push(reversedEntries[i]);
            }            

            var previousLinks = data.links.filter(function(link) { 
                return link.relation === 'previous'; 
            });            

            if (previousLinks.length === 1) {
                traverseToFirst(previousLinks[0].uri, entries, dfd);
            } else {                
                dfd.resolve(entries);
            }           
        }).fail(function() {
            dfd.reject();
        });                    
    };  

    this.read = function (streamName) {                   
        if (!streamName) {
            throw new Error('streamName missing.');
        }  

        var dfd = $.Deferred();                           
        
        readLastFromHead(streamName).done(function(lastUri) {
            var entries = [];                        
            traverseToFirst(lastUri, entries, dfd);                        
        }).fail(function() { 
            dfd.reject(); 
        });    

        return dfd.promise();              
    };

}
First read the link to the last page. From there, read the entries on that page, look at the links on that page and start making your way forward, traversing the pages to the first one. All events on the page should also be reversed before they get pushed to the result.

Using this snippet, you can read a stream and have all events returned in the sequence they were appended.
new es.StreamFeedReader('http://127.0.0.1:2113/streams/')
    .read('account-35')
        .fail(function() {
            test.ok(false, 'reading the stream failed.');
            test.done();
        })
        .done(function(res) {
            var streamContainsAllEvents = function() {
                test.equal(651, res.length, 'expecting 651 events in stream.');
            };
            var eventsInStreamAreOrdered = function() {
                var ordered = true;
                for (var i = 1; i < res.length; i++) {
                    if (res[i - 1].eventNumber > res[i].eventNumber) {                            
                        ordered = false;
                    }
                }
                test.ok(ordered, 'event numbers out of order.');
            };

            streamContainsAllEvents();
            eventsInStreamAreOrdered();                                

            test.done();
        });
This code is also available on GitHub.

Sunday, February 2, 2014

Thinking in Systems

We are surrounded by systems day in, day out. As software developers, we even get to spend a big portion of our day actively building and changing systems - be it software, teams, communities or businesses. Seeing the whole, but more importantly understanding how systems exist of inter-related parts that affect each other in all kinds of interesting ways, is crucial to growing sustainable systems.

Thinking in Systems is a primer on the subject of system thinking written by Donella H. Meadows. The book is divided into three parts. The first part explains the basic concepts of system thinking using everyday systems. The second part covers why systems work so well, why they still surprise us, how to avoid common system traps and how to take advantage of some of the opportunities they present. The last part, and for me the most interesting part, shows where to intervene in a system and how to live in a world of systems.

Although the subject is pretty involved, the material is presented in a very consumable fashion, preparing you for more academic material. This is probably the book to read when you want to be introduced to systems thinking.

Here are the sections I highlighted.
Everyone or everything in a system can act dutifully and rationally, yet all these well-meaning actions too often add up to a perfectly terrible result.
You think that because you understand "one" that you must therefore understand "two" because one and one make two. But you forget that you must also understand "and".
Purposes are deducted from behavior, not from rhetoric or stated goals. 
Enough central control to achieve coordination toward the large-system goal, and enough autonomy to keep all subsystems flourishing, functioning and self-organizing. 
If you become a manager, you probably will stop seeing labor as a deserving partner in production, and start seeing it as a cost to be minimized. 
The structure of a commons systems makes selfish behavior much more convenient and profitable than behavior that is responsible to the whole community and to the future. 
If the desired system state is good education, measuring that goal by the amount of money spent per student will ensure money spent per student. If the quality of education is measured by performance on standardized tests, the system will produce performance on standardized tests. Whether either of these measures is correlated with good education is at least worth thinking about. 
There is a systematic tendency on the part of human beings to avoid accountability for their own decisions. 
If you want to understand the deepest malfuctions of systems, pay attention to the rules and who has power over them. 
So how do you change paradigms? You keep pointing at the anomalies and failures in the old paradigms. You keep speaking and acting, loudly and with assurance, from the new one. You insert people with the new paradigm in places of public visibility and power. You don't waste time with reactionaries; rather, you work with active change agents and with the vast middle ground of people who are open-minded. 
If no paradigm is right, you can choose whatever one will help to achieve your purpose.
There's something within the human mind that is attracted to straight lines and not curves, to whole numbers and not fractions, to uniformity and not diversity, and to certainties and not mystery.