Made Tech Blog

There’s no substitute for experience: lessons from central government software delivery

I joined Made Tech in a lead developer role on a central government account. The client and everyone involved are fantastic. They’re amazing people that are fun to work with. We’re lucky to work in a well-sponsored and supported initiative. Our client clearly wants to make their processes better for their end users, and it’s great to be working on a project that will make a real difference to the whole of the UK. It’s been challenging but hugely rewarding work, so I thought I’d share some of the things I’ve learned.

The importance of transparency

But I’m not going to lie – it was a rocky start. Partly, because I caught COVID at the very beginning of the delivery. Fortunately, my team stepped up in a big way, keeping pace in what proved to be a rapid and challenging kick-off. But there were other challenges too. As we got familiar with the code base, we realised that most of the skills we’d need were new to all of us. 

To be open with the client, we shared that we’d need to learn and get familiar with the core languages of the project as well as particular frameworks – let alone the actual code base and its bespoke approaches. 

Understandably, the client was concerned, but they soon realised that the technical requirements of the code base would be challenging regardless of familiarity with the languages. We introduced the concept of polyglots – developers skilled in various languages and methodologies – and the benefits they bring. In particular, we discussed skills including extreme programming (XP) and clean architecture principles

This validated the importance of being honest and transparent with clients. Almost always, they’ll give you the freedom to prove your worth. And it prevents a mismatch in expectations. But there’s still hard work to do and frank conversations to have. 

There’s no substitute for experience

There’s a lot to be said around coding standards and subjective expectations. Here I mean the kinds of things that you can’t learn from a book or tutorial. The things that somehow get done through the established ways of working with various ecosystems. It’s the kind of knowledge that experienced developers forget they ever learned. 

Experience is key. In a lot of cases, the specific problem can only be learnt  by doing – and in particular, by making mistakes and fixing them. Eventually, newer developers feel at ease contributing too.

My take is that the benefits of tribal programming can be significant, so to get up to speed quicker, it pays to get familiar with the tribe’s language as soon as possible. A team should have developers who have experience with a part of the tech stack, with overall expertise spread among the team. 

You’ll be better placed to support each other. And it can help prevent unnecessary debates about trivial stuff. Honesty and hard work are vital in building trust, but that can be a balance between expense of time and speed to deliver. But anything that creates an extra overheard can count against you when performance is measured by certain metrics.

Pragmatism beats prescriptivism

We didn’t strictly follow extreme programming, in that pair programming wasn’t a convention. Neither was test-driven development (TDD), the code being a reflection of code after patterns, but at least tested, which is sealing code to help with change. 

XP simplicity rules or design principles were not always followed. The test pyramid was inverted after an architectural decision to cover a lot more than a unit test, using tools that were more inline with front-end ways of visualising problems. 

The biggest challenge for us was that these tools did not lend well to “TDDing” problems, leaving us with that empty feeling of lacking the tools to do the job. 

The backend could facilitate TDD, but this was difficult because these integration tests, incorrectly represented as unit tests, seeded real databases at the expense of very slow tests. This meant minutes for a test in some cases when even seconds would be unacceptable. 

This was not the fault of any API developers and was endorsed by this framework. This had probably worked very well on small projects, but problems emerged when scaling up. The bottom line is we couldn’t immediately demonstrate the code discipline we wanted and expected to practise, and at best felt useless in immediately solving problems with aligned best practices. 

A lot of these ideas were born from good but misinterpreted ideas, which is hard to change when this has come out of using “better” coding practises. A good example is Ian Cooper sharing a story of TDD and what went wrong, which people interpreted as “only do end-to-end testing” and delete most other tests as it will just bake you in concrete. Which is a bit like a builder removing the underpinning of the house because you’ve put in stronger window frames and added a porch. 

When historical code is littered with bad unit tests, it can reinforce the idea that unit testing is in itself bad. I have seen this a lot in different organisations, where devs go overboard with testing frameworks and with the wrong kind of tests. And I include myself in that when first introduced to TDD. I contributed to the same anti-patterns without realising it, so I sympathise at how easily this happens, even with the best of intentions. 

Tackle one thing at a time

The next few months were about solving specific problems, understanding the good and the less good, and trying to influence change where possible. We successfully solved several features facilitating experience through the entire stack, and including other microservices outside of the immediate project. 

After 10 months of experience with the project, we were able to facilitate work done for another department. We made client end users very happy with features making their user experience better, where they’d previously felt ignored or neglected. 

As time has gone on, we’re now at the stage of talking about the future and how inefficient some ways of working have become. Even though the intentions are good, the productivity is measurably more stifled, and the bottom line is that code entropy is not just about surface level code rules. 

We’ve been able to integrate with other teams, facilitating a faster transfer of domain knowledge and the potential to pair with developers outside the Made Tech mindset, but this has been slow to adopt. Wider adoption is gearing up. We’re still a long way from applying first principles but in first gear and making progress to the next stage. 

The important thing to pass on from our experience is that change doesn’t happen overnight. Patience and conviction of cause will help solve one problem at a time. You need to forge alliances and earn trust that will help change to happen. 

The rest is hard work, determination, coupled with good practises and value-driven objectives. If you can’t measure and understand success, it won’t happen. You are also part of a team where the group mentality is what you’re bringing to the offering, and should be agreed and understood by most, to keep it well aligned and build the momentum needed to make change possible.

You can read more about Made Tech’s work with central government on our website.

About the Author

Vincent Farah, Lead Engineer at Made Tech

Vincent Farah

Lead Engineer at Made Tech