http://vunvulearadu.blogspot.ro/2014/08/clean-code-naming.html
In the last blog post we discover the universe of Clean Code written by Robert C. Martin. We had the opportunity to go deeper on the naming topic and see how easily small things like meaningful names or naming that revel intention can improve the quality and readability of the code itself.
Today we will talk dive deeper in Clean Code and we will talk about ‘Functions’. This basic and simple mechanism used to write programs can impact not only how easily a program can be maintain and extended but also the mental health of developers. Don’t forget that long methods will make your eyes bleed.
Imagine a book where all the paragraphs are mixed, the font size is different for each of it and a part of them has 20 pages. How easily you can read a book like that. Code should be written in a way that gives the opportunity to people to read it like a book, from to bottom, where each different logic is grouped separately.
My PM from that period accepted this estimation and gave me green light to work on it. But in the end, I needed 4X more time to finish the task because the methods themselves were too long and I couldn’t do anything there without having nightmares during the nights.
So, what we can do to improve the quality of developers and our software from functions/methods perspective.
The natural question that pops in our mind is “How short?”.
Unfortunately we cannot have a magic number like 5 or 20, because is pretty hard to generalized it. The length of a method depends on multiple factors like the code conventions. For example how often you hit enter to add a new line (for every ‘{‘ or for every logic statement and so on).
In general if you end up with a method longer than 10-15 lines of code you should take a look over it and see why is so long. Because of code conventions or it is because there is too much logic there.
Additionally to this you will improve the readability and documentation of your own code. For developers will be very easy to understand what the code does and what the check behind that is IF or WHERE supposed to do.
This is why a function should do ONLY one things. If you need to do more than one thing, than you should split it into separately functions.
Even if the statement is so simple, it is pretty hard to do this. If you discover in a function different part of code that is grouped or you can extract a part of it into a separate function with a meaningful name than the functions is doing more than one thing.
One level of abstraction per Function
This can be a mechanism that can tell us that the function is doing to many things. For example a function that process an entity and also internally start to split and transfer one of the entity fields has more than one level of abstraction.
It is pretty clear that you should extract the string processing into another function. In this way each function will have only one level of abstraction.
We should replace the switch statement with polymorphism. This is the perfect solution, but there are cases when such a solution would add to much extra complexity. When you need to use switch statement you should hide them as deep as possible, in Clean Code the recommendation is behind a abstract factory.
A name like ‘TriggerDoorLock’ it gives us all the information that is needed to know what that function is doing.
Finding a good name is pretty hard and can consume a lot of energy. Addition to good names you should be consistent and try to use the same naming pattern when there are similarities.
When you end up with more than 3 or 4 arguments something can be wrong. You should take a look over them and see if you cannot more the function in another location or to add another abstraction level.
The OUT option to arguments is not all the time recommended and it may be a smell that something is wrong there. For example the TryXXX methods usually check if a conversion can be done. If it can be done with success, ‘TRUE’ is retuned and the out parameter will contain the conversion result. This could be a smell that the method is doing too many things – converting and checking.
Because of this side effects we can end up with temporary coupling. For example when function ‘GoLeft’ can be called only if ‘StartEngine’ was called. You should think about a way to expose only the methods that are available at a specific time, without creating temporarily coupling. For example the ‘StartEngine’ could return an object that has only the commands like ‘GoLeft’, ‘GoRight’ and so on.
For this cases throwing an exception is better and will simplify the work of clients. Additional to this, the error handing will be 100% separately from your logic.
In the last blog post we discover the universe of Clean Code written by Robert C. Martin. We had the opportunity to go deeper on the naming topic and see how easily small things like meaningful names or naming that revel intention can improve the quality and readability of the code itself.
Today we will talk dive deeper in Clean Code and we will talk about ‘Functions’. This basic and simple mechanism used to write programs can impact not only how easily a program can be maintain and extended but also the mental health of developers. Don’t forget that long methods will make your eyes bleed.
Imagine a book where all the paragraphs are mixed, the font size is different for each of it and a part of them has 20 pages. How easily you can read a book like that. Code should be written in a way that gives the opportunity to people to read it like a book, from to bottom, where each different logic is grouped separately.
Happy story
I remember one time when I had to extend an existing code written by somebody else. When I open the solution I found only one class, with 2 or 3 methods that had in total around 4.000 lines of code. My estimations for that task were:- 4 days on refactoring
- 1 days to add the new functionality
My PM from that period accepted this estimation and gave me green light to work on it. But in the end, I needed 4X more time to finish the task because the methods themselves were too long and I couldn’t do anything there without having nightmares during the nights.
So, what we can do to improve the quality of developers and our software from functions/methods perspective.
Small
This is the first and the most important rule related to functions. You should keep them as short as possible. The explanation is pretty simple: a shorter function will do less (only one simple thing). Additionally to this, it will be more easily to understand and manage it.The natural question that pops in our mind is “How short?”.
- 100 lines?
- 50 lines?
- 10 lines?
- 5 lines?
Unfortunately we cannot have a magic number like 5 or 20, because is pretty hard to generalized it. The length of a method depends on multiple factors like the code conventions. For example how often you hit enter to add a new line (for every ‘{‘ or for every logic statement and so on).
In general if you end up with a method longer than 10-15 lines of code you should take a look over it and see why is so long. Because of code conventions or it is because there is too much logic there.
Blocks and Indenting
Thing about an IF, ELSE, WHRE, REPEAT and this kind of functionality. You don’t want to end up with an IF on 10 lines. It is pretty hard to read and understand. For this kind of cases you should extract the check into a separately function and call if from the IF statement. Appling this rule you will end up with statements like IF or WHERE that needs only one line of code.Additionally to this you will improve the readability and documentation of your own code. For developers will be very easy to understand what the code does and what the check behind that is IF or WHERE supposed to do.
Do One Thing
If you read a long function you realized that more than one thing is done there. For example in the same function you open the DB connection, you execute a query, you convert the result to another type and you handle special cases. Each of this things should be done in a separately places.This is why a function should do ONLY one things. If you need to do more than one thing, than you should split it into separately functions.
Even if the statement is so simple, it is pretty hard to do this. If you discover in a function different part of code that is grouped or you can extract a part of it into a separate function with a meaningful name than the functions is doing more than one thing.
One level of abstraction per Function
This can be a mechanism that can tell us that the function is doing to many things. For example a function that process an entity and also internally start to split and transfer one of the entity fields has more than one level of abstraction.
It is pretty clear that you should extract the string processing into another function. In this way each function will have only one level of abstraction.
Switch Statement
The store related to switch statements is pretty long and we will talk about with another occasions also. In our case we should extract the logic of each of CASE’s to separate functions. Even if we will do this thing will not be okay because we are violating SRP (Single Responsibility Principle).We should replace the switch statement with polymorphism. This is the perfect solution, but there are cases when such a solution would add to much extra complexity. When you need to use switch statement you should hide them as deep as possible, in Clean Code the recommendation is behind a abstract factory.
Use descriptive names
The name of a function should describe exactly what it does. Not less or more. For example a function with name like ‘DO’, ‘ACTION’ are not very helpful, because we don’t know what are there scope.A name like ‘TriggerDoorLock’ it gives us all the information that is needed to know what that function is doing.
Finding a good name is pretty hard and can consume a lot of energy. Addition to good names you should be consistent and try to use the same naming pattern when there are similarities.
Function Arguments
How many arguments a function should have? The best value is 0, but not all the time is possible. Each time when you add a new argument think about the role of it.When you end up with more than 3 or 4 arguments something can be wrong. You should take a look over them and see if you cannot more the function in another location or to add another abstraction level.
The OUT option to arguments is not all the time recommended and it may be a smell that something is wrong there. For example the TryXXX methods usually check if a conversion can be done. If it can be done with success, ‘TRUE’ is retuned and the out parameter will contain the conversion result. This could be a smell that the method is doing too many things – converting and checking.
Have No Side Effects
This is the case when your function is doing more than one thing, but without telling to the client. For example a ‘Read’ method that read the content of a file and after it delete it without notify the user. In this case the user should be notified about this action or at least he should know about it from the moment when he does the call – ‘ReadAndDelete’.Because of this side effects we can end up with temporary coupling. For example when function ‘GoLeft’ can be called only if ‘StartEngine’ was called. You should think about a way to expose only the methods that are available at a specific time, without creating temporarily coupling. For example the ‘StartEngine’ could return an object that has only the commands like ‘GoLeft’, ‘GoRight’ and so on.
Command Query Separation
A function should do only one thing. You should never have methods that execute a query and in the same time a command. This two action needs to be separately all the time without exception.Prefer Exceptions and not Error Codes
Returning an error code created two additional things that needs to be done by developer/client. He needs to know the mapping of each error code and in the same time he has to check the returning error code.For this cases throwing an exception is better and will simplify the work of clients. Additional to this, the error handing will be 100% separately from your logic.
Comments
Post a Comment