Clojure
Functional SOLID – Open/Closed Principle
Continuing on the series about SOLID principles on functional programming, the next one is the Open/Closed Principle. The definition from the Wikipedia:
The open/closed principle states “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”; that is, such an entity can allow its behavior to be extended without modifying its source code.
This is kinda interesting on its own way: what’s an “extension”? Considering the context when it was written, and future interpretations of the principle, the idea is that any program should not be re-compiled (re-written, modified, etc) to be extended. The idea of this principle is that local changes should not propagate to other parts of the program: make entities as self-contained as possible, write then in a way that extensions would not depend on modifications on these entities, then “close” then to modifications. I can see two cases for the “open-closed principle” violation, and the first one is the most common:
(defn as-int [some-str] (when (re-matches #"\d+" some-str) (Integer/parseInt some-str)))
This code returns an Integer
if it can parse a string as a number, and nil
if it can’t. Now, suppose we want to “extend” this functionality by accepting other objects like Double
(truncates to integer) or nil
(returns 0
). The only way to do it is to change the when
to a case
, but that means that for every new implementation I’ll have to change this function. Now, a better way is to use protocols:
(more…)