Tuesday, March 10, 2009

SOLID with Uncle Bob


This morning I attended a course on class and component design by Robert C. Martin.

Class Design

You can read about the SOLID Principles here, but he emphasized a couple of things that would help in applying the principles:

  1. Objects don't really model the "real world" because the real world lies to us: real-world objects would violate the Single Responsibility Principle; Liskov Substitution Principle means real world IS-A relationships do not imply inheritance in classes, only "is-substitutable-for" relationships

  2. I asked if this conflicts with Domain Driven Design in any way. It doesn't, because the DDD people are still modeling your domain in a fine-grained enough way to satisfy the Single Responsibility Principle

  3. You won't be able to predict what will and will not change, so don't spend too much effort on that. Instead use TDD to develop simpler class structures, and refactor to Open/Closed later, as requirement changes come up

  4. That these are heuristics - instead of trying in vain to follow them all the time, you should design "above the line" and "below the line" classes


Above the Line:

  • abstract classes

  • business logic

  • closed for modification, except for the relatively uncommon case where you are changing the business rules encapsulated in them

  • open for extension, by concrete classes below the line

  • abstract factories

  • more stable code, changed less often, harder to change because it has more dependencies on it


Below the Line:

  • implementations of the abstractions above the line

  • messy things, like dependencies on external services, databases, GUIs, printers

  • e.g. changing a dependency from a database call to a web service call would not change the business logic above the line, you would just change a factory somewhere to sub in the new dependency for the old one

  • factory implementations

  • less stable code, changes often, because you want to change it often, and easier to change because it has few dependencies on it


Interesting point: if an abstract factory method accepts an enum parameter to determine the runtime type of the return value, then that constitutes the Above the Line code knowing about the implementing types, which is not desirable. If you just pass in a string, then you have weak typing, at least in that one place, but you'll be following SOLID. Ok, I lied about this point being interesting.

Component Design- depending on your language, this refers to packages, JAR files, DLLs, projects, whatever you call the group of classes you build and deploy together

  • No cycles in thee dependency graph - C# enforces this for us, others do not

  • The other three main rules: CCP, REP, CRP - contradict each other. Early in a project's life, use more CCP. As a project matures, you'll need to move classes into different components based on REP, CRP

  • Components should be independantly deployable. Versioned components are good things - release a version while keeping the old version up and running for a while, during which its dependents release new versions of themselves with the newer dependencies

  • Independent deployablility does not mean you must deploy independently to production, it just means different teams can develop components separately and deploy to test servers separately, and have independent CI builds.

No comments:

Post a Comment