Record of experiments, readings, links, videos and other things that I find on the long road.
Registro de experimentos, lecturas, links, vídeos y otras cosas que voy encontrando en el largo camino.
Wednesday, August 30, 2017
Books I read (January - August 2017)
- Vencidos pero vivos (Vaincus mais vivants), Maximilien Leroy and Loïc Locatelli Kournwsky
- El Boxeador: la verdadera historia de Hertzko Haft (Der Boxer: Die Überlebensgeschichte des Hertzko Haft), Reinhard Kleist
- Vuelo a casa y otras historias (Flying Home and Other Stories), Ralph Ellison
- Rendezvous with Rama, Arthur C. Clarke
- Treasure Island, Robert Louis Stevenson
- Agile Principles, Patterns, and Practices in C#, Robert C. Martin
- Atonement, Ian McEwan
- En una piel de león (In the Skin of a Lion), Michael Ondaatje
February
- El gigante enterrado, Kazuo Ishiguro
- The Time Machine, H.G. Wells
March
- JavaScript Patterns: Build Better Applications with Coding and Design Patterns, Stoyan Stefanov
- Slack: Getting Past Burnout, Busywork, and the Myth of Total Efficiency, Tom DeMarco
- El minotauro global (The Global Minotaur: America, the True Origins of the Financial Crisis and the Future of the World Economy 2nd edition), Yanis Varoufakis
- La sonrisa etrusca, José Luis Sampedro
April
- Howards End, E. M. Forster
- A Wizard of Earthsea, Ursula K. Le Guin
- Las tumbas de Atuan (The Tombs of Atuan), Ursula K. Le Guin
- En tierras bajas (Niederungen), Herta Müller
- How to Love, Thich Nhat Hanh
- La costa más lejana (The Farthest Shore), Ursula K. Le Guin
- Tehanu, Ursula K. Le Guin
- Obliquity: Why our goals are best achieved indirectly, John Kay
- Tales from Earthsea, Ursula K. Le Guin
- The Other Wind, Ursula K. Le Guin
- Metaphors We Live By, George Lakoff and Mark Johnson
May
- Are Your Lights On? How to Figure Out What the Problem Really Is, Gerald M. Weinberg, Donald C. Gause
- Bird by Bird: Some Instructions on Writing and Life, Anne Lamott
- Nonviolent Communication: A Language of Life, Marshall B. Rosenberg
- Mañana. Una revolución en marcha (Demain. Un nouveau monde en marche), Cyril Dion
- Thinking in Systems: A Primer, Donella H. Meadows, Diana Wright
June
- So Good They Can’t Ignore You, Cal Newport
- The Man Who Would Be King, Rudyard Kipling
- A Few Lessons From Sherlock Holmes, Peter Bevelin
- El dios de las pequeñas cosas (The God of Small Things), Arundhati Roy (2nd time)
- What Did You Say?: The Art of Giving and Receiving Feedback, C. N. Seashore, G. M. Weinberg, E. W. Seashore
July
- Pride and Prejudice, Jane Austen
- La Meta (The Goal), Eliyahu M. Goldratt
- Structured Design: Fundamentals of a Discipline of Computer Program and Systems Design, Edward Yourdon and Larry L. Constantine
- The Tartar Steppe (Il deserto dei Tartari), Dino Buzzati
- Getting It Done: How to Lead When You're Not in Charge, Roger Fisher, Alan Sharp
- Humble Inquiry: The Gentle Art of Asking Instead of Telling, Edgar H. Schein
- Occupy, Noam Chomsky
August
- Sinuhé, el egipcio (Sinuhe egyptiläinen), Mika Waltari (2nd time)
- La mejor oferta (La Migliore Offerta), Giuseppe Tornatore
- Programming Beyond Practices, Gregory T. Brown
- Clojure Polymorphism, Paul Stadig
- Why Don't We Learn from History?, B. H. Liddell Hart
- Usable Software Design, Alexandru Bolboaca
- Decline and Fall, Evelyn Waugh
- La Casa Infernal (Hell House), Richard Matheson
Monday, August 28, 2017
Interesting Talk: "Beyond PEP 8, Best practices for beautiful intelligible code"
Wednesday, August 23, 2017
Notes on OCP from Agile Principles, Practices and Patterns book
- OCP -> "Software entities (classes, modules, functions, etc) should be open for extension but closed for modification <- [Martin's definition. The origin of the principle comes from Bertrand Meyer that gave it a slightly different definition]"
- "When a single change to a program results in a cascade of changes to dependent modules, the design smells of fragility" <- [related with violating Beck's Local Consequences principle from Implementation Patterns] OCP advises us to refactor the system so that further changes of that kind will not cause more modifications. <- [related with Cockburn's & Larman's Protected Variations] If OCP is applied well, further changes of that kind are achieved by adding new code, not by changing old code that already works"
- "It's possible to create abstractions that are fixed and yet represent an unbounded group of possible behaviors"
- "[A module that uses such abstractions] can be closed for modification, since it depends on an abstraction that is fixed. Yet the behavior of the module can be extended by creating new derivatives of the abstraction"
- "Abstract classes are more closely associated to their clients than to the classes that implement them" <- [related with Separated Interface from Fowler's P of EAA book]
- "[Strategy and Template Method patterns] are the most common ways to satisfy OCP. They represent a clear separation of generic functionality from the detailed implementation of that functionality"
- Anticipation
- "[When a] program conforms to OCP. It is changed by adding code rather than by changing existing code"
- "In general no matter how "closed" a module is, there will always be some kind of change against which it is not closed"
- "Since closure can't be complete, it must be strategic. That is the designer must choose the kinds of changes against which to close the design, must guess at the kinds of changes that are most likely, and then construct abstractions to protect against those changes."
- "This is not easy. It amounts to making educated guesses about the likely kinds of changes that the application will suffer over time."
- "Also conforming to OCP is expensive. It takes development time and money to create the appropriate abstractions. These abstractions also increase the complexity of the software design"
- "We want to limit the application of OCP to changes that are likely"
- "How do we know which changes are likely? We do the appropriate research, we ask the appropriate questions, and we use or experience and common sense. And after all that, we wait until the changes happen!" <- [relates with Yagni, also talking about learning about your domain] "We don't want to load the design with lots of unnecessary abstractions. <- [related with Metz's The Wrong Abstraction] Rather we want to wait until we need the abstraction and then put them in"
- "Fool me once"
- "... we initially write our code expecting it not to change. When a change occurs, we implement the abstractions that protect us from future changes of that kind."
- "If we decide to take the first bullet, it is to our advantage to get the bullets flying early and frequently. We want to know what changes are likely before we are very far down the development path. The longer we wait to find out what kind of changes are likely, the more difficult it will be to create the appropriate abstractions."
- "Therefore, we need to stimulate changes"
- "We write test first" -> "testing is one kind of usage of the system. By writing tests first, we force the system to be testable. Therefore, changes in testability will not surprise us later. We will have built the abstractions that make the system testable. We are likely to find that many of these abstractions will protect us from other kinds of changes later <- [related with Feather's The Deep Synergy Between Testability and Good Design]."
- "We use short development cycles"
- "We develop features before infrastructure and frequently show those features to stake-holders"
- "We develop the most important features first"
- "We release the software early and often"
- "Closure is based on abstraction"
- "Using a data-driven approach to achieve closure"
- "If we must close the derivatives [...] from knowledge of one another, we can use a table-driven approach"
- "The only item that is not closed against [the rule that involves] the various derivatives is the table itself. An that table can be placed in its own module, separated from all the other modules, so that changes to it do not affect any of the other modules"
- "In many ways the OCP is at the heart of OOD."
- "Yet conformance to [OCP] is not achieved by using and OOP language. Nor is it a good idea to apply rampant abstraction to every part of the application. Rather it requires a dedication on the part of the developers to apply abstraction only to those parts of the program that exhibit frequent change."
- "Resisting premature abstraction is as important as abstraction itself <- [related with Metz's The Wrong Abstraction]"
Tuesday, August 22, 2017
In a small piece of code
In a previous post we talked about positional parameters and how they can suffer from Connascence of Position, (CoP). Then we saw how, in some cases, we might introduce named parameters to remove the CoP and transform it into Connascence of Name, (CoN), but always being careful to not hiding cases of Connascence of Meaning, (CoM). In this post we’ll focus on languages that don’t provide named parameters and see different techniquess to remove the CoP.
Let’s see an example of a method suffering of CoP:
In languages without named parameters (the example is written in Java), we can apply a classic[1] refactoring technique, Introduce Parameter Object, that can transform CoP into CoN. In this example, we introduced the ClusteringParameters object:
which eliminates the CoP transforming it into CoN:
In this particular case, all the parameters passed to the function were semantically related, since they all were parameters of the clustering algorithm, but in many other cases all the parameters aren’t related. So, as we saw in our previous post for named parameters, we have to be careful of not accidentally sweeping hidden CoM in the form of data clumps under the rug when we use the Introduce Parameter Object refactoring.
In any case, what it’s clear is that introducing a parameter object produces much less expressive code than introducing named parameters. So how to gain semantics while removing CoP in languages without named parameters?
One answer is using fluent interfaces[2] which is a technique that is much more common than you think. Let’s have a look at the following small piece of code:
This is just a simple test. However, just in this small piece of code, we can find two examples of removing CoP using fluent interfaces and another example that, while not removing CoP, completely removes its impact on expressiveness. Let’s look at them with more detail.
The first example is an application of the builder pattern using a fluent interface[3].
Applying the builder pattern provides a very specific[4] internal DSL that we can use to create a complex object avoiding CoP and also getting an expressiveness comparable or even superior to the one we’d get using named parameters.
In this case we composed two builders, one for the SafetyRange class:
and another for the Alarm class:
Composing builders you can manage to create very complex objects in a maintanable and very expressive way.
Let’s see now the second interesting example in our small piece of code:
This assertion using hamcrest is so simple that the JUnit alternative is much clearer:
but for more than one parameter the JUnit interface starts having problems:
Which one is the expected value and which one is the actual one? We never manage to remember…
Using hamcrest removes that expressiveness problem:
Thanks to the semantics introduced by hamcrest[6], it’s very clear that the first parameter is the actual value and the second parameter is the expected one. The internal DSL defined by hamcrest produces declarative code with high expressiveness. To be clear hamcrest is not removing the CoP, but since there are only two parameters, the degree of CoP is very low[7]. The real problem of the code using the JUnit assertion was its low expressiveness and using hamcrest fixes that.
For us it’s curious to see how, in trying to achieve expressiveness, some assertion libraries that use fluent interfaces have (probably not being aware of it) eliminate CoP as well. See this other example using Jasmine:
Finally, let’s have a look at the last example in our initial small piece of code which is also using a fluent interface:
This is Mockito’s way of defining a stub for a method call. It’s another example of fluent interface which produces highly expressive code and avoids CoP.
Summary.
We started seeing how, in languages that don’t allow named parameters, we can remove CoP by applying the Introduce Parameter Object refactoring and how the resulting code was much less expressive than the one using the Introducing Named Parameters refactoring. Then we saw how we can leverage fluent interfaces to remove CoP while writing highly expressive code, mentioned internal DSLs and showed you how this technique is more common that one can think at first by examining a small piece of code.
References.
Books.
- Refactoring: Improving the Design of Existing Code, Martin Fowler
- Growing Object-Oriented Software Guided by Tests, Nat Pryce and Steve Freeman.
- Refactoring Ruby, Jay Fields, Kent Beck, Martin Fowler, Shane Harvie
Posts.
- Refactoring Ruby: Bad Smells in Code, Jay Fields, Kent Beck, Martin Fowler, Shane Harvie
- Builders vs option maps, Kyle Kingsbury
- Refactoring tests using builder functions in Clojure/ClojureScript, Manuel Rivero
- Remove data structures noise from your tests with builders, Carlos Blé
- Two examples of Connascence of Position, Manuel Rivero, Fran reyes
- About Connascence, Manuel Rivero
Footnotes:
Friday, August 18, 2017
Interesting Talk: "re-frame your ClojureScript applications"
Thursday, August 17, 2017
Interesting Talk: "Testing Stateful and Concurrent Systems Using test.check"
Tuesday, August 15, 2017
Notes on SRP from Agile Principles, Practices and Patterns book
Lately I've been doing some study on object-oriented concepts doing an effort to get closer to the sources. These are the resulting notes on Single Responsibility Principle I've taken from the chapter devoted to it in Robert C. Martin's wonderful Agile Principles, Practices and Patterns in C# book:
- "This principle was described in the work of [Larry Constantine, Ed Yourdon,] Tom DeMarco and Meilir Page-Jones. They called it cohesion, which they defined as the functional relatedness of the elements of a module" <- [!!!]
- "... we modify that meaning a bit and relate cohesion to the forces that cause a module, or a class, to change"
- [SRP definition] -> "A class should have only one reason to change"
- "Why was important to separate [...] responsibilities [...]? The reason is that each responsibility is an axis of change" <- [related with Mateu Adsuara's complexity dimensions]
- "If a class has more than one responsibility the responsibilities become coupled" <- [related with Long Method, Large Class, etc.] <- [It also eliminates the possibility of using composition at every level (functions, classes, modules, etc.)] "Changes to one responsibility may impair or inhibit the class ability to meet the others. This kind of coupling leads to fragile designs" <- [For R. C. Martin, fragility is a design smell, a design is fragile when it's easy to break]
- [Defining what responsibility means]
- "In the context of the SRP, we define a responsibility to be a reason for change"
- "If you can think of more than one motive for changing a class, that class has more than one responsibility. This is sometimes difficult to see"
- "Should [...] responsibilities be separated? That depends on how the application is changing. If the application is not changing in ways that cause the [...] responsibilities to change at different times, there is no need to separate them." <- [applying Beck's Rate of Change principle from Implementation Patterns] "Indeed separating them would smell of needless complexity" <- [Needless Complexity is a design smell for R. C. Martin. It's equivalent to Speculative Generality from Refactoring book]
- "An axis of change is an axis of change only if the changes occur" <- [relate with Speculative Generality and Yagni] "It's not wise to apply SRP, or any other principle if there's no symptom" <- [I think this applies at class and module level, but it's still worth it to always try to apply SRP at method level, as a responsibility identification and learning process]
- "There are often reasons, having to do with the details of hardware and the OS [example with a Modem implementing two interfaces DateChannel and Connection], that force us to couple things that we'd rather not couple. However by separating their interfaces, we [...] decouple[..] the concepts as far as the rest of the application is concerned" <- [Great example of using ISP and DIP to hide complexity to the clients] "We may view [Modem] as a kludge, however, note that all dependencies flow away from it." <- [thanks to DIP] "Nobody needs to depend on this class [Modem]. Nobody except main needs to know it exists" <- [main is the entry point where the application is configured using dependency injection] "Thus we've put the ugly bit behind a fence. It's ugliness need not leak out and pollute the rest of the app"
- "SRP is one of the simplest of the principles but one of the most difficult to get right"
- "Conjoining responsibilities is something that we do naturally"
- "Finding and separating those responsibilities is much of what software design is really about. Indeed the rest of the principles we discuss come back to this issue in one way or another"
Other posts in this series: