Before getting to software quality, lets spend time to see how a software degrades?
Software degrade doesn’t happen in a day or a week, it takes couple of months or even years for us to realize that the software quality is degraded. And it takes even more time after that to bring it back on track. It just starts to happen from the day when we start rushing the code into it, without giving enough time for ourselves to think before implementing features or fixing defects, we always tend to think the code that we write is good.
And if we are not concentrating on quality on every step we take in developing we end up as I had mentioned in my last post here.
Imagine how it would be if we could track the degrade at the moment when we insert a bad code. It really needs good observation and practices to achieve it, but in real world since we are so busy in writing new code and delivering quickly we least bother on looking back on what we have done wrong. And we are always proud of our code, how can we check if we are at the best.
There are few good practices that will really help us to avoid sidelining with your product quality path. And using these practices in every step will ensure us that we get early warnings and keep our product lively.
Let’s see what are the quality parameters that really matters in product health.
- Cyclic Dependencies: This is the most important of all, this parameter targets the types and namespaces. If there is any cyclic dependencies then it shows most of the principles are broken. and once we introduce cyclic dependencies, its really really hard to maintain that piece of code. To describe a cyclic dependency lets taken an example. If a type/namespace A is using a type/namespace B and B in-turn is using A, then we call such dependency as cyclic dependency. In this case both A and B are tightly coupled and any changes in A or B will result in an impact in both of them. Writing UT for such dependent types is also hard to mock or stub.
- Afferent coupling (Ca): This parameter helps us to monitor single responsibility principle (SRP). This parameter is applicable for method, type (class), namespace (package) and even assemblies. For eg: if 3 other types are dependent on a type t1, then afferent couple of t1 is 3. If there are more types referring a type then it shows that it is taking more responsibility and it should be broken down into multiple types.
- Cyclomatic complexity (CC): This parameter is the count of number of path of execution. For eg: If there is no condition in your method then the CC of that method would be 1. If there is one if condition it would be 2. So any condition in your method will increase the CC by 1. All the following keywords increases CC by 1. If, while, for, foreach, case, default, continue, goto, ||, &&, catch, ?:,?? etc..
- Interfaces: Following dependency inversion principle (DIP) and interface segregation principle (ISP) gives us very much flexibility for future modification.
- New keyword: For creating any object, we have to use a new keyword, but why is it called bad to use new keyword? new keyword is good if its in right places, it should not be scattered though out the code, the less new keyword is used the better. We can decrease the usage of new keyword using factory method, dependency injection or MEF. But how does it help us?? imaging a logger class, and as of now we have a requirement that logger should log only in a text file and we implemented it and used new keyword across our code wherever we need logging. Later if the requirement says we should provide also option to log in event logger then we start writing if-else inside our logger class. Instead its a new responsibility and should be taken care by a new class. So if we had the creation of logger in a factory, we can just write a new implementation and return it.
- Comment and names: Comments as suggested by uncle bob in his book “Clean Code” is ugly. He suggests that if the variable, methods, types, namespaces and assemblies are named in a descriptive way, then there is no need for a comment. Reading a line should feel like reading an English sentence. Always make a class noun and a method verb, Eg a class Cycle can have methods like Ride(), Start(), Stop()
- Number of lines: This parameter depends on programming language that is used, for .Net and Java for a method 15 is an ideal count, and for a type its 200. There are many cases that is observed when you cannot write a logical flow within 15 lines in a method. But ideally it’s good to method and type as short as possible.
DIP says no classes should be accessed directly but should be used thorough an interface.. For eg imaging if a type A wants to use B, instead of referring B directly in A, create IB interface and use IB in A, now A is dependent on the signature not the behavior, if new type of B1 comes we don’t have to change anything in A, and simple pass the instance of B1 instead of B.
ISP says dont clutter your interface with all the methods but segregate it using SRP. For eg: if we are writing some class for Person and create an interface IPerson with methods, walk, run, stop, sit, stand, eat, sleep, meditate, exercise etc. Instead separate IPerson with behavioral interface, like IMove can have walk, run, stop methods, instead of having them in IPerson directly. and then inherit IPerson or better Person class from IMove.
There are many many more quality parameters that needs to be considered. But lets focus on these above parameters since they are really important to be taken care of. In next post lets see how to get early warnings on the above parameters as soon as we break the law.
Let me know if there are any important parameters that I have missed to mention.
Happy Learning :)