Feedback-Centric Development — The One Hacker Way

Ralf Westphal
Clean Code Development
12 min readJun 5, 2017

Erik Meijer got something right in his talk “One Hacker Way”. There’s a lot of bashing and ranting… but at the core there also is a precious diamond to be found. It’s his admonition to be driven by feedback.

As software developer we should focus on production code — and let ourselves be guided by feedback.

How true! How simple! But contrary to the audience’s belief it’s no easy feat. He got much applause when he suggested, attendees who had not committed code recently should leave. People liked him extolling the virtues of “hacking”, of focusing on code — instead of on fuzzy stuff like a process or even talking or thinking. No, it’s the code, stupid!

Unfortunately they did not get the implications of this, I guess. And Erik Meijer did not tell them what that really, really means. So I’ll try to describe how I see what truly and honestly focusing on code and feedback means.

Purpose

I’m sorry, but before I get to code, we need to lay a foundation. We need to be very clear about why we should produce code in the first place.

Code is a tool for our customers. Customers want to use software to achieve something, to reach a goal. In order to be helpful for that, code needs to meet certain requirements. I see three basic requirements:

  • Software needs to be functional, e.g. a calculator has to provide addition and multiplication.
  • Software needs to be efficient, e.g. a calculator has to add and multiply at a certain speed.
  • Software needs to be evolvable, e.g. a calculator needs to be adaptable to changing functional and efficiency requirements, maybe in the future it has to also provide a sine operation or has to become even faster.

Functional and efficiency requirements define the behaviour of software which is produced by logic (for me that’s transformational statements, control-flow-statements, and I/O or API usage). Evolvability requires a certain structure which is spanned by modules on different levels (for me that’s function, class, library, component, micro-service).

What Erik Meijer means, when he favours hacking over some obscure agile way of development is, that software developers should produce code in order to create appropriate behaviour and structure.

And what he means, when he says we should look for feedback is, that we should check whether the code written already delivers on the behavioural and structural requirements.

Being Feedback-Centric

Now for the fun part: If Erik Meijer is serious about feedback, he needs to emphasize that it has to be sought frequently. In fact the central and recurring question everything is revolving on is:

How can I get feedback on my code as quickly as possible?

That’s what I call feedback-centric. Yes, we should focus on code. But code without feedback has no value. So we should seek feedback “at all costs”. As soon as possible. Frequently. From the most relevant source.

Software development thus becomes a high frequency iterative activity:

  1. Code
  2. Check (gather feedback)
  3. Back to 1. to fix any deficit or add more behaviour or improve the structure

Feedback-centric development thus is code-first development. I like! Don’t you? As Erik Meijer said: Forget about test-first programming or even TDD. It’s the production code which rules!

Tiny Steps — The №1 Implication

If you really, really buy this — it’s about code and about feedback –, then you also have to buy the implication: Coding has to progress in tiny steps.

Because only tiny steps can get you frequent feedback. If you hack away for an hour or a day without feedback, then you’re coding pretty much in the dark. Truly frequent feedback is not more than a couple of minutes or hours away.

When you look at some requirements you have to ask yourself: What can I do to get feedback in the shortest possible amount of time? Can I get feedback in 10 seconds, 5 minutes, 30 minutes, 4 hours?

Not Only Code — The №2 Implication

The ultimate feedback of course is on code. So if you can feedback on some code in 1 minute go for it.

At least initially, though, it’s even faster to get feedback without any code. Producing code and getting some stakeholder to check it for conformance to requirements often takes longer than simply asking a question.

Code should not be a question, but a statement of some understanding — even if that turns out to be wrong.

So as long as you’ve questions or are not very sure if you understand what the requirements are… do not start hacking. Rather ask questions, e.g. by talking or by presenting some test cases you made up.

Test cases are a an excellent way to demonstrate understanding. They are unambiguous. Any explanation of your knowledge needs interpretation. Not so test cases. They are either correct or not.

Incremental Steps — The №3 Implication

Being driven by code and feedback also means, you can’t just program any code. The code you want to write is, well, code you can get feedback on. That means it needs to be code some stakeholder can relate to.

Feedback-centric development thus means producing code incrementally. Code needs to make a difference, needs to produce some possibly very small additional value. And if that’s indeed the case only a stakeholder can tell you.

Incremental development means outside-in design. You need to start with actual requirements, not technological details. Requirements have to be finely sliced to arrive at increments which can be quickly implemented for feedback. That’s an art of its own.

Automatic Tests — The №4 Implication

Once you’ve identified a tiny increment you can start coding. That’s just fine. No need to write a test first. What a relieve, isn’t it? ;-)

Then, after maybe 3 minutes of writing production code, you run the code to give yourself a first round of feedback. Since you’ve asked a lot of questions you’re some kind of authority on the requirements — but of course by no means ultimately decisive. The right to accept only lies with stakeholders.

But how do you run the code and check it for deficiencies? You can do that manually. That’s just fine. But how frequent can you then check?

Not checking the behaviour for correctness with automatic tests is a violation of the core principle of feedback-centric development. It’s not just about code, but also the fastest feedback possible. You have to balance code production and feedback generation.

That means, you need to write automatic tests. Do it after you wrote your production code. That’s fine. Since you only added a tiny increment there is not much to test. At least do it for every error you encounter. Reproduce the error with an automated test, then fix it. Rerun the test to get feedback if your fix actually works.

Automatic tests have two feedback purposes:

  • whether the code you just wrote already delivers on the required behavioural increment (maturity tests)
  • whether other code still delivers on its behavioural requirements (regression tests)

TDD might seem to provide no benefit. But it should be clear now, that test-after, i.e. for feedback generation after hacking is a must. It’s a sine qua non if you’re serious about the One Hacker Way.

But contrary to Erik Meijer you might want to consider test-first none the less. Because writing the test before the production code gives you the benefit of more focus and of higher probability of good coverage.

Testable Structure — №5 Implication

Now that automatic testing finally is inevitable even for the most eager hacker ;-) it should be obvious that not just any code structure will do. The code must be structured in a way as to be easily testable.

That even means, each increment should be testable in isolation. Otherwise the feedback would not be precise — which would be a violation of the fundamental principle we started out with.

What this leads to is… refactoring. Finally! Because in TDD refactoring is clearly optional. Yeah, it’s a prescribed step after the test went green — but look at the TDD examples out there. They are a testament to how easy it is to skip this step.

No, TDD does not (!) exert any force to make a developer refactor her code. Everyone rather writes the next red test. But if you’re serious about the One Hacker Way, i.e. feedback-centric development, then you have to provide yourself with quick and precise feedback. And that (!) requires you to structure the code in a way to make it possible.

  1. Code some increment
  2. Write a test to get feedback on just that increment; if that’s not possible, refactor enough to get it working

Feedback-centric development makes you the first consumer of your code. Eat your own structural dog food and see if it’s palatable, i.e. if you can easily test the logic hanging in that structure.

Structural Review — №6 Implication

Manual or even automatic tests just provide feedback on behavior. But as stated above it’s not just behavioral requirements the production needs to deliver on. Customers want us to write code in a sustainable way. Nobody knows what kind of changes come around in the next weeks, months, years. So our production code needs to be prepared; it needs to be evolvable.

Evolvability is a quality of the structure of the code. Traditionally it’s produced by some kind of modularization. Recently some more principles have been added to reach this goal under the name of Clean Code.

However you call it one thing is for sure: evolvability is hard to measure. Automatic tests and the customer/user can give comparatively easy feedback on functionality and efficiency. But whether evolvability is high enough… they can’t tell. Especially because evolvability cannot be stated in a requirements document.

Customers simply assume software to be infinitely malleable and to live forever. Mostly, at least to my experience.

That means, tools measuring certain structural metrics cannot tell the undoubtable truth about the structural quality of software. At best they might hint at certain spots where it seems evolvability is lower than desired.

The ultimate feedback on evolvability only comes from… developers. If developers have a hard time to change a codebase, then it’s hard to evolve. It’s that simple.

How then can feedback from developers as authorities on evolvability be gathered frequently?

Firstly, the feedback is generated implicitly by adding the next increment. If the developer trying that finds it difficult, he just has generated feedback — and can act on it. Refactoring is fixing an evolvability deficiency when it arises.

Unlike with TDD where there is no feedback on structure generated, and refactoring is recommend in a broad brush manner, in feedback-centric development refactoring always has a clear purpose. It’s done when necessary to enable the next increment.

Evolvability is too important to leave it to a single developer, though. Sensitivity to structural quality is very unevenly distributed among developers for several reasons. That’s why it is helpful to get feedback from more than one developer as soon as possible.

Enter pair programming. During pair programming it’s possible to focus on behaviour and structure at the same time. Four eyes see more than two. So if you haven’t been convinced of pair programming so far, but like the idea of The One Hacker Way… now is the time to start pair programming. It’s a valuable technique to get more frequent feedback on code structure.

Equally valuable is of course the age old technique of doing code reviews. I don’t think they should be replaced by pair programming. Code reviews go beyond the four eyes of the developers who wrote the code. More eyeballs simply can spot more structural flaws. Also a group can check if the structure matches a common understanding of how code should be modularised.

But even with pair programming and code reviews I feel there is something missing, though. They generate feedback on structure with different frequencies and from different perspectives. But the feedback of both is, hm, somewhat artificial.

Improving the structure to enable an automatic test carries a certain urgency. Refactoring is really needed to be able to continue according to the principle of frequent feedback. Pair programming and code reviews don’t “force” structural improvement in such a way.

That’s why I suggest another technique I call code rotation (or maybe story rotation). Code rotation means, some requirement should not be fully implemented by a single developer or even pair. If coding an increment takes a day, for example every 90 minutes the eyeballs looking at it should be completely exchanged. Maybe developer A and B start, then C and D continue etc. Yes, A and B should be replaced by a fresh pair. There is a quick handover — and then the new pair has to get along alone with the codebase.

And that’s the point: Only if the developer(s) working on a requirement change completely will there be honest feedback about the structure. If even one dev of the first pair remains for a second tour on the code the feedback is “contaminated”. We’re so prone to lie to ourselves when it comes to our own code… This can only be avoided by letting fresh eyeballs look at it.

Sometimes I employ this technique in trainings. I let developers start to work on an exercise — and then after a while they hand their code over to their neighbour. You can imagine that this is no delight for anyone ;-) But why? It’s this dissonance that needs to be removed from coding. It stems from non-obvious code structures.

Bottom line: Evolvability is of great importance. Unfortunately it’s hard to measure. So we need to actually look at code and work with it to get a feeling for its quality. Therefore we need to establish a hierarchy of feedback cycles:

  1. Make every increment testable — refactor as needed. Frequency: continuously
  2. Make code understandable to your pair programming partner — refactor as needed. Frequency: minutes
  3. Make code understandable to your successor — refactor as needed. Frequency: hours
  4. Make code understandable for the whole team — refactor as needed. Frequency: day(s)

Software Design — №7 Implication

Switching pairs during development of a feature is a tough call. Sure you want to avoid it. But why? Too much context switch? Takes too long to find your way around the code of other devs to be able to continue their work?

Yeah, right. That’s all difficult. But you can choose: experience that now — or sometime in the future. And it should be obvious that it becomes harder the longer it takes until somebody else looks at your code.

In order to make code rotation as smooth as possible another technique is needed. Frequent feedback gets another prerequisite: design.

Yes, I believe the reason for explicit design now should become apparent. Explicit design done by a group of devs or even the whole team helps to understand the code. Also it decreases the need for refactorings later.

Some modularization cannot be avoided to be done ad hoc during hacking. But quite some modularization can be done before even starting to code. It’s a part of developing a solution. It’s the “thinking before coding”. And it has value because it makes it easier for developers to switch working on the codebase.

So forget about design “because that’s how you do software development”. Also forget about not doing design “because that’s how real programmingers code.”

Explicit design is a means to an end. It’s purpose is to develop a common understanding of easily evolvable coarse grained structures — in order to increase the frequency of feedback. Because you don’t want to wait years to realise you’re sitting on a monolith, if the next developer can tell you in a couple of hours he has a hard time extending what you left behind.

Continuous Deployment — №8 Implication

Ultimate feedback only comes from those who require your code to do their job. That means it must be very, very easy to give your code to them. The closer the code to the final usage environment the better.

That’s why continuous deployment is so important for any software project. We need it to be a no brainer as much as possible to deploy code so we can ask just about anybody for feedback at any time.

Think about A/B deployment, think about deploying each increment separately, think about deploying only to a subset of customers… The more freedom and options you have, the better for gathering feedback.

In Closing

At first I did not like Erik Meijer’s talk much. But once I saw through his polemic fireworks I realized how much truth can be found in what he said. Never mind his suggestion to treat developers as top athletes. Never mind him calling Jeff Sutherland a satan.

Let’s stick to the title, the core of his message: We need to focus on code — because only that’s delivering value. And we need integrate feedback into our work much more seriously — because only then we know if we’re actually heading in the right direction with our code.

Forget about hype, buzzwords, and any elaborate belief system like “Agile” or “Scrum” etc. Yes, like the Buddhists are saying: “If you meet the Buddha on a road, kill him.” We need to kill our Buddhas, the gurus, the dogmas. Let’s do away with cargo cults.

Instead focus on the essential: production code. And get as much feedback as possible. Truly become a closed system on many levels of your daily practice and your organisation.

If you like this article, click the heart and/or share it. Thanks! Or you might have a look at my personal blog here or the (mostly German) blog on Clean Coding by the Clean Code Developer School.

PS: If you happen to recognise one of your favourite “agile practices” in my above description, congratulations. Of course there is value in some of them. We don’t need to throw the baby out with the bath water. My point, though, is to justify such practices starting just from production code and the need for feedback. Nothing more, nothing less. No buzzwords, no argumentum ad verecundiam.

--

--

Ralf Westphal
Clean Code Development

Freelance trainer, consultant, speaker in the software industry for more than 30 years. Main motivation: make programming joyful and simple. http://ralfw.de