DILOS in Clojure

Malina Tran
Tech and the City
Published in
3 min readJul 24, 2016
Meet Colin Jones. He also works at 8th Light!

I watched Colin Jones’s talk, SOLID Clojure from Clojure/west in 2012. It served as a great transition from object-oriented mode of thinking to functional programming! What made it relevant was how Jones framed these principles as problem statements. This made me better understand why any of this even mattered.

The five principles, which Jones humorously reverses and calls ‘DILOS’, included the following:

  • Dependency inversion. In object-oriented programmed, this principle basically states the following: higher-level modules should not depend upon lower-level modules (rather, both should depend on abstractions) and abstractions should never depend upon concretions or details (rather, details should depend on abstractions). Doing so will ultimately reduce coupling between units of code. After all, a change in one place will cascade to too many other places in the code. So, why the hype about abstractions? They factor out inner details so that there is more flexibility in a function’s use; being concerned about how something is implemented allows the function (and us) to focus on it single purpose, which leads to the last principle. In Clojure, there are abstractions such as `defprotocol` and `defmulti`; namespaces can also be considered abstractions.
  • Interface segregation. This principle states that clients shouldn’t have to depend on abstractions that they don’t use. Large interfaces should be split into smaller, more specific ones so that clients will only have to know about the methods that are of interest to them. This means reasonably small, cohesive namespaces and protocols are the way to go. Overall, this makes it easy to reason about the code. I’ve definitely encountered this issue in the Ruby version of my tic-tac-toe game, where I felt as if I was passing in objects to other classes that only required a method or two, not the entire object.
  • Liskov substitution. Breaking down Barbara Liskov’s definition: if S is a subtype of T, then objects of T can be replaced with objects of S without altering properties of that program. In the context of Jones’s talk, he clarifies that problem is when the particular concretion is not substitutable for its abstraction.
  • Open-closed. A rather prevalent problem is that the addition of a new feature may require changes to an existing code. The idea is that the code should be open for extension, but closed for modification (as in, it doesn’t touch existing source code). Traditional object-oriented solutions require using polymorphism and switching on type, as well as using wrappers for existing libraries. Multimethods in Clojure make things more extensible; they allow you to have different ways of dispatching based on more granular details.
  • Single responsibility. A unit of code that has too many clients can lead to a cause for pain and lead to potentially-conflicting changes. So, why change that code? It makes it simpler for us to wrap our minds around the code. In object-oriented program, single-responsibility can be thought of at a class-level; in Clojure, we can think about it at both a protocol level and function level. After all, it’s easier to reason about a function that does a singular thing than understand a bloated function in all of its complexity.

--

--