Translation of an article by Cindy Sridharan.In this article, the author is going to:
- Shed light on some of the perceived benefits of small features.
- Explain why some of the benefits are not at all as rosy as advertised.
- Explain why small functions are sometimes counterproductive.
- Explain when small features are really useful.
Among the general programming tips, the elegance and efficiency of small functions is invariably exalted. In the book “Clean Code” - perceived by many as programmers' bibles - there is a chapter devoted only to functions, and it begins with an example of a truly terrible, and also a long function. And further in the book, the
length of the function is branded as the most terrible sin:
')
The function is not only long, it contains duplicate code, a bunch of incomprehensible string values, and many strange and non-obvious data types and APIs. Did you understand it after three minutes of study? Probably not. There is too much happening in it and at too many levels of abstraction. Here, strange string values ​​and strange function calls are intermixed with double nested if-expressions, flag-driven.
The same chapter briefly discusses which qualities should make the code “easy to read and understand” and “allow the casual reader to intuitively understand what kind of program they belong to,” and then declares that it is necessary to make the functions
smaller .
The first rule of functions is that they should be small. The second rule says that functions
should be even smaller .
The idea that functions should be small is considered practically sacred and not subject to revision. It often pops up during code revisions, discussions on Twitter, at conferences, in books and podcasts, articles on best refactoring techniques, and so on. And recently this idea popped up in a ribbon in the form of such a tweet:
In my Ruby code, half the methods are just one or two lines long. 93% shorter than 10. Https://t.co/Qs8BoapjoP https://t.co/ymNj7al57j
- @martinfowler
The author cites a link to his article on the length of functions, in which he writes:
If, when looking at the code snippet, you made an effort to understand what is being done here, then you need to extract it into a function and give it a name in honor of this “what”.
Having accepted this principle for myself, I developed the habit of writing very small functions — usually only a few lines long [ 2 ]. I’m worried about any function longer than five lines, and I often write single-line functions [ 3 ].
The virtues of small functions are promoted so often that in just a few days this topic has surfaced in the form of such a tweet:
I like part of the board @ dc0d_
- @davecheney
Some are so preoccupied with small functions that they passionately defend the idea of ​​abstracting each and every part of nominally complex logic into a separate function.
We had to work with code bases written by people who had absorbed this idea to such an unholy degree that the end result was hellish and completely contrary to all the good intentions with which the road was paved. In this article, we want to explain why some of the widely publicized benefits of small functions do not always correspond to our hopes, and sometimes are completely counterproductive.
Estimated Benefits of Small Functions
In confirmation of the merits of small functions, a number of statements usually roll out.
Do one thing
A small function is more likely to do one thing. Note: Small! = One line.
- @davecheney
The idea is simple: a function should do only one thing and do it well. At first glance, it sounds very sensible, even in some harmony with the Unix philosophy.
The ambiguity arises when it is necessary to define “one thing”. It can be anything from a simple return expression to a conditional expression, part of a mathematical calculation, or a network call. As is often the case, “one thing” means one level of abstraction of some logic (usually business logic).
For example, in a web application, “something one” could be a CRUD operation like “create a user”. When creating a user, at least you need to make an entry in the database (and handle all related errors). You may also have to send a person a welcome letter. Moreover, someone else will want to initiate a special message in a message broker like Kafka to feed the event to other systems.
It turns out that “one level of abstraction” is not at all one. Some programmers, who unconditionally accepted the idea that a function must do “one thing at a time,” hardly resist the urge to recursively apply this principle to each of its functions or methods.
So many of them cannot stop until they make the function completely DRY and modular - and this never works perfectly.
- @copyconstruct
That is, instead of a reasonable and unshakable abstraction, which can be understood (and tested) as one element, we create even smaller elements from which all the components of “one thing” are formed, until this alone becomes completely modular and fully DRY.
Erroneous DRY
DRY is one of the most dangerous design principlα (34) floatiα (25) aα (28) und α (29) t α (13) α (27) e toα (22) y
- @xaprb
DRY is not necessarily synonymous with making functions as small as possible. But I have watched many times how the second leads to the first. I believe that DRY is a good guideline, but very often pragmatism and reason are placed on the altar of dogmatic adherence to this principle, especially by programmers with Rails-beliefs.
Raymond Hettinger, one of the main Python developers, has a fantastic
Beyond PEP8 performance
: Best practices for beautiful, intelligible code . It needs to be viewed not only by Python-programmers, but in general by everyone who is interested in programming or earns them a living. It is very astutely exposed the shortcomings of the dogmatic following PEP8 - a Python style guide implemented in many linters. And the value of the speech is not in the fact that it is dedicated to PEP8, but in the valuable conclusions that can be drawn, many of which do not depend on a specific language.
Look at least
one minute from a speech during which a frighteningly exact analogy is drawn with the insidious call of DRY. Programmers who insist on the widest use of DRY risk not seeing the woods behind the trees.
The main disadvantage of DRY is coercion to abstractions, nested and premature. Since it is impossible to abstract
perfectly , we have to do it
well , to the best of our ability. At the same time, it is impossible to give a precise definition of how “good” should be, it depends on many factors.
On this graphic, the term “abstraction” can be replaced by “function”. For example, figuring out how best to design a level of abstraction A, you can think of:

- The nature of the assumptions underlying abstraction A, what is the probability (and duration) that they will be logical.
- The tendency of the abstraction levels underlying the abstraction A (X and Y), as well as those based on it (Z), to remain consistent, flexible and correct in implementation and design.
- What are the requirements and expectations for any future abstractions above (M), or below the abstraction A (N).
Abstraction A developed by us will inevitably be constantly revised, up to a partial or complete rejection. Therefore, the fundamental property of our abstraction, which will inevitably be modified, must be
flexibility .
And if we start using the DRY principle at any time, then we will deprive ourselves in the future of this flexibility, the ability to adapt to any possible changes. What we really need to do is to give ourselves a little bit of freedom to make the inevitable changes that will be required sooner or later, and not to start building the perfect solution right away.
The best abstraction is one that is optimized
enough , not
perfect . This is a feature, not a bug. It is necessary to understand this essential feature of abstractions in order to design them successfully.
Alex Martelli, who coined the phrase “duck typing” and the famous Pythonista, has a performance called The Tower Of Abstraction; read these slides from the
presentation :


The well-known rubistka Sandy Metz has a performance by
All The Little Things , in which she postulated that “duplication is much cheaper than wrong abstraction,” which means you need “to prefer duplication of wrong abstraction.”
I believe that abstractions in general can not be "correct" or "wrong", because the boundary between these concepts is fuzzy and forever changes. Our carefully fostered "ideal" abstraction from the status of "wrong" separates only one business requirement or error report.
It seems to me that abstraction should be perceived as a certain range, as in the graph above. One end of the range is optimization in terms of
accuracy , while absolutely all aspects of our code need to be optimized to a state of
absolute accuracy . But the best is the enemy of the good: striving for the ideal will not help design
good abstractions, since it requires perfect fit. Another part of our spectrum is optimization in terms of inaccuracy and lack of boundaries. And despite the maximum flexibility, this approach has its drawbacks.
Sometimes for a specific context there is only ONE perfect solution. But the context can change at any time, as well as the ideal solution https://t.co/ML7paTXtdu
- @copyconstruct
As in most cases, the “ideal” is somewhere in the middle. There is no universal perfect solution. “Ideality” depends on many factors — programmer and interpersonal — and a good developer should be able to recognize where the “ideal” point of the spectrum is for each context, and constantly overestimate this ideal.
Names
After deciding
what and
how we abstract, it is important to give an abstraction name.
And
it is difficult to call.
In programming, it is considered to be a common truth that giving long, descriptive names is good, with some advocating the replacement of comments in the code with functions whose names are comments. The point is that the more descriptive the name, the better the encapsulation.
and finally naming. Fowler with friends stand for descriptive names,
So WHAT WE HAVE DONE THE NAMES HOW THAT ARE VERY HARD TO READ
- @copyconstruct
Perhaps it rolls in the Java world, where wordiness is in the order of things. But the code with such names is difficult to read. When reading the code, such snapshots from a pile of words introduce me to a light stupor, while I try to isolate all these syllables in the function name, embed it in a mental model that had formed in my head by that moment, and then decide whether to go on to the definition functions and study its implementation.
But with “small functions” there is another problem: the pursuit of them leads to the fact that there are
even more small functions, and everyone has verbose names for the sake of refusing comments and self-documenting of the code.
And I am very tired of understanding the verbose names of functions (and variables), embedding them in a mental model, deciding which ones to study in more detail and which ones to skip, and finally adding all the pieces of the mosaic into a single picture.
The smaller the function, the more of them and their names. I'd rather read the code, not the function names.
- @copyconstruct
, , , , , . ,
if-else
,
if
elseif
, .
, -
aVeryVeryLongFuncNameAndArgList
. . , , , , .
, —
.
createUser
,
renderPageWithSetupsAndTeardowns
(
Clean Code), , . , , .
, .
Clean Code (The Stepdown Rule).
, . , , . .
, , . , , .
, , , ( ) . , , .

, . , «- » ( ).
Clean Code ,
, .

.

,
The Wrong Abstraction. :
. . , , . , , , , , (« »).
, , , , ( ). , , -,
.
- , . . , , (graceful death). , , , .
+1. , . /,
 — @copyconstruct
«» , , . , ,
Git-, , . , , , ( ) .
, ,
Clean Code.
, , . , Go (
) .
- . //, , //.
.
, - .
, , Ruby,
 — @copyconstruct
Ruby 5-10 , - - . , .
,
, .
, : , , . , .
« »: 1. 2. 3.
 — @sdboyer
, — 1) 2) (rails, django ) 3)
 — @copyconstruct
. -, «». - . ,
, .
, DRY. , , . , , , «» «».
«» , / , — - . ,
/, , , «- » , , .
, :
, . . DRY. .
, , , .
( , ), .
 — @copyconstruct
, , , open source-.
, , .
-
, , , dbs macbook.
 — @tyler_treat
, , , , .
 — @tyler_treat
, , . -, .
/ , / .
 — @copyconstruct
. . , — - . , , . , , , . , .
, -. ( ) , . , .
, . API , , HTTP-. . 1-2 , HTTP- . Kafka .
, (property based testing) , . Haskell- QuickCheck, , Scala (
ScalaCheck) Python (
Hypothesis). - .
, , . , JSON/msgpack, .
DRY — ( ).
.
, — . 2016 Pycon
onelineizer, ,
Python ( ) . , production- .
:
Go: , .
 — @rakyll
, Go. , , , , , , .
, , « ». . , . , , .