eZ Community » Blogs » Arne Bakkebo » Best practices - QA#3

By

Arne Bakkebo

Best practices - QA#3

Wednesday 03 April 2013 8:50:25 am

  • Currently 5 out of 5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

In my previous post I talked about having a code formatting standard to make the code more readable. Having established this as a routine, the next step of readability is to consider how to make what you do with the code more readable. This part is rather hard to define, so I'm going to talk about some best practices here.

[QA#2 - Code formatting standards]

There can be different criterias for software development best practices, some may oppose one another at some point so we have to consider which is the more important criteria depending on the task at hand. I have outlined some general considerations here (not necessarily in prioritized order):

  1. Simplify interfaces and reduce code complexity
  2. Avoid unnecessary dependencies
  3. Reuse code (avoid duplications)
  4. Write consistent code (use the same methods and practices throughout the project)
  5. Consider the frameworks intentions (don't work against the framework you are building on)

I have probably forgotten some points, feel free to give your input on this list. Point 5) refers to for instance eZ Publish and Symfony2, or any other library you use in your code. I guess points 3) and 4) is fairly self explanatory, so I'll focus on 1) and 2).

How do we make the cleanest possible interfaces between different systems, modules, classes and functions? Several methods have been developed to simplify this process. Those of you who have worked with eZ Publish 5 may recognise SOLID[1], which is the philosophy that Symfony2 is based on. I will quickly summarize it here:

  • Single Responsibility - limit each class to have a single purpose in the solution.
  • Open/Closed - make each class available to be extended (open), but not available for interface modifications (closed).
  • Liskov Substitution - if our code use base classes, it must also be able to use any classes derived from these base classes without modifying our code.
  • Interface Segregation - a class should not be dependent on any other class that it does not need, keep classes as independent as possible.
  • Dependency Inversion - make your modules depend on abstract interfaces, not on implemented classes.

Personally I've mainly focused on the Single Responsibility and Interface Segregation parts, but I'm thinking it is a good idea to follow all of these as a matter of course. As always in software development, if you start building good habbits then making good software does not necessarily take more time than making bad software. Of course, the challenge is in building good habbits.

Btw.Single Responsibility and Interface Segregation does not limit itself to only classes. This should be a focus on modules and functions and any separable entity in the code as well as classes.

When doing software development, what makes the development process run out of time is not writing the code. It's going back after it is "done" and fixing the code...multiple times. And the further out in the development cycle you get (planning, writing code, testing, deploy), the more time it takes to go back and fix it[2]. To avoid many rounds of fixing the code, I recommend planning the different interfaces before you start working on the code itself. Consider the classes you require, consider every function and variable in each class, take care to plan each parameter required in the functions and decide if the function should be private or public.

For the function parameters, take care to keep them to a bare minimum. Keep a mind on the context the function should have, do not include parameters that does not fit with that context, and avoid function parameters if the values can be found inside the function. Don't use boolean parameters to specify different purposes of a function, instead split it up in different functions and move duplicated code out in sub functions. Also, keep a focus on the different names you use, make every name explain something about what your code does.

When you are done, ask someone else to consider your interfaces, and give you feedback. Having someone else review your plans is invaluable to reduce the number of times you have to go back and fix things. It takes some practice to learn to plan good interfaces. Getting feedback from someone else is a part of that learning process, and so is discussing the better solution of two alternatives. I plan on writing a bit more about feedback in a future post, when getting to the topic of code reviewing.

Consider also how much work a function should do. If you put too much logic into one function, the code becomes longer and gets harder to read. If the function becomes too long to easily grasp, try to mark out logical single purpose units within that function and move them out in a new sub function.

It's impossible to put absolute limits on what makes good or bad code, but I'll list some warning signs here. If your code hits one or more of these warning signs, it's not necessarily bad but it should tell you it's worth the time to reconsider your code:

  • A function with more than three to four parameters
  • A function longer than 20 lines
  • A function with an undefinable single purpose
  • Duplicated code
  • More than one or two static functions in a class
  • More than four to six public functions in a class (this depends a lot on the purpose of the class though)
  • Functions with reference parameters (a function should need only one return value or object)
  • Undefined magic numbers (define all numbers in the code as constants with descriptive names)
  • Comments that does not explain the purpose of the code
  • No comments
  • Commented code that is not in use any more
  • Variable names called "temp" or similar meaningless names
  • Inconsistent code formatting (ref.my previous post)

There are probably more good warning signs, feel free to add yours in the comments.[3]

The point here is not to write perfect code. There is no such thing as perfect code. The point is to keep a focus on how to improve the code at all times, because that is how you end up with clean code and learn how to make it so.

Ok, I think this post is getting long enough, so I'll end it here. Keep in mind that it takes a lot of practice to learn good software development practices, and that people have written massive amounts of heavy books about these topics. I think it's worth a summary though, hope it helps someone.

References:

[1] SOLID methodology: http://www.codeproject.com/Articles/60845/The-S-O-L-I-D-Object-Oriented-Programming-OOP-Prin
[2] Speedy software development: http://www.stevemcconnell.com/articles/art04.htm
[3] Best practices: http://codebalance.blogspot.no/2011/02/20-software-developing-best-practices.html

Proudly Developed with from