Agile software practitioners focus a lot of attention on people, communication, collaboration, and strong values. In many environments, these are unquestionably the best opportunities for improvement. Inevitably, though, all software development teams reach a point where their greatest opportunity for improving the way they implement and deliver a product are of a technical nature. There is no single standard set of universal technical practices, and Best Practices really need to be thought out in the context in which they would be used. Each team should look at what is most appropriate for their context.
Practices
Here are the core practices we see used by high-performing Agile teams:
Agile Testing
Agile testing is a core part of applying the lean principle of Build Quality In as we develop products. Testing in Agile involves applying testing in a way that increases collaboration and understanding, improves feedback, and helps implement quality products quicker. While the use of automation is an important practice, ensuring we can do the types of manual testing not easily automated, but provide valuable feedback, are just as important.
The key practices and principles here are:
- Agile acceptance testing
- Move QA up-front
- Minimize QA at the end of the cycle
- Ensure cross-functional collaboration
- Testing as an integral part of implementation (incrementally and iteratively)
- Automate the right things
Other Resources:
- The Agile Testing Quadrants
- The Test Pyramid
- The Agile Testing Book
- Behavior-Driven Development or Specification by Example
Test-Driven Development
For most teams automated testing is not new. Some form of unit testing or functional testing is common, but to get a better return on our testing investment, there is a need to level up. We can increase the level and timeliness of feedback by adopting the practice of Test-Driven Development (TDD). In addition to earlier feedback, TDD leverages tests to give the team design feedback that influences better and less wasteful implementation of features than is usually found by testing after implementation.
The same TDD workflow that is most often applied to Unit Testing can be applied to different levels of tests. The most common TDD related testing activities are:
- Test-Driven Development
- Acceptance-Test Driven Development
- Behavior-Driven Development or Specification by Example
- Test Automation
- Refactoring
Other Resources:
- Red-Green-Refactor
- Elisabeth Hendrickson has a great ATDD example that is a helpful read.
- Book: Growing Object-Oriented Software Guided by Tests
- TDD process smells
- BDD In a Nutshell
Continuous Integration
Software implementation involves the combined efforts of one or more people brought together to form something that is ultimately deliverable. Feedback should be given at the earliest point possible to tell us when new features do not cleanly integrate with existing ones, or the behavior of the system has changed in an unexpected way. While merging and integrating code lines is often considered painful, doing it more often and in smaller increments makes is easier, as well as provides earlier feedback.
The most common practices within Continuous Integration are:
- Use a single source repository or main code line
- Automate the build
- Test each build
- Commit to the mainline frequently (daily)
- Drive integration, build, etc from every commit
Other Resources:
- Book: Continuous Integration: Improving Software Quality and Reducing Risk
- Martin Fowler’s Continuous Integration article
Continuous Delivery
With Continuous Delivery we mean:
- Using deployment pipelines and deployment automation
- Test Automation
- Continuous Deployment
Other Resources:
- Jez Humble’s Book/Blog
- Deployment Automation Patterns cheat sheet
- Continuous Delivery vs. Continuous Deployment
Refactoring
The goal of Code Refactoring is to restructure existing code in order to improve its readability, reduce complexity, improve maintainability, and make it more extensible without changing the external behavior of the code. This is done by relying on automated tests to ensure the behavior of the code stays the same while making a series of small, incremental changes to the internal structure of the code.
Many modern Integrated Development Environments (IDEs) and code editors provide functionality for assisting with applying common patterns of refactoring such as extracting a new class from an existing one or renaming a method across a code base for clarity/readability.
Refactoring is a key part of Test-Driven Development but can also be performed outside of the cycle when necessary. Normally, the observation of a Code Smell is the driver for performing refactoring.
Other Resources:
Peer Review
Core Practices:
- Code Reviews
- Collective Ownership
- Pair Programming
Emergent Design
Developers, architects, and teams often struggle with how and when to approach design. In contrast to the more waterfall style of Big Design Up Front in a designated phase, Agile teams tend to design all the time and let the design emerge as features are added. This certainly happens continually through refactoring as part of Test-Driven Development, but other elements of design also take place in planning sessions and designated design sessions. By employing emergent design throughout, we reduce the waste or rework associated with unvalidated or unused designs.
Some key practices and concepts are:
- Principle of The Last Responsible Moment
- Simple Design (Minimizing Accidental Complexity)
- Finding Effective Abstractions
- Harvesting Idiomatic Patterns
- Managing Technical Debt
- Genericness (Over Engineering)
- TDD as a Design Tool
- Refactoring
Other Resources:
- Kent Beck’s Rules of Simple Design
- “You Ain’t Gonna Need It” (YAGNI)
- Essential Complexity vs. Accidental Complexity
- Clean Code
DevOps
DevOps is often discussed as an outside yet complementary practice to Agile. But its focus on collaboration, shared understanding, and shared responsibilities across Development and Operations are much like the Agile team struggles between Developers and Testers or other combinations of Roles. For Agile teams, DevOps is a key part of achieving Continuous Deployment and Continuous Delivery. These practices are also important for improving consistency, reducing wait time and other wastes, and sharing knowledge between roles that traditionally have been very siloed.
While collaboration and communication are critical, the key technical practices involved are:
- Deployment Automation
- Infrastructure Automation
- Infrastructure as Code
Practices for Improvement
Whether you are Agile or Lean, use Scrum or Kanban, or none of the above, these practices and principles and others like them should be considerations for your toolbox and for initiating team improvement.