We are usually involved in projects demanding a high level of software quality, whether they be large legacy applications, where the customer is already beset with problems and is trying to shut the stable door after the horse has bolted, or newer pilot projects, which need to be built on stable foundations. As experienced technical experts we can of course help to get things on the right track. Having said that, we frequently find that our customers initially do not understand how quality is about a lot more than just good technology.
Even technically excellent teams can slip into quality problems if the working conditions or the project goal are unclear. In this article we explain why this is the case and what we can do about it.
Is it a bug or a feature?
Poor software quality often only comes to management’s attention when the number of errors reaches an unacceptable level. Yet what is actually a bug and what is just a (missing) feature? This question often leads to discussions between the product and development teams and cannot, strictly speaking, be answered without a clear written specification of the software’s requirements.
How do we decide during development what can be removed and what needs to remain? Most developers have experienced the situation where a bug fix leads to a string of new ones, due to something “not working like it used to” in the new version. For fear of breaking something, we often see developers steer clear of improving bad software design, which in turn leads to a continuing deterioration of the software’s maintainability.
To escape from this dilemma we need a shared understanding of what the software actually is: that is to say, what can it do and what not? Each user story should include clear acceptance criteria and, where applicable, define what is out of scope. For effective software development the team also needs to understand the broader context, i.e. not just what it is developing, but also why it is required and what concrete use cases are envisaged. Experienced teams avoid bugs through this type of communication, before they even begin with the implementation in code.
The development team still of course needs the right technical skills and experience in order to ensure that the software functions properly and is adequately protected through automated tests. Best practices such as pair programming, code reviews and test driven development (TDD) can help achieve this.
We frequently encounter projects with inadequate test coverage. Our approach is not to write new code or fix a bug without corresponding automated tests to verify the expected behaviour. This, however, presupposes that it is clear what the software is supposed to do.
Acceptance criteria in a user story serve as a basis for understanding this. Acceptance test driven development (ATDD) even goes so far as to translate the written specification into executable tests. Similarly, in the case of bugs, the way in which the functionality deviates from expected behaviour and how the error can be reproduced need to be clearly defined. This information can then be mapped into appropriate automated test cases so as to ensure functional correctness and avoid regression.
It is critical for the business to understand high test automation as an integral part of high-quality software which actually makes development faster: development speed should always be measured based on working features. Unfortunately, the deployment of technical experts is in many cases not enough to communicate this message, rather, the business often requires significant cultural and organisational upheaval, which reaches as far as management level, to achieve this. Development teams cannot bring about such a change on their own.
Additionally, efficient test automation can only be achieved when developers and testers work together cross-functionally. If testing is only carried out after the development stage (for example by a dedicated QA department) many of the advantages of test automation, such as fast feedback loops, are lost. Consequently organisational aspects such as team structure and process often go hand in hand with technical matters.
It is, on the other hand, not enough just to deliver good requirement documents and to expect a new culture to appear. Teams need to be capable of mapping these requirements onto an efficient test pyramid and ensuring the software still works in ensuing months and years. Even good teamwork is a skill that cross-functional teams need to learn through practice.
Furthermore, code testability is very much dependent on good software design. Technical methods, for example test driven development and refactorings, can help to improve this, and such methods can be more readily established when experienced developers or coaches are on hand.
Legacy applications often suffer from old code being difficult to understand and maintain. This leads to new features being very expensive and to an ever-increasing bug rate.
Experienced teams refactor their application code continuously and ideally avoid these pitfalls. They are capable of recognising how the software design can be improved as they go along in order to implement the current feature and regularly switch between the “two hats” (new functionality and refactoring) to achieve the goal in hand. They also keep an eye on upcoming requirements to ensure the technical foundations are optimised to deal with them. In order to achieve this they keep open a continuous dialogue with product team representatives and understand the current business goals.
But what happens when larger refactorings are required? Teams with only a technical focus might prefer to leave no stone unturned in order to achieve their interpretation of technical perfection and might even push for a complete rewrite of the application. This is, however, rarely the most efficient use of limited resources.
Refactorings should always be geared towards making the job in hand and future requirements easier and quicker to implement. Yet in order to achieve this, it is important to understand where the application is heading. A clear product vision and strategic focus on defined goals is critical so that refactorings with the most value (i.e. which improve future development speed) can be prioritised.
Whether larger refactorings should be undertaken is always a judgement call, which cannot be made solely based on technical reasons. A clear product strategy, which defines the key parameters for anticipated functional requirements, is incredibly helpful to estimate the relative effort of the refactorings and to answer important questions such as:
- How and to what extent will this component be extended in the coming development cycles?
- Does the current software design satisfy the requirements on the product roadmap?
- Do we (in the worst-case scenario) need to throw this component away and start from scratch?
Nonetheless, even the best product vision cannot be fulfilled if teams do not have the technical skills to dig themselves out of the hole they find themselves in. Once it is clear where the journey is heading, developers still need the right technical skills and training to understand how to refactor a legacy application and keep the project on the right track.
Software architecture is not an end in itself, but should seek to provide an optimal technical foundation for the product’s business requirements. There is no such thing as “the best architecture”, rather, it is always a question of making trade-offs. A software product will always have multiple architecture goals which conflict with and need to be weighed up against each other. Again, the product’s goal and its functional requirements will also play an important role here in making the appropriate architectural decisions.
During development, even the best teams will keep coming up against conflicts between current and future requirements. On the one hand, software architecture should be evolutionary and be improved incrementally, as it is impossible to predict users’ feedback and the exact nature of future priorities. Yet, on the other hand, certain architectural decisions do need to be made early enough in the development process so that the right foundation is in place to facilitate productive development. Only a well-functioning team, which not only brings together the relevant technical and business knowledge but also assumes responsibility for the software’s architecture, will be in a position to make the right decisions and react to changes in requirements in the best possible way.
Only through such teamwork is it possible to identify the right context boundaries in the application and to define the business domains and their objects. It is also critical to establish a universal language for these domains, so that business objects and the software’s use cases are clearly understood by the entire team.
Successful teams discuss the software’s architecture as part of their daily business and are able to experiment with various possible solutions. This is not possible in organisations where small predefined tasks are imposed on development teams from above or where teams are constantly under pressure from external deadlines. Agile practices in self-organised teams are therefore an important precondition for good architecture decisions.
It is, on the other hand, not enough simply to introduce agile frameworks and hope that this leads to teams being immediately capable of good software architecture. This will usually not be the case without support and coaching from experienced developers, especially if the previous working conditions were very different and the developers do not have prior experience of working in self-organised teams.
Code quality and the “four eyes principle”
Methods such as clean code, pair programming and code reviews help to achieve a high level of software quality. As technical coaches we can help out in these areas, but this will only be possible if development teams are given the freedom to try out and practise such methods as part of their day-to-day work. Similarly, teams need freedom to make their own decisions and take responsibility for matters such as architecture and testing strategies. Some of the teams we come across have solid technical skills but complain about time pressure, not being allowed to pair together, or long waiting times for code reviews. In these organisations methods such as pair programming are often seen as time-wasting, without understanding their positive benefits.
This is a clear signal that the organisational framework is not suitable. The importance of software quality needs to be understood throughout the entire organisation and embedded in its culture. Otherwise the benefits of any technical training will simply wither away, as, despite initial enthusiasm, teams will usually drift back into old ways of working due to external pressures.
Agility and teamwork
Technical skills and methods alone are not enough to succeed in agile software development. No matter which agile framework is used, all participants need to learn how to use the relevant tools and practices effectively and play their role in the team.
In Scrum, for example, it is not just the scrum master and product owner who need to be coached, rather, the developers also need to learn how to contribute to plannings, refinements and retrospectives in a constructive way. All roles need to work together and complement each other. Teams need to be cross-functional, so that they have all the necessary expertise to implement end-to-end features. Only this way can a collective responsibility for quality be established. Where teams are divided up on a purely technical basis, features often suffer from misunderstandings and errors at the interfaces between components, and teams blame each other when explaining why their integration does not work as planned.
There are, of course, also overarching software and architecture issues which need to coordinated at a cross-team level. A development team cannot manage this on its own: communication between teams and with others involved in such matters needs to be encouraged by the organisational structure. Developers should be enabled to take responsibility for such issues. The establishment of communities of practice can, for example, help to achieve this.
Continuous reflection and improvements of the development process and roadmap are ideally managed by the teams themselves – but, in most organisations that suffer from the above-mentioned quality problems, the necessary management setup is not in place to enable this.
Consequently we see the best possible results when our coaches also have direct and regular contact with management, to gain acceptance and adoption of agile methods at that level too. If this does not happen, the contradictions between “classic management” and agile development hamper progress, and we remain stuck with hierarchical layers – those above and those below – with all the negative consequences that entails.
For genuine changes in an organisation to occur, management buy-in is required, as well as a “sponsor”, who understands the necessary changes and measures (often initiated by the coaches) and promotes them in management circles. Such a sponsor is capable of translating the necessary changes into management speak and helping all relevant stakeholders to participate in the transformation.
Good software quality is not just a technical question, but depends on good teamwork:
- The product vision and goals need to be clearly defined.
- The organisational structure needs to encourage good development practices.
- The team needs to exhibit the necessary technical know-how.
We often find that the best way of helping our customers to handle quality problems is with a team of coaches with different skillsets:
- Product coaches help the business with product direction and prioritising the requirements.
- Agile coaches help to establish agile working conditions and self-organised teams.
- Technical coaches help the teams with the establishment of agile software development practices.
With such a team we can help businesses to attack quality problems from the root upwards and to improve quality in a sustainable way.
Do you want to learn more about building quality software for your project? Then feel free to get in touch with us.