Skip to main content

Feedback

Introduction

Satisfaction Icon

In order to work effectively in small batches we rely on feedback loops. Without feedback we never know if we are on the right track. Feedback loops are essential for learning and adapting quickly. They are a way to validate our assumptions and hypotheses. We can only find out if we are right or wrong by testing our ideas in the real world.

In software development, we need feedback to know if our features are working as expected. We need feedback to know if our code is correct. We need feedback to know if our users are happy. We need feedback to know if our software is secure. Every decision about our software can be improved with feedback.

Even improving our processes or deciding on the best tools requires feedback. We need to know if our processes are working. We need to know if our tools are helping us. If they aren't we need to know, so we can change them.

Without feedback, we can only ever succeed by accident.

Real-World Example

David Farley gives a fun example of the value of feedback in his book, Modern Software Engineering. Your goal is to balance a broom on the tip of your finger. There are two basic strategies you can use to achieve this goal, one based on careful planning and the other based on reacting to fast feedback.

To employ the first strategy you would first need to calculate the center of mass of the broom. Then you would need to measure the air currents and other environmental factors that might affect the broom. Using this data you could then calculate the exact angle and force needed to balance the broom on your finger.

If our calculations are correct, the broom will balance perfectly on the first try, but calculating these values is complex and time consuming. If we make any mistakes at all, the broom will fall. We are also vulnerable to changing conditions. The slightest breeze could throw off our calculations, forcing us to start over.

The second option is to simply try to balance the broom on your finger. If it starts to tip one way, you move your finger in the opposite direction. This feedback is easy to get and we can react to it quickly. We can adjust our finger in real time to keep the broom balanced.

This simpler strategy is even robust against changing conditions. If a breeze starts to blow, we can feel the broom start to tip and adjust our finger to keep it balanced. We don't need to know the exact angle or force needed to balance the broom. We just need to react to the feedback we get.

Feedback in Software Development

While the previous example is a bit silly, it illustrates an important point. We can spend a lot of time planning and calculating, but we can never know if our plans are correct until we test them in the real world. We need feedback to know if we are on the right track.

Feedback is critical in every phase of software development. The source of this feedback may change, but the need for feedback remains constant.

Fail Fast

Faster feedback should always be preferred. The faster we get feedback, the faster we can learn and adapt. If we are going to fail, we should fail fast. The longer we wait to get feedback, the more time and resources we waste.

The topics below are presented in order of importance, purely because of the speed of feedback they provide. Feedback we get during coding is faster than feedback we get during integration, and so on. This means that we can get a lot more feedback during coding than we can during integration. This is why we should focus on getting feedback as early as possible.

Feedback in Coding

Every developer needs to be actively seeking feedback as they are writing code. Don't wait until after you think you're done to find out if your code works. Never rely on an external team to give you feedback, it adds too long of a delay.

There are two main sources of feedback we can get while writing code:

  • Compilation Errors
  • Unit Tests

Compilation errors are the fastest feedback we can get. They tell us immediately if our code is syntactically correct. If we have a compilation error, we can't even run our code. We need to fix these errors before we can move on.

Compiler Icon

Compiler feedback is fast, but doesn't tell us if our code is correct. We need to run our code to get that feedback. This is where unit tests come in. Unit tests allow us to validate our assumptions about our code. They tell us if our code works as expected.

Many developers only write unit tests after they have written their code. This is a mistake. Writing unit tests needs to be done in parallel with writing code. This way we can get feedback on our code as we write it. Test-Driven Development (TDD) is one way to force yourself to intersperse writing code with writing tests. In TDD, you write a failing test first, then write the code to make the test pass. This ensures that you are always getting feedback on your code.

Even without TDD, you should be writing unit tests as you write your code. I'll often write small tests just to validate my understanding of some utility or subroutine. If someone were to ask me whether I spent my morning writing code or writing tests, I can never answer that question. I was doing both at the same time.

Modern IDEs make running tests trivially simple. Run them often.

One additional approach to getting feedback on your code is pair programming. It can produce some of the best feedback you can get, but it is a large investment in time and resources. A good pair programming partner can give feedback that is immediate and of high quality. They might catch mistakes before they are made, and offer insights into code clarity that aren't obvious to the author.

The conversation that happens during pair programming is also valuable. You can ask questions and get immediate answers. You can discuss the best way to implement a feature. Pair programming is a great way to get feedback on your code and to share knowledge about the codebase.

Feedback in Integration

The next opportunity for feedback comes when we integrate our code with everyone else's. During this phase there are two kinds of feedback we can get:

  • Integration Tests
  • Code Reviews

A good set of integration tests can tell us if our code works correctly with the other modules in the system. They might give us feedback on how our code performs under load, or whether or not it is secure. These are usually too slow to be run after every change, but are helpful for validating end-to-end behavior. Integration tests are a great way to get feedback but quality sets tend to be rare and difficult to maintain.

During code reviews, we are looking for feedback from our peers. We're trying to leverage their experience to improve our code. They can tell us if our code is readable, maintainable, and following our team's best practices. Code reviews are a great way to get feedback on our code, but the quality of that feedback depends a lot on the skills of the reviewers and the amount of code being reviewed.

Consider a long lived feature branch. If you are working on a feature for a month then it is going to contain a lot of code. A code review of that branch is going to be a huge task, possible looking over thousands of changes. It is going to take a long time to review all of that code. This means that the feedback you get is going to be slow. The quality of the feedback is going to be lower just due to limitations on the reviewer's time. If the base state of the branch is out of date, even the integration feedback might not be accurate.

This is why it is important to keep your branches short lived. The shorter the lifespan of the branch, the faster the feedback. The faster the feedback, the faster you can learn and adapt. Trunk based development consistently outperforms feature branching in terms of speed and quality of feedback.

Agile Icon

Feedback in Design

Feedback that can accurately tell us if our software design is correct is hard to come by. There are no automated tests that can tell us if we have chosen the right overall design. However, testing can gives us some hints that our design might incorrect. If our code is hard to test, it is likely that our design can be improved. Well design systems, ones that take modularity and separation of concerns seriously, are easy to test.

The second form of feedback comes from more experienced developers. Mentors are critical to the growth of junior developers. They can provide feedback on design decisions and code quality. Their experience can identify potential problems before they impact the project.

The final form of feedback on our design can come from deploying our work to the real world. In order to make that process efficient, we need to be able to:

  • Deploy our software quickly and easily
  • Monitor our software in production
  • Roll back changes quickly if they are causing problems

If our deployment pipeline takes several hours to run, which is pretty common, then we are going to get feedback on our design very slowly. Acting on that feedback may also take hours. This is why we need to optimize our deployment pipeline. We need to be able to deploy our software quickly, ideally in minutes.

We also need consistent and reliable logging and monitoring. The behavior of our software in production is the ultimate feedback on our design. If we can't see how our software is behaving, we can't know if our design is correct. We need to be able to see how our software is performing, how our users are interacting with it, and how it is affecting the rest of the system.

CI/CD Pipelines

The best way to get feedback on your design is to deploy your software to production as soon as possible. This is why Continuous Integration (CI) and Continuous Deployment (CD) are so important. They are the best possible approach for any software development team.

Achieving CI/CD is not easy. Teams need to be able to:

  • Execute thousands of tests in minutes
  • Automatically deploy to production with no human intervention
  • Automatically detect issues and roll back changes

Even teams that can't achieve full CI/CD can still benefit from working towards it. Every improvement in your deployment pipeline is an improvement in your feedback loop.

Other Feedback

Even outside of the development process, quality feedback will help us to make better decisions.

Feedback in Product Design

Software engineers aren’t really paid to create nicely designed, easily testable software. We’re paid to build something that creates value for the organization. Our deployment process should be focused on delivering useful ideas into production as quickly as possible, and ensure that we put in place clear ways to measure the impact of those ideas.

The measurement is what gives us meaningful feedback and allow us to tell the difference between good ideas and bad ones. Good software organizations take this measurement very seriously. Telemetry is added to any new feature to measure its impact. A/B tests are run to compare different ideas, and then the results of these tests are used to decide what features to keep and what features to remove.

Logging Matters

Some developers view logging as a secondary concern. They want to spend their time writing features that are visible and have an obvious impact. Writing tracking code is never directly visible to the user, so it is often seen as a waste of time by less experienced developers.

This is a mistake. Logging is critical to the success of any software. If you can't measure the impact of your changes, you can't know if they are good or bad. You can't know if you are making progress. You can't know if you are wasting your time.

Just because a feature seems like a good idea doesn't mean it is. You need to measure its impact, and you can only do that with good logging.

Measuring Organizational Change

The same principles apply to organizational change. If you are going to make a change to your development process, you need to measure its impact. You need to know if it is making things better or worse. You need to know if it is worth the effort. If your team switches from Waterfall to Agile, how do you know if that change helps you to do you core job better? Are you building better software? Are you building it faster?

We need some way of measuring success. Unfortunately, most proposed metrics for this are terrible. Lines of code, number of developer hours, percent of test coverage, and other common metrics are all terrible ways to measure success. They are all easily gamed and don't actually tell you if you are building better software. They are all vanity metrics, not correlated in any meaningful way with quality software, value, or success.

"Working software is the primary measure of progress." - Agile Manifesto

The Agile manifesto pushed back against these metrics, and advocated for a more subjective measurement of success. This lead to a lot of confusion. Any attempts at measurement were just subjective guesses and useless for making decisions.

We can do a bit better just by applying the scientific method.

  • Identify where you are now and what you want to improve
  • Describe a step that you think will take you in that direction
  • Decide how you will measure whether you are closer to your goal
  • Make the change and measure the results

This is the scientific method at its most basic. This approach seems like it should be obvious, but it is rarely done. Most organizations tend to just make changes and hope for the best. They don't measure the impact of those changes. They don't know if they are making things better or worse.

An even better approach comes from the DORA research group. See the DORA Metrics section for more information.

Evolution Icon

Feedback in Your Career

The final place you need feedback is in your career. Are the skills you are learning valuable? Are you on track to achieve your goals? Are you making progress?

The 10,000 Hour Myth

The idea that 10,000 hours of practice is required to become an expert in a field is a myth. This can only work if you are getting fast, meaningful, feedback. If you are practicing without feedback, you are just repeating the same mistakes over and over again. You are not learning from your mistakes. You are not improving. You are not becoming an expert.

I've met plenty of developers who have been writing code for 10 years, but they are still making the same mistakes they made in their first year. They are not experts. They are just repeating the same year over and over again.

Career feedback can come from your peers, your mentors, or your manager. These are the people who can see what you're doing and spot areas where you can improve. They can give you advice on how to improve and can help you set goals. Your peers will be able to tell you if you are working well in the team. Your mentors will be able to tell you if you are growing as a developer. Your manager is there to help coordinate all of this and help you grow in your career.

Regular check-ins are essential. Your end of year review should never be a surprise. You should already know how you are doing, where you need to improve, and what your goals are. If you don't, then you are not getting timely feedback. Work with your manager to set up regular check-ins. These can be weekly, bi-weekly, or monthly. They should be frequent enough that you can make changes quickly.

While your manager should be helping with this, don't rely on them. They are busy and have a lot of other things to worry about. You need to take control of your own career. You need to be actively seeking feedback throughout the year.

Faster Feedback Improves Everything

Setting yourself up to get feedback more quickly leads to improvements across the board.

A projects I was once involved in was a switch from a 6 month release cadence to a weekly release cadence. In order to make this happen the DevOps team needed to reduce build times. They increase the size of the build farm, optimized the build scripts, and parallelized the build process. These changes reduced the average build time from about 6 hours down under 15 minutes.

This led to a huge decrease in the number of failed releases and the number of defects that made it to production. Developers were able to get feedback on their code much more quickly. They were able to fix issues before they became a problem. They were able to experiment with new features and see the results. Just by striving to get feedback more quickly, the quality of the software improved.

Conclusion

Feedback is essential for learning and adapting quickly. Without it, we are only just wandering in the dark. Every phase of software development needs to be guided by fast meaningful feedback. We need to be constantly seeking feedback on our code, our design, our processes, and our careers.

Image Credits