How to Grow Architecture & Infrastructure (Be a Well Rounded Technical Lead, part 2)

Monday, 2 December 2013

Directing the build-out of a software project is fraught with difficulties. There is a definite requirement to build something fit for purpose, often quickly with new or untested technologies. But what 'fit for purpose' means is often changeable or not clear. As a Technical Lead, it's easy to get lost in the deadlines, or to build something that functions but doesn't work when the pressure’s on.

A Technical Lead is invested in to bring their experience to bear in the building of software. They are often seen as responsible for how the software is built.  They need to understand what's good enough from a number of perspectives and then try to deliver that, keeping an eye on the quality of the software built and technologies they use.

You can't do what your team can't do

You can't see all the code all the time, so your focus should be on the team. It pays to ensure they are informed, consulted and empowered to do the right thing. By focusing on your team it becomes far more possible to focus on the strategic, not just on the urgent.

You can't know everything at the start

Be learning focused: think strategically, build incrementally. Working in a field where technologies are always changing, exploratory processes can be invaluable. The work that you and the team decide to tackle first should shed light on your future choices. Does it solve the problem? Can we see it working in production? Does it make the delivery more or less risky? What if you had to throw it away and start again?

Be aware of the constraints

There are constraints that shape the system you build — from time pressures and the shape of the team; to the way and the scale you figure people will interact with your product. Some of the practices below help you discover them, others help you react to them. Being aware of how these construct and distort what you and the team build will help you to make something that will do the job.

Walking around the practices

Governance - Own the strategic

As Technical lead your job is ensure that the right thing is built and technologies are used wisely. It's your job to give direction when needed and to help the team put long term shape to what’s being done. It might involve setting out your expectations, or it might involve drawing pictures of what you are building with the team and asking them where the dragons be.

Though you may not know every detail about all technologies being used, you should be informed and have an opinion on how they should be used. There is no shame in not knowing something, but there is in not finding out. To govern well you'll need to also look outside the team to make sure choices are well informed and aren’t made in isolation.

Coding - staying connected with the day to day work

Peer review and pairing are good ways for the group to manage the quality themselves, but you need to be ensuring there is good stuff coming out. Though you can’t and shouldn’t do the lions share of the coding yourself, you should be involved and keep in touch with the team and what's being built. There is much to gain by being part of the coding effort.

Coding with the team and being part of the code review discussions are part of setting the standard and communicating your ideas. By staying connected you learn directly about the quality of the codebase and how easy it is to change, the standards the team is working to and the blockers they face.

Coding closely with other team members also gives you a view on what practices are valued, and what is understood at ground level. You get to see if the vision and metaphors are communicating a shared understanding of the goal.

Structure Emerging Design - grow the design as you code

When new software is being built, we often don't know everything about what it needs to do or how the code should be best structured. Sometimes we don't even know what technologies will be up to the job.

Your job is to ensure that the team builds a system that works as a whole, as they code the pieces. The system should have clarity: things should have a home and everyone should understand what goes where. Building for openness and flexibility can be the key: building in modules, introducing firebreaks and seams — reviewing and reconstructing as you go. Piecemeal incremental work, without review and restructuring can result in a Big Ball of Mud or a Monolith. Don't practice no-design, practice enough-design - think of the last responsible moment to act.

Review often enough to steer — stopping the line when large adjustments are needed. This is likely to involve having design discussions often, and planning rework alongside adding new functionality. Many teams have success in having 'town planning' style meetings and birds-eye-views of the system's design that gets adjusted as it grows. Having something on the wall that can be pointed at, talked to and criticised is essential for everyone to have a shared view.


Vision and Metaphor - a shared shorthand

Having a shared understanding is critical for a team to be able to move fast and accurately. You get convergence of the ideas in the code being written. A vision can bring a team to focus on the big picture of what they are building and how it could work. Keeping this in mind as each small part of the system is built can keep each aligned to the whole.

System metaphors are a great way for a group to find a common language around what they are building. They form a way for the group to share, talk and imagine the system being build at an abstracted level. Sharing language concepts with the wider business can help accuracy in conversations and remove surprises

Identify Technical Debt - build with explicit quality choices

Technical Debt is the trade off between now and later — the corners that the team trim off to get the software into user's hands sooner. Not thinking about everything can help you build something useful sooner. However, some corners cut stop the team reacting efficiently to change. A lack of design and bad code can generate more and more complexity on every change until all you have is an unmaintainable mess. Then it's rewrite time.

It can occur intentionally, when a team need to produce the next version ASAP, but it can also be unplanned. Accidental debt can result from code produced whilst a team is learning, or when standards slip whilst attention is elsewhere. Code often gets to live for longer than planned: adopted for new purposes, being more useful than expected. In the end code all to easily gets over complex and design gets lost.

Fortunately discovering your technical debt is easy: ask your team. They know the code that stinks, that feels like moving in treacle to change. Often what's slowing them down or generating bugs is the debt from previous work. Its worth fixing the pain points, but also consider looking into the root causes, giving you and the team something concrete to learn from.

Teams that review what they do and have the space to fix bad code can keep on top of the problem. You can start to get a gut instinct on whether a team is on top of things, and if they are aware of what level of quality they are producing.

Identify the Cross Functional Requirements - design a system that works under pressure

When building software we need to ask: what do we need to do to ensure that our system is reliable, safe and recoverable. The Cross Functional Requirements are constraints, user-needs and standards that should be considered to ensure that a useful system is built for the full set of stakeholders. Ownership of this challenge often falls to the Technical Lead as they have the skills and the knowledge to shape and inform discussions.

Often requirements such as these are implicit - they are assumed or inferred - whilst focus is placed on the user requirements and features of the system. Its well worth discovering the important CFRs of your system in conjunction with the investigation of the user requirements.

A simple way to do this is to take the stakeholder group through a list of potential requirements. Driving the discussion to discover what's important, when and why? Reviewing these CFRs with the stakeholders can provide a lot of insight and need to happen as work develops and as things change.

Once captured and understood, you need to take what have been learnt and turn it into material the team can act on. I’d recommend blending the requirements discovered from CFRs in to your backlog of work, to be prioritised and worked on together with user features. Not all CFRs can be seen as features. Some are constraints that should drive your design, others, like logging, are standards that should be considered on all stories.

Remove the Moral Hazards - burst the bubble of unreality

Moral hazards happen when a person is insulated from consequences of a situation, and so take risks they wouldn't normally take. Many developers work deeply silo’ed — coding well away from both the people who want what they are building and from where it's going to be running. This isolation can mean that many of their decisions aren’t based on all the facts and will suck.

You want your team to be able to make good informed choices, so it's your job to burst the bubble. Ensure they get time to to understand what their software is being used for, and where it's going to be hosted and used. Getting feedback from production like environments back to the developers as quickly can help guide good decisions. It helps to have them involved in the delivery and maintenance of the software as it's shipped.

Producing working code isn’t enough. Getting the code into the real world often and measuring success in that environment can really inform a team. Many groups work to build something simple and learn as much as they can as quickly as they can before expanding their users and systems.

Further Reading

Michael Nygard’s Release It tells of the complexity of integrating systems, and building a stable system when connecting the components of your own together. He also looks at the patterns needed to build a system that will scale. His talk 'Failure Comes in Flavors' talks about some of the stability anti patterns to avoid.

The Big Ball of Mud covers architecture anti patterns whilst Domain Driven Design suggests methods to help you build an implementation that reflects the world the code exists in.

Getting your software safely into production often helps you get feedback and lowers risk Continuous Delivery covers a wide area of topics in this area, but has a focus on a quality pipeline to production.

Summary - Rinse and Repeat

Ensure you and your team gets a good view of the problem’s different dimensions so you can deliver the qualities you need.  It's not not a one off job, periodically I like to look at our completeness against the constraints and again ask: 'what’s changed?', 'what's not enough?' and 'what if?'

The answers to these questions are often trade offs of the architectural needs, software quality, and the delivery, we look at how to balance some of the risks in the next post.

With thanks to Jen Smith for the read through and advice

No comments :