99 Bottles of OOP
99 Bottles of OOP
Chapter 1 - Rediscovering Simplicity
Design is about picking the right abstractions. Pick the right ones and everyone will love both it and you. If you choose the wrong ones, code will be convoluted, confusing and costly.
Early abstractions are not quite right and therefore they create a catch 22. Don’t reach for abstractions but instead resist them until they absolutely insist upon being created.
Value/cost questions -
How difficult was it to write?
How hard is it to understand?
How expensive will it be to change?
Incomprehensibly Concise
Speculatively General
Concretely Abstract
Shameless Green
Evaluating code based on opinion
What is clean code?
What is Clean code? A collection of quotes - “full of crisp abstractions”, “clean code is written by someone who cares”, “highest value for the lowest cost”,
Evaluating code based on Facts
Metrics are crowd-sourced opinions about the quality of the code.
Three different metrics - source lines of codex cyclomatic complexity and ABC
ABC - Assignments, branches (of control - function calls) and conditions
There’s something beyond complexity, a higher level of simplicity.
Chapter 2 - Test Driving Shameless Green
“Quick green excuses all sins” - Kent Beck.
Consider the problem, sketch out an overall plan but don’t overthink it.
“As tests get more specific, code gets more generic”
Use metrics, but don’t rely on them completely.
Transformation Priority Premise
Simple operations that change the behaviour of the code in priority order.
When a problem can be solved with any of several transformations, the transformation with the highest priority is simplest and therefore best.
‘Pluralize’ abstraction is the wrong concept for verse 2, even though it leads us to that abstraction.
DRY is important but if applied too early (overzealous programmers) it can end up in the incorrect abstractions.
Ask yourself these questions when making any change -
-
Does the change I’m contemplating make the code harder to understand?
-
Incorrect abstractions make the code harder to understand. Insufficient understanding of the problem.
-
What is the future cost of doing nothing now?
-
Some changes cost the same whether done now or later, waiting saves you money
-
When will the future arrive, i.e. how soon will I get more information?
-
“Better to tolerate duplication than to anticipate the wrong abstraction“
Three of Kent Beck’s Green Bar Patterns are -
-
Fake it till you make it
-
Obvious implementation
-
Triangulate - conservatively drive abstraction with tests. Write several tests at once, then make them all pass with one bit of code
API Design - song API vs verses(99,0) API
Intention vs Implementation
The distinction between intention and implementation allows you to understand a computation first in essence and later, if necessary, in detail.
Tests are not the place for abstractions, but concretions
Chapter 3 - Unearthing Concepts
Refactor now or later? Weigh up opportunity cost Vs benefits.
Refactoring Systematically
Refactoring is the process of changing a software system in such a way that it does not alter the external behaviour of the code yet improves its internal structure.
If tests are bad, improve them first and then start refactoring.
Flocking Rules
-
Select the things that are most alike
-
Find the smallest difference between them
-
Make the simplest change that will remove that difference
Always make the smallest changes, if you accidentally make a big one and things break, undo and make the smallest change. This gives you a very precise point of failure when things break.
Flocking Rules allow code abstractions to appear by grouping similar things together etc.
Why “flocking”?
Watch the Science of Sync TED talk
Birds flock, fish school and insects swarm. A flock’s behaviour can appear so synchronized and complex it gives the illusion of being centrally coordinated.
The flocking behaviour is a result of a continuous series of small decisions made by each participating individual.
-
Alignment - steer towards the average heading of neighbours
-
Separation - don’t get too close to neighbours
-
Cohesion - steer towards the average position of the flock
Complec behaviour emerges from the repeated application of simple rules.
Converging on Abstractions
DRYing out sameness has some value, but DRYing out difference has more.
If two concrete examples represent the same abstraction and they contain a difference, that difference must represent a smaller abstraction within the larger one. If you can name the difference, you’ve identified that smaller abstraction.
Horizontal Vs vertical changes
Naming Concepts
One way to identify Abstractions is to imagine the concrete examples as rows and columns in the spreadsheet. Naming something should always be one level of abstraction higher than the thing itself.
Use a table like below to come up with the name of the concept/abstraction.
Imagine other concrete examples and the abstraction appears! In the above example, imagine wine instead of beer. “Container”.
Making a slew of simulatenous changes is not refactoring, it’s rehaktoring.
Chapter 4 - Practicing Horizontal Refactoring
Replace difference with sameness.
Naming strategies for a new concept/abstraction -
-
Ponder name for 5-10 mins (timeboxed) with thesaurus in hand
-
Pick any name and unblock yourself quickly, hoping that the name will become obvious later (you’ll never know less than you know right now)
-
Pick a “best effort” name and improve it later as you understand the domain better
-
Ask someone for help, the “name guru” in the team
Deriving names from responsibilities
Best to stay horizontal and concentrate on the current goal instead of thinking too far ahead. When you create an abstraction, first describe it’s responsibility as you understand it at this moment. As your understanding improves, you can improve the name later.
Choosing Meaningful Defaults
Sometimes you’ll want to use a more meaningful default other than FIXME, when you want to execute the TRUE statement of an if condition.
This will still allow you to change one line at a time but you have to be more careful about removing the default value later on.
Obeying the Liskov Substitution Principle
The idea of reducing the number of dependencies imposed upon message senders by requiring receivers return trustworthy objects is a generalisation of the Liskov Substitution Principle.
Liskov prohibits you from doing anything that would force the sender of a message to test the returned result in order to know how to behave.
Discovering Deeper Abstractions
The ‘shape’ of a method should give you a clue if you’ve got the abstraction wrong.
When you’re confused, don’t try to solve the entire problem straightaway.
The power of iterative application of the Flocking Rules.
Final solution Vs Shameless Green
The final solution has a worse score than shameless green but it has clean abstractions and much easier to understand the underlying concepts.
You don’t have to understand the entire problem in order to find and express the correct abstractions - you merely apply these rules, repeatedly, and abstractions will naturally appear.
Chapter 5 - Separating Responsibilities
Identifying Patterns in Code
-
Do any methods have the same shape?
-
Do any methods take an argument of the same name? This is usually a code smell!
-
Do arguments of the same name always mean the same thing?
-
Do the tests in conditionals have anything in common?
-
How many branches do the conditionals have?
-
Do the methods contain any code other than the conditional?
-
Does each method depend more on the argument that got passed, or on the class as a whole?
Do any methods have the same shape?
You can identify same-shaped methods by doing the Squint Test.
Testing for equality is better than testing for less than or greater than. It increases precision and hence enables future refactorings.
Insisting upon messages
As an OO practitioner, if you see a conditional, the hairs on your neck should stand up. You should feel entitled to send messages to objects.
There’s a big difference between a conditional that selects a correct object and one that supplies behaviour. The forner s acceptable but the latter suggests there are missing objects in your domain.
Extracting Classes
Primitive obsession - when primitive data types (string, int etc.)) are used to model concepts in your domain.
Experienced OO programmers deftly create virtual worlds in which ideas are as real as physical things.
Name things at one higher level of abstraction rule applies more to methods than to classes. Methods should be named after what they mean, classes should be named after what they are.
Extract Class refactoring - Martin Fowler
Appreciating Immutability
A variable us that which varies, or in maths, a quantity which admits an infinite number of values in the same expression.
Easy to test, no thread safety issues with immutable objects.
The costs of caching and mutation are interrelated. If the thing you cache doesn’t mutate, your local copy is good forever.
Cacher - In French, means to conceal or hide
The first solution to any problem should avoid caching, use immutable objects and treat object creation as free.
Chapter 6 - Replacing Conditionals with Objects
TO READ