The following strategy outlines the changes necessary to ensure code quality while modernizing your approach to software delivery. Greenfield applications have the luxury of thinking about the problems inherent in an existing organization’s delivery process in a new way. Working with legacy applications brings about significant angst as experience has taught us to be leery of making changes to these brittle applications, due to both the complexity and cost associated in working with these applications.
This article attempts to appease those fears by illustrating how simple it is to apply a contemporary approach to software delivery to not only legacy application code, but to organizational structures and processes which are also legacy in nature. Adopting these new practices and embracing this advice has proven to lead to delivery of high quality, production-ready software at the speed of Silicon Valley startups.
When it comes down to it, agile and waterfall are not so different. Agile attempts to do everything good about waterfall, while shortening the amount of time it takes to begin the feedback loop. Agile is meant to make your processes leaner and quicker, and constantly evaluates anything which lengthens the feedback loop, or hinders rapid delivery of high quality, working software.
The test cycle in software is a very important part of the feedback loop. In modern application delivery, as much of this cycle is automated via unit tests, integration tests, and functional tests. In order to accomplish this, developers must have clearly defined acceptance criteria: what makes a feature “done” from the customer (end user) perspective. Acceptance criteria is usually generated just-in-time to ensure the most immediate information is applied, and stale constraints are not inadvertently applied to a feature.
In waterfall software delivery, testing is typically manual, and is deferred until after the complete build cycle. The feedback loop is delayed, and bugs are inevitably discovered late in the process. Even worse, the context of what makes a feature “done” is usually incomplete or outdated, as acceptance criteria was forced into the language of a requirements document, and usually prepared months prior to the beginning of the QA cycle.
In order to understand how to make the necessary changes to adopt agile’s approach to testing, is worth exploring both the differences and similarities between waterfall and agile software delivery. Only then will the changes required for people, process, and technology in order to successfully adopt this new way of doing things become apparent.
Existing, siloed waterfall processes attempt to guarantee the delivery of quality software through manual, tail-end quality assurance testing. At this point in the project, the waterfall process actually starts to emulate agile – bugs are identified, reported, and developers fix those bugs, and then a new QA cycle begins. However, a “wall” still exists between the QA and development teams, and direct communication and real-time collaboration are often discouraged in favor of using ticketing systems and email.
In an agile project, QA team members are embedded with the agile team, co-located to ensure maximum efficiency through direct communication. Once each story has been delivered by the software developer, it becomes ready for QA testing. QA testing can happen at that moment, and any questions the QA team has about the story can be asked of the developer directly. QA testing is faster and more efficient, since the scope of change is smaller. Bugs are discovered within the iteration (or sprint), and instead of creating a bug in the agile backlog, stories are rejected and developers fix them immediately.
Another core facet to working with legacy code is the introduction of automated tests. Legacy codebases will typically have little to no automated test coverage, nor continuous integration (CI) builds to ensure that those tests are being run. As such, the starting point in working with legacy code is often to setup an automatically triggered build in a modern CI build system. This CI build should, at a minimum, check out the codebase, attempt to compile it, and run all unit tests. Failures should be reported immediately. This build should run on every code commit to your SCM.
Once the CI build is equipped, work on the software can commence. Any time any change is made to existing code, a test should first be written to prove that a class and relevant methods works as it currently does before making a change, then the developer makes the change, and re-runs the test to prove that the class still works as expected. The CI build further validates this by running the tests outside of the developer’s machine.
At this point, the feature is considered “Done” from the developer’s perspective. The story is ready to be handed off to QA for manual verification, often from a functional perspective. For example, the QA team member opens up the application in their browser, and interacts with the application according to a “test script” – a written set of instructions on how to test the app, including negative test scenarios to validate – and proceeds to explore the application for bugs. As previously mentioned, any bugs discovered are communicated directly to the developer, the story is rejected with the bug info, and the story goes back to the developer.
Modernizing the QA approach takes more work. The QA team member’s manual work should be automated. Automating API testing could be done with tools such as SoapUI test suites, or PostMan. Selenium provides an robust toolset for automating tests against HTML-based projects. This poses a problem for many large organizations, however, since QA teams are considered non-technical. Arguably, anyone with a little time and the right incentive can learn how to use any of the tools mentioned here to employ automated tests.