Monday, April 18, 2011

Notes from DDD & CQRS training - day 1

My notes from the 1st day (11/04/2011) of the DDD/CQRS training by Greg Young, just as I took them - very little post-processing applied so it might be of little help for anyone but me (or maybe other participants of the training).

UIs:

  • CRUD (these suck)
  • task-based (users like those)
Aggregate:
  • group of object we treat together as a whole
  • affect only a single aggregate - that lets you avoid distributed transactions (think horizontal partitioning/sharding)
  • put the method next to the state it operates on is
  • denormalization helps to get the design right
Booksto read:
  • Streamlined object modelling 
    • time interval object
    • make implicit explicit
  • Object-oriented software construction 2nd edition by Bertrand Meyer
    • describes CQS 
saving two objects = bad

  • business doesn't care about consistency
  • breaking bidirectional relationships
    • ask: do those things need to be consistent? 
    • drop consistency of invariant
  • domain model != data model
  • if needed, a Domain Service can ensure consistency (this should really be used only as a last resort!)
  • collection of Transaction objects can have a domain meaning
  • AggregateRoot (AR) name makes sense for the entire aggregate
  • too much magic is bad (think ORM)
  • between aggregates use soft links (IDs) instead of references
TIP: keeping track of Optimistic Concurrency Exceptions makes an interesting statistic

EXERCISE: test-drive Probability value object class with methods like combine(Probability), not() etc, encapsulating a Java's BigDecimal (.NET's Decimal?). The tricky part: you can't have any kind of accessor methods to expose the internal state. What do you test first?

And now... suppose that standard BigDecimal implementation is too slow for your system. You have to change the implementation of the Probability class but retain the API. How many tests do you have to change?

personal note: this turned out to be an easy, yet an interesting exercise. Funny, how it changes the way you write code when you don't have those evil getters around. I really, really liked it!

Repository:
  • Evans: works on aggregates, provides domain language to persistence infrastructure
  • Fowler: purely technical stuff

  • make contracts in the domain:
    • as narrow as possible
    • as explicit as possible
  • this will lower the conceptual coupling
Service:
  • any piece of procedural code
  • can be:
    • infrastructure
    • domain
    • application
  • but it the end they are all facades
  • if you do things right you might never need services
  • interface segregation
    • single method interfaces
    • role interfaces
Hexagonal architecture - ports & adapters

TIP:
 why not check check-ins for illegal dependencies (like domain depending on something else) and reject those that don't follow the rules?

On SOLID principles:
  • they are just heuristics
  • don't try to stick to them no matter the cost (duplication sometimes can be a good thing!)
EXAMPLE: When not to adhere to Interface Segregation?
  • when all methods go the the same source
    class Stream implements ICanSeek,ICanRead,ICanWrite
    // client code:
    void DoesSomething(ICanSeek seeker, ICanRead reader) {
      seeker.seekTo(0);
      while (var x = reader.read() != null) {
      /...
      }
    }
    ICanSeekRead extends ICanSeek,ICanRead != Foo implements ICanSeek, ICanRead
    • DI/IoC:
      • ServiceLocator is totally OK when resolving things at the same layer
      • about injecting into entities: most dependencies match the lifecycle of methods, not objects 
    void Submit(ISearchDriverLicences s) {
      s.searchFor("something");
    }
    void F() {//coupling from F to G
      G.Something();
    }
    interface ISomething{
      something();
    }
    void F(ISomething s) { 
      s.something();
    }
    class ISomethingImpl:ISomething {
      // sometimes DI is too much:
      void something(){
        Console.WriteLine("Hello world");
      }
    }
    • we're overusing tools, frameworks 
      frameworks pollute our brains

      Back to services:

      • ApplicationServices 
        • should be role interfaces, one for every use case of the system
        • you should have no business logic in them (not even an if statement!)
      isValid() antipattern
      • pure evil!
      • don't do that!
      • causes GIGO (Garbage In, Garbage Out)
      • entities end up being in one of 3 possible states:
        • valid
        • invalid
        • have no frakking clue
      • encapsulation is about protecting state - don't let people jam it!
      Specification
      • (wikipedia)
      • predicate logic (think Prolog)
      • might need getters (protected/internal) exposed
        • but people will start using them as soon as they see them
      • composite specification
      public class AService {
        AService( IEnumerable<Specification<Customer>>  
          rules){}

        void deactivate(Customer c) {
          if(!rules.areAllValid(c) { 
            throw new IllegalArgException(); 
          }
          ...
        }
      }

      === END OF DAY 1 ===
          
      Unfortunately, those notes don't show how absolutely awesome the training was. Really got my eyes wide open on many issues that I was somehow missing before.

      On a related note - people really do use functional programming in real-world applications! After hearing that from Greg I started learning Clojure. I had a Prolog & Haskell course back at the university. I didn't like the Prolog part but really enjoyed writing minimized code in Haskell. Now I just have to find some time to refresh by skills at functional programming. Or better - find some use for it so I can justify re-learning it at work ;)

      No comments:

      Post a Comment