I think no one will argue that a good code is a code that not only executes, but also describes its task as much as possible (this, of course, refers primarily to business logic). Moreover, it describes it not with the details of the algorithm, but with its signature (name, parameters, and return type), the signature of the methods being called, and the variables it uses. In this case, the body of the method can be read from top to bottom without holding any additional context in memory.
Example
Let's consider the following class (the subject is somewhat unusual, but I hope that this will make the process of reading someone else's code less boring):
public class Invasion { private SearchCriterion _searchCriterion = (new GeniousCriterion()).or(new SexyCriterion()); private ExperimentProcedure _experimentProcedure = (new MockProcedure()).then(new WatchProcedure()); private _experience = new Experience(); private HumanBeing[] _humans; private ArrayList<HumanBeing> _chosenOnes; public void investigate() { updateChosenOnesList(); experiment(); } private void updateChosenOnesList() { _chosenOnes.clear(); for (HumanBeing human : _humans) if (_searchCriterion.satisfied(human)) _chosenOnes.add(human); } private void experiment() { for (HumanBeing human : _chosenOnes) _experience.push(_experimentProcedure.do(human)); } }
Wherein
It is required to find out what the investigate method does or verify the correctness of its logic. In this case, I would not like to understand the code of all the methods that it calls.
The updateChosenOnesList method. In this case, by the name of the method, you can determine that its implementation should update the _chosenOnes field. At the same time, after reviewing the list of fields of the object, we can assume that the search for new ones will be among the _humans, and the search can use the _searchCriterion criteria. However, it is not very convenient to check the list of object fields and trace the connection between their names and method names. The situation is similar with the experiment method.
')
And another example
Here is another implementation of this class (see comments):
public class Invasion {
Actually, this was the application of a functional programming style. Let's see what the pros and cons of this option compared with the first.
pros
They are not, but there are a lot of minuses. Joke.
First, it is now easier to read the method of investigate and understand what it does, and whether it does what it should, and if it does, whether it is correct. In this case, you can not look anywhere except for the body of the method itself, including the list of fields.
Secondly, now private methods do not depend on the state of the object. It turns out that the result of their execution is determined solely by the transmitted parameters (i.e. when you call, you do not need to monitor the state of all fields of the Invasion object — you can see which fields are transmitted and which are modified). At the same time, those parameters that are used as arguments were formed / initialized in the body of the investigate method — i.e. see the entire algorithm and all changes that have occurred with the state of Invasion.
Minuses
Performance - alas. At the same time, there is no point in sadness, unless the investigate method is called very often.
It is necessary to pass additional parameters to the methods - this is quite critical if there are many of them - 4 or more. On the other hand, if there are a lot of parameters on which the method depends, then perhaps it is a reason to think about changing the architecture (usually adding a new class, such as SexyCriterion, which may contain the necessary parameters).
For example
Generally speaking, in this case there was no need for closed methods. It was enough to add the objects of the search criteria and procedures to the ability to fully process the collection of objects. However, there were maximally distributed responsibilities between different types of objects, primarily in order to reduce the amount of code for example. It often happens that either there is no time to build such a model, or there is no need (for example, when there is a suspicion that the requirements may change and you need to apply the simplest solution). In such cases, the functional style can somewhat simplify the reading and support of the code, while practically without increasing the time spent on development.
Epilogue
You can write code that does not contain methods with a large number of lines (for example, more than 10) and does not require private methods (such methods can always be placed in a separate object of behavior). However, the process of building such a code is not simple.
Therefore, it is possible to break the complex code of the public method into several private function-methods, depending solely on their parameters, and not modifying the state of the object. In such a case, only public methods (not private) should address the state of the object directly - i.e. methods that are part of its interface. This allows you to reduce a complex algorithm to a set of methods, each of which can be easily read, provided that the variables, methods, and their parameters have received suitable names.
And, just in case, if suddenly there are questions, where is the PLO, and where is the functional programming. OOP - based on this paradigm, responsibilities are divided between the objects Invasion, Criterion, Procedure, Experience. Functional programming - with its help the internal logic of Invasion is implemented, private methods in this case are functions (they depend only on the input parameters and do not modify the state of the Invasion object).
Thanks for attention! Please write in the comments your opinions, comments and criticism.
Posted on 09/10/2012, with some commentsPlease note that it is not only about editing the state of an object with internal (auxiliary) class methods, but also about the fact that these methods do not have to read the state of an object themselves (they receive all their parameters as arguments).
Naturally, this principle does not pretend to be absolute, there are cases when closed methods are better given the opportunity to refer to the state of a class. First of all, this is the case when there may be duplication of code in the form of transferring the same set of function arguments in different places (or editing the same set of fields based on the results of the function). For example, if the updateChosenOnesList method should be called in several places and each time it needs to pass the same internal fields of an object, then it is definitely better implemented in the first example.
Those. The purpose of the article is not to specify the coding method, but to pay attention to the advantages that the use of the method-functions gives.
The topic of the possibility of editing functions of its arguments was NOT considered here.