Owing to code is a strategy that can solve many use but must be kept in control.
In the previous post I did a brief summary about Scrum, and also, I mentioned that it is an agile framework that intentionally leaves some gaps (the technical aspects) that are meant for the team to fill in according to their own needs and reality. Today, I want to discuss about some engineering practices and techniques that can help teams fill that gap. But first there is a concept that needs to be clarified...
You owe it to the code
The Technical Debt Concept
The concept of technical debt is similar to a financial debt; you acquire a financial debt when you borrow money to use it in a short term with the promise that it will be paid later on at the costs of interests.
Whenever a developer team chooses to implement a feature or to fix a bug using a short term solution at the cost of making it harder to change later on; the team is increasing the technical debt of the software. The development team might be willing to implement a short term or quick fix to gain an advantage now (like releasing on time or restoring a faulty system) with the promise to pay it later on by removing the short term code and replace it by more mature and better quality code that will last longer (as the later solutions take longer to design and code).
In a team with many developers, the debt on the software being worked on can grow quite fast, and as with financial debts; the debt must be kept under control at all times to prevent to reach a crisis state or to get to a point where the debt is unpayable.
Teams working on software with a huge technical debt will spend most of their future development time paying such debt (fixes will take longer to implement and harder to do, and changes will impact more and more pieces of the software) The time they’ll spend on adding features will be reduced because of the time they’ll need to fix bugs and stabilize the software.
Technical debts are very hard to measure; teams need to be careful and must be aware of the decisions and choices they have made that increased the technical debt of the software being worked on, keep a track of them and aim to pay them as soon as possible.
Code with small technical debt is less rigid and more adaptable; remember that in order for the development team to keep doing agile development the code needs to be kept adaptable (to support changes that enter latter in development) so managing the technical debt is a must if agile development is to be used.
Engineering Practices, Techniques and Tools to aid agile development and to lower technical debt.
Code Refactoring is the common name that groups a series of techniques used by developers to change the internal structure of software without changing its external behaviour. The main reasons why the code might need an internal restructuring is to improve some of the software quality attributes like: maintainability, efficiency, scalability, accuracy, reliability, modularity, adaptability, etc.; and to pay technical debt.
Agile development requires high adaptability and maintainability in the code it is producing (as changes are welcomed even on late development) while development teams need to keep working at a steady pace. Code growth is also accelerated by agile development; refactoring often is a way to improve adaptability, maintainability and when done well, it helps keeping the code manageable as it grows.
Developers also use refactoring as a way to introduce patterns to existing code, it can also be used on relational databases (this is more complex as the migration of data also needs to be addressed). HTML and JS files used in web applications also benefit from refactoring techniques.
Among the most common refactoring techniques are: extract interfaces, extract classes, extract methods, lazy initialize attributes, remove middle man, replace constructors with factory methods, and many more that I won’t mention here.
Refactoring could be risky and dangerous (when it is done improperly it could introduce bugs and destabilize the software); that is why it's extremely important for developers to have a way to guarantee the applied refactorings are successful every time (by successful I mean that refactorings improved targeted software quality attributes while the functionality wasn’t affected by them).
The way to do it is to measure the results before and after the refactorings and compare them; the type of measurement required depends on the target quality attributes to improve; for example measure latency and response times is needed to determine the successfulness of refactorings done to improve performance.
However, to verify that the external behaviour has not changed after the refactorings, the development team need to test all functionalities impacted (regression testing) and the results must be the same results before and after refactorings.
These regression testings need to be performed every time the code changes to ensure that the external behaviour remains the same after any modifications to the code; this will give the developing team constant visibility on the functional correctness of the software.
One technique that is most useful to help achieve this constant visibility is by producing Self-Testing Code.
Self-Testing Code and Test Driven Development (TDD)
Self-Testing Code, according to Martin Fowler, is the practice of writing comprehensive automated tests in conjunction to the functional software. The key concept is that each software piece must be able to test itself... thus the name “self-testing code”.
Self-Testing Code is achieved when the development team can be confident that by running the series of automated tests against the code base, the functionality correctness can be accurately measured.
“should these tests pass, the team could confidently say the code is free of any substantial defects”.
This automated test suite must be produced as part of the software; in fact in self-testing code the software can’t be considered as done if these automated tests are pending.
To ensure the benefits of self-testing code, the suite of test must be executed often (the closer they are from the changes, the better) and the test suite must be up to date and correct at all times.
If done properly there will be less bugs in production, but the greatest advantage is that it will allow the development team to change the code without the fear of breaking it; it will give them confidence to adopt changes (the essence of agile development), it will also enable the refactoring needed to keep the technical debt controlled.
Test Driven Development (TDD) is a technique for building software where development begins by writing tests first; then the new functionalities are built by only writing the minimum amount of code needed to pass the written set of tests and then the code is refactored to make it clean.
Kent Beck (one of the Agile manifesto authors) is credited as the developer of TDD back in the 90’s while creating XP.
The advantages of TDD are that it produces Self-Testing code, and also forces the development team to understand the requirements and to think in the code interface first, as these are needed to be able to write the required tests.
The basic steps to follow are:
Write all automated tests needed to guarantee the next bit of functionality to build is correct and execute them so that they fail (there is no code to test so the tests should fail).
Write the code that implements the next bit of functionality and test it against the written test until all written tests passes.
Do all refactoring needed to clean up the code base (this will keep code base clean as it grows).
These steps are repeated for any new bit of functionality to add to the software. Developers should never integrate code that breaks the tests into the mainline.
So, by producing Self-Testing code, the refactoring power is fully attainable, as there will be a safety net to do it that removes the fear of breaking working code; and by refactoring often, the technical debt can be reduced, the adaptability and maintainability of the code can be kept as the codebase grows and better quality is achieved.
One technique that also helps to produce better quality code while improving performance of the development team is Pair Programing.
Pair Programming (PP)
Pair Programming is a software development technique in which two developers work together, concentrating on the same code, using the same computer.
PP is often associated with Agile development (the main reason is because eXtreme Programming uses this technique) however it can be used outside the agile world too.
The idea behind Pair Programming is to let developers write better code by collaborating in pairs as equals (not as a teacher-student mentoring type of collaboration) by doing so, continuous discussion and review is fostered,as a result they will produce better designs, they’ll make fewer mistakes, learn from each other and in general they’ll write better code than if working individually.
Usually, when Pair Programming, both developers sit side by side in front of the monitor; one developer will be the driver (will have control over keyboard and mouse), the other one will be the navigator; the driver will focus on writing the code while the navigator focuses on reviewing each line as it is typed and on the strategic decisions (that will directly impact on the quality attributes of the code been written like: cohesion, low dependency, adaptability, complexity, etc); both developers must continually discuss the decisions been made and review the code produced by alternating the roles often.
There are other variations on how to do it, like using remote tools to enable PP in distributed locations; in this case the team must pay attention that the use of such technologies doesn’t interfere with the focus of the PP activity.
It is often found that pair programming increases productivity of the development team, as the coding tasks are done faster and of better quality than when working individually, however the number of man-hours needed to finish a coding task will often increase as well, thus making it more expensive.
Additionally PP requires social and soft skills from the developers; like: good and continuous communication, teamwork, creative thinking, negotiation skills, etc; so to be effective pair programmers either need to have these skills or invest time to let them develop them.
As you may imagine, PP requires time to be fully adopted, as it is a counterintuitive way to typical programming and most developers will need to learn it before actually being able to use it effectively. The best way to adopt it is by letting your team try it; however it’s a good idea that you find someone with real experience on PP so that he can teach the team how it should feel.
PP’s common benefits include: performance increase , better code and reduction of the risks of having only one person familiar with parts of the code.
In the next post we will discuss additional practices used like: Continuous Integration and Continuous Delivery.