levels of abstraction Robert C. Martin in his book "Pure code" says that properly composed functions should be:
- small
- perform a single operation
- maintain a level of abstraction
While the first two points easy to imagine and implement, it noticed that the last point is not completely understood among some developers.
To illustrate where the committed is often a mistake let us use a simple and well known to every living activities:
recipe for scrambled eggs
- Dissolve butter in small skillet
- melted butter Put the ham cut into small squares and finely chopped chives
- broken eggshells with a sharp knife and content pour into the pan
- Add a little salt and pepper and stir until the eggs shear
recipe is rather intuitive and nobody should have any problem with his understanding. At this level of abstraction sufficient to use several components in a simple way and we already have our food ready.
But "underneath" to place the complex and (because of our culinary domain name into the model), insignificant phenomenon. As this provision would look like if it were part of a program created by nierozgarniętego programmer?
add (butter)
while (maslo.nieJestStopione) {
for (atom in atomyWProbceMasla) {
atom.dostarczEnergii
}}
add (sliced \u200b\u200bham)
while (szczypiorek.jestCaly) {
interacts with a knife in the crystal lattice chives
}
add (chives)
noż.dodajEnerigiiPotencjalnej
noz.zamieńEnergięPotencjalnąNaKinetyczną
noż.uderzW (egg)
add (zawartośćJajka)
add (salt)
for (ziarnkoPieprzu in szczyptaPipeprzu) {
add (ziarnkoPieprzu)
}
and stir until the eggs shear
(correctness of the physical may be inaccurate but this is not the merits of the example)
That rule changed a lot harder to understand and to make matters worse culinary domain was mixed with domain physical in which the potential recipient of the provision has to face a much higher plane problem.
To maintain a level of abstraction back to the roots:
patelnia.dodaj (butter)
patelnia.podgrzejDoRostopieniaMasla ()
patelnia.dodaj (Cut soft (ham))
patelnia.dodaj (Cut soft (chives))
pan . add (break (egg))
patelnia.dodaj (salt)
patelnia.dodaj (pepper)
mieszajDoMomentuScieciaSieJajek (frying pan)
Corrected source provision is clearer and does not require knowledge of the issues beyond the domain of culinary. We also see an interesting visual effect, which can be used as a kind of test or not we go beyond the area of \u200b\u200babstraction: namely, the Revised Version has no indentation.
As the phenomenon could have been presented as an example closer to IT?
function (object) {
operacjaDomenowa ();
guts = obiekt.wyciągnijBebechy
...
several nested loops, and try and catch
...
Operation Domain ()
znowuGrzebanieWBEbechach ()}
concrete example: we service request from a browser, which can contain pictures and text attachments. Any type of attachment we have to save to a separate directory.
przetworzRequest (request) {
zapiszPlikiTekstowe (request)
zapiszObrazki (request)}
And anyway, you can:
przetworzRequest (request) {
zapiszPlikiTekstowe (request)
stream = OtworzStrumien
for (bit in the picture) {
strumien.pisz (bit)
strumien.zamknij
}}
I think it's clear which version will be clearer, more pleasant, convenient and easier to maintain a person who sees this piece for the first time in my life.