So, you have made it. You are the Product Owner of the company’s flagship product. Now you will spend your days thinking about business value and customer satisfaction, and leave all that technical stuff to the development team – you never understood it anyway. Unfortunately, you’re not off the hook so easily. In order to correctly prioritize the product backlog, you need to be aware of some of the technical items that will need to be included there. You need to understand the value of these items and recognize the terms the development team throws at you. Or worse, if the developers do not throw these terms at you, you will need to demand of the team they start using the technical practices you deem most valuable to your product.
Practice #1: Version control system
This is something that almost every project team already has in place – if they don’t, your product is probably in big trouble. What a version control system (VCS) provides is a place to store all versions of all files in the project, which in turn gives you a easy way to go back in time to previous versions of files when the need arises. It is, to use another common term, a system for source code management (SCM).
A VCS gives you an opportunity to, among other things, maintain a current release and a future one in parallel and keep track of who has changed what in the project files. It also enables you to use continuous build (more on that below).
There are several systems for handling the version control, and which one is the best for your organization is a question that you, the Product Owner, probably do not need to worry about. A few examples of systems that are being used are Subversion, CVS, ClearCase, Team Foundation Server and Git.
Practice #2: Continuous integration
If you have a version control system (VCS) in place, your team should consider taking this step. A continuous integration (CI) system takes the code that has been submitted to the VCS and automatically builds a new version of the product.
The value of doing this is that you always have a the latest version of your product built and ready, which allows for (more or less) immediate testing, manual or automated. You also get very fast feedback on any build-stopping problems that have been introduced with the latest code. Often the system is set up to report, via email or some other more immediate form of feedback, to the submitter of new code if the build breaks. If you have several teams working in parallel on the same product, you should have them make every effort to have the continuous integration build the entire product from its subsystems.
Another value of having a CI-system is that it forces the team to create a fast and automated build process. You will no longer have to be in the position where the team says it cannot release the product because “only Ron knows how to system, and he is out with a cold for the week” or “sure we can build a new release for you to test, but you have to wait for three hours before you get it because of all the manual steps we have to take to build the product”.
Finally you should look into automatically deploying the built product as well – most CI systems will have support for that.
There are several systems for doing continuous integration. A few examples are CruiseControl, Hudson and Team Foundation Server.
Practice #3: Automated testing
Testing the product manually usually takes a lot of time. In fact, for larger systems it is not uncommon for the testing to take longer time than the development of new functionality. So to improve this common situation, we introduce automated tests.
Automated testing can be introduced at several levels of the development. Closest to the code is unit testing. This is a technique where the developer writes a few lines of code that tests other pieces of the code. These tests can be written before writing the source code (called Test-Driven Development, TDD) or after writing the source code (unsurprisingly called Test-After Development).
We can also introduce automated smoke- and integration-tests. These are especially useful in conjunction with a continuous integration system – after building the product automatically you run a quick few tests to make sure the product seems to work – at least enough to start and be ready for more serious testing later.
Going further, it is of great value to introduce automated regression and acceptance tests. This is, in many cases, the most challenging thing to accomplish. But the payback can also be a lot bigger if you put in the initial effort of getting this in place. This is where most of the manual testing is usually done, and as mentioned earlier, it can take weeks and months to do this in a larger system. The regression testing is focussed on making sure the new code has not broken any old functionality, at least not any old functionality that is covered by the regression tests that are in place. The acceptance testing is done to make sure the product adheres to the requirements.
One major objection usually used by teams is that it is hard to automatically test graphical user interface (GUI) applications. It is to some extent true, but it is today quite doable in most modern software development environments. A couple of tools to have your team look at, if they are up for the challenge of introducing this, is Selenium and Marathon.
The biggest gain in quality is achieved if your team can manage to introduce automated tests at all levels. But doing it at just one level is much better than having no automated tests at all.
Practice #4: Refactoring
Refactoring is the art of rewriting the source code so that it does exactly the same thing, but in a different way. This may sound a lot like waste, and something the developers would love to do for the fun of it, but is in fact a requirement for being able to work in an agile way with software development. You need to take some time to rewrite things that is already working, to accommodate for new functionality. The alternative would be to try and anticipate every possible functionality that may be introduced in the product in the future, and this has been proven again and again to be a futile task – there will as good as always be changes in the requirements while working on a product.
Refactoring also takes into account that the developers learn while building. So after building something, they will know a lot more than when they started, and can, with a little extra effort, make the code more maintainable, less error prone and more agile in the sense that new functionality can more easily be added to it.
To not continuously do refactoring, is to risk building up what is called technical debt. This means that if we just keep adding new functionality, sooner or later (most likely sooner), the team’s progress will slow down due to technical limitations in the code. To be able to keep a steady, possibly increasing, pace of delivered functionality, the team needs to continuously work with refactoring.
To be able to do this without introducing a lot of bugs in existing functionality, automated testing (unit and/or regression) is almost a requirement. There is a lot of support for refactoring in today’s development environments, but to do it efficiently is an art that the developers will need to learn. All you have to do, as the Product Owner, is to allow them some time to do this.
Practice #5: Simple design
Designing a software system entails deciding how different parts of the system should collaborate and how responsibilities should be divided between them. This can be done in (almost) as many ways as there are developers, and there is rarely only one correct choice. All too often the design ends up being the work of the smartest developer or architect on the team, using all the latest trends (oh yes, there are trends) in software design. Most often it is also a big up-front job, meaning the design of the whole system is done before the work of implementing any part of it has started. This leaves the more inexperienced developers more or less clueless about how things fit together, and they end up able to contribute less to future design discussions. Also, if/when the smartest developer, the one brain smart enough to comprehend the superb deign of the system, leaves your company or moves on to a new product within your company, the rest of the developers are left feeling very confused and lost and having a really hard time implementing new functionality within the framework of the design they do not fully understand.
To counter this problem, and to work more agile with the software development, we want to avoid doing a full design of the system up front but instead let the design evolve while implementing functionalities of the product. To be able to do this, the team needs to keep the design simple. A simple design is more easily improved when the team learns more about the product they are building. A simple design is also easier to modify when requirements change mid-project. And not least, a simple design is more likely to be understood by all members of the development team.
One technique that aids in making the design simple is to keep the domain model, the software implementation of the world you product will live in, defined in terminology that can be shared by everyone involved with the product – the developers, the domain experts, the Product Owner and the end users. This allows for much easier discussions – everyone can use the same terms for the same things. A lot can be learned from the area of Domain-Driven Design (DDD) about how to actually do this.
Practice #6: Collective code ownership
A quite common problem in software development is that without conscious effort, there will be parts of the code that no more than one of the developers dare touch for fear of breaking something. This makes the product much more vulnerable to that developer leaving the company or being on sick leave for an extended period of time. To avoid this, the team should make an effort to introduce collective code ownership.
In practice this means that there should be no parts of the code that only one developer knows. Every developer on the team cannot, in most instances, know exactly every part of the product, but all developers can be familiar with all of the code, and you should make sure to always have at least two developers that know more about each specific part. To accomplish this spreading of knowledge we can use several methods. One way is to do code design discussions and reviews at regular intervals, where developers present parts of the code to each other and discuss the chosen solution and possible refactorings. You can also make it a requirement for a developer to discuss a chosen solution with at least one other developer before it can be submitted to the version control system. A way of making the knowledge transfer automatic, is to introduce pair programming. This entails two developers sitting at one computer, solving a problem together. This may sound like a waste of resources, but those who start using it oftenly find that the quality of the code produced, and the reduced cost in time for knowledge transfer, more than make up for the time “lost” when two developers work on one task.
To make it easier for the team to actually do this, I recommend you have two things in place. The first thing is a common coding standard, to make sure developers write their code in the same way. It need not be extremely detailed, but at least some commonality should be found in how the code is structured regardless of which developer has coded it. The second thing is the simple design I discussed as practice number 5.
So now you have heard about my top priority practices. My suggestion to you is to spend time and effort implementing them – if not all at once, at start trying to implement at least a few of them. The aim of these practices is not to make the developers happier because they get to use them, which they very well might be – developers most often want to create better code – but rather to make your product better. Better in this context meaning more maintainable and more easily changed when you have changes in your requirements. Best of luck to you!