Home > Point2 - Technical > SOLID with Uncle Bob

SOLID with Uncle Bob

March 10, 2009

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.

By: Todd Sturgeon

  1. seanjreilly
    March 11, 2009 at 10:15 AM

    Great post Todd!

    “No cycles in thee dependency graph – C# enforces this for us, others do not”

    I would say that C# doesn’t enforce this: dependency != inheritance. However, constructor based dependency injection (as opposed to setter based injection) does ensure that there are no cycles in the dependency graph.

    Could you go into a bit more detail about CCP, REP, and CRP?

    • toddsturgeon
      March 12, 2009 at 12:24 AM

      @seanjreilly, my understanding from the talk was that C# will not allow cycles in the assembly reference graph. I cannot confirm this because in 6 years the thought never crossed my mind to try to create such a cycle, lol. There’s a partial dependency cycle in our DB project though, that shows up only in a clean build from scratch, so I can confirm they are not good things.

      Basically Martin said that in C++, a cycle would immediately explode your build times so high you would likely fix the problem, but in Java, the problem could be small enough that you compound the problem before it gets bad enough that you try to fix it.

      He didn’t address cycles in class dependencies directly, but yeah, if you inject dependencies in the constructor, you wouldn’t get a cycle. Not all class collaborators are dependencies though.

      On the project I’m currently working on, this concept of separation of “above the line” code is exactly what I wanted to achieve with the DomainLogic project, but maybe creating a separate project for “above the line” also violates the package design principles. I’d have to look into that when it’s not so late. 🙂

  2. March 11, 2009 at 10:21 AM

    My pair and I were wondering yesterday how SOLID related to code smells.

    It seems like when you’re refactoring you’re guided by one of the two (a SOLID principle or a code smell), but do they mesh well?

    Also, I’m glad you asked about DDD, there’s been a lot of buzz about that around here recently.

    • toddsturgeon
      March 12, 2009 at 12:45 AM

      @Kevin, I also attended some talks today from Josh K (Refactoring to Patterns). I’ll blog about them too when I get a chance. The #1 code smell is duplication, other smells are dead code, poor naming, long method, large class, long param lists. Many of these smells suggest you might be violating the Single Responsibility Principle. If your names have the word “And” in them, you might be violating SRP.

      Writing tests first will also help you identify distinct responsibilities early, but it’s totally ok to refactor to SRP and other SOLID patterns rather then design up front.

      In the same way, writing test first will make you a client of your class before you write it, so your naming will be better up front for free with TDD, but don’t spend big time up front thinking of the perfect name. Rename over time as your understanding of the system increases, and as the responsibilities of your classes get spilt out into different classes.

  1. No trackbacks yet.
Comments are closed.
%d bloggers like this: