H
H
Hint2016-09-21 17:58:36
PHP
Hint, 2016-09-21 17:58:36

How to break a large function into several smaller ones?

I read the article "The Art of Writing Simple and Short Functions" https://habrahabr.ru/post/310590/
This topic is constantly procrastinating, and the same question constantly arises in my head.
Obviously, you need to break complex functions into parts. But I often have the problem that internal functions will almost certainly not be reused anywhere. Quite often, a specific function is obtained with a specific set of parameters and a specific result. And what would you call it then? Use parent function name as prefix? Moreover, if we move the code to a separate function, then the question of checking incoming parameters appears, which was probably performed in the parent function. In the parent function, we knew for sure that the parameters were correct, but here it turns out that we either do not check anything, which is bad for the independence of the newly-made function, or once again check what we have already checked before, which negatively affects performance. I mainly program in php and there I have a real problem with this, since there are no local functions in the language. Their presence could improve the situation due to the fact that internal functions have a local scope, which means they should not have unique understandable names, plus they cannot be called from outside, which means there is no point in checking the parameters several times.
What am I doing wrong? Are there times when it's actually better not to break? Or is the presence of such cases unambiguously indicative of bad architecture?

Answer the question

In order to leave comments, you need to log in

4 answer(s)
A
Adamos, 2016-09-21
@Adamos

Architecture is not measured by the length of features, but by their purpose. A function that performs exactly one task will usually not be long.
Approach the question from the side of testing. Are you satisfied with testing this function as a single black box? Or does it have specific parts that perform full-fledged subtasks, for which it would be nice to have a separate test in case there are changes in the function? If not, and you just have a uniform sheet, there is no need to break it. If there is, why not?
Well, if you are confused by the accumulation of functions that no one else needs, remember that PHP has OOP and all this can be collected in a class, and functions that are not used anywhere else are made private.

P
Philipp, 2016-09-21
@zoonman

Discover namespace .
Never prefix functions, otherwise it will be like this shit `syn_whitelabel_form_whitelabel_partner_node_form_alter()` (this is real code).
Master OOP eventually. Collect your functions within one functional domain into one class.
If the function is internal, declare it private and call it via `self::`.
Regarding parameter validation - PHP allows you to declare parameter types like array or classes. In many cases, these things are sufficient.
You need to break large functions into small ones when the action is repeated at least once or can be used by another part of the project.
A typical example is validators, they can be used everywhere.

A
abcd0x00, 2016-09-22
@abcd0x00

You have the wrong approach. You first make some big function, and then you want to break it. So this big function of yours is complete bullshit. That's the problem. Because you already did it wrong.
You should not have a function that first appears, and then you think that it can be made. It should be the other way around. First, a task should appear that needs to be done, and now a function that performs it should appear under this task. And there can be many such functions, and all of them can be different.
For example, you want to print the string "hello" in C.

The code
#include <stdio.h>

int main(void)
{
    printf("hello\n");
    puts("hello");
    fputs("hello\n", stdout);
    fprintf(stdout, "hello\n");
    fwrite("hello\n", 1, 6, stdout);
    return 0;
}

Conclusion
[[email protected] c]$ .ansi t.c -o t
[[email protected] c]$ ./t
hello
hello
hello
hello
hello
[[email protected] c]$

These are ready-made functions, they were already written once. And they solve your problem. And they were not originally intended for this at all. Many of them are not used for such tasks, but they can be used. They just do something with what they serve. And what they serve and whether they were originally intended for this - it does not matter.
And here is the same task, but the listed functions are not allowed to be used. What to do?
You can write a function instead.
The code
#include <stdio.h>

void f1(void)
{
    putchar('h');
    putchar('e');
    putchar('l');
    putchar('l');
    putchar('o');
    putchar('\n');
}

void f2(char c)
{
    putchar(c);
    putchar('e');
    putchar('l');
    putchar('l');
    putchar('o');
    putchar('\n');
}

void f3(char c)
{
    int i;
    
    putchar('h');
    putchar('e');
    for (i = 0; i < 2; i++)
        putchar(c);
    putchar('o');
    putchar('\n');
}

int main(void)
{
    f1();
    f2('h');
    f3('l');
    return 0;
}

Conclusion
[[email protected] c]$ .ansi t.c -o t
[[email protected] c]$ ./t
hello
hello
hello
[[email protected] c]$

Now this is closer to the point. The problem is posed and solved with the help of several different functions. The fact that these functions can't be used anywhere else is irrelevant, that's another matter. The main thing is that the task is solved correctly and accurately, as it was set.
Now let's think about how it happened that the printf () function, written decades ago, solved our problem and thousands of other problems, and their functions f1 (), f2 () and f3 () can only solve our problem, but besides it, they cannot solve a dozen other tasks?
What is the difference between printf() and f1()? The fact that in printf() the string "hello" is passed as a parameter (that is, the output text is parameterized), while in f1() there is no string at all, it is formed from characters that are not even parameterized. And what about f2(), because there is a parameter there? And in f2(), the output text is not parameterized enough, just like in f3().
What is the secret of parameterization? The fact that the data should be parameterized as much as possible and have as few dependencies as possible. To do this, they strive to make them as simple as possible, because you will never guess which structures will operate in decades, and which ones will be thrown into the trash and forgotten like a bad dream.
This is how a function is written: you must set a task and solve it by calling some function. And if the function does not exist, then you still have to call it, but then add its contents. And when you finish writing a function, inside it you do the same thing - you set a task and solve it by calling some function.
In the example above, you solve the problem of printing the string "hello" with the f1() function, and inside the f1() function, you solve the problem of printing a character on the screen with the putchar() function. (Fortunately, putchar() is already ready and well parameterized. But if it’s not ready, then you also call it, and then add its interior, in which everything is repeated - the task and the call.)

T
trevoga_su, 2016-09-22
@trevoga_su

OOP

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question