The idea of progression in a craft through well defined stages has been around since medieval times. Begin as an apprentice, qualify as a journeyman or journeywoman, perhaps eventually progressing to a master of your craft.
This held up well until the industrial revolution, when we decided mass production and cheaper goods were a better deal. Germany still has a strong culture of vocational training, but the modern practice is different from the tradition.
It's 14th century Europe, you're 10 years old and you've decided wood is the most exciting technology around. You want to solve real-world problems and deliver a truly 15th century product. Or at least your parents do and they've sent you to live with a master carpenter as an apprentice. While you may start out on household chores, in just 7 short years you'll graduate to journeyman or journeywoman. You'll be a proficient carpenter, ready to work on any project.
At some point you might decide to open your own workshop, take in some apprentices and mentor them in the same way you were mentored. You've become a master carpenter and the process begins again.
Code as craft
The construction of software should be an engineering discipline. However, this doesn’t preclude individual craftsmanship. Think about the large cathedrals built in Europe during the Middle Ages. Each took thousands of person-years of effort, spread over many decades.
Lessons learned were passed down to the next set of builders, who advanced the state of structural engineering with their accomplishments. But the carpenters, stonecutters, carvers, and glass workers were all craftspeople, interpreting the engineering requirements to produce a whole that transcended the purely mechanical side of the construction.
It was their belief in their individual contributions that sustained the projects: We who cut mere stones must always be envisioning cathedrals. (Quarry worker’s creed).
What does a modern software development career look like from a traditional craft perspective?
You start with the household chores of the development team, working on issues and smaller features. There's enough to learn right now. You can use the safety of a well-scoped feature, without much ambiguity, to stay focused on strengthening your core skills.
You learn one language really well. Get to know the standard library in detail. Not just the core APIs of the language but taking the time to read the library code itself — a great opportunity to see what idiomatic code looks like in this language. While it's always good to know multiple languages you need strong proficiency in at least one. You'll work with it until you understand its strengths and its weaknesses. "Java is slow" is a poor critique, a better understanding might say "Java tends to verbose code which can make comprehension slower, Java 8 is an improvement, but a reasonable type system and the JVM make it a great choice for many problems. I still wouldn't write a web app in it though."
This is the point where you gain your initial trust. That small issue turns out to be unexpectedly complex. The root cause lies in code owned by another team. They haven't touched it in months. You've built up the context, you understand the problem better than anyone else right now, you carefully craft a fix and submit it for review. Even if there are comments and you have to change most of what you wrote, people will take notice. You're someone who can be trusted to own a problem, whatever it takes.
This stage might last months or years, but the quickest progressions I've seen come from engineers with endless enthusiasm and curiosity. Their pace doesn't change when they switch from an exciting new feature to a hard to reproduce bug. Learning is expected, mistakes will happen. Attitude counts more than aptitude.
Let's use journeyperson and acknowledge the gender imbalance in our industry and that gender identity is not a binary concept for everyone.
Ambiguity in the problems you solve increases. Does this solve the right problem? In the right way? You learn the easiest way to anticipate future requirements is to keep things simple now rather than try to predict the future. Sometimes you'll talk directly to customers to figure out what they truly need from you, rather than what they're asking for. Planning and estimation become more important as you coordinate across multiple teams; technical, sales, marketing and support.
You leave the comfort zone of a single technology, embracing new languages and tools. Your goal is proficiency at every level of the stack. Mastery of the back-end alone means your interface is poor and unwieldy, the solution doesn't work if nobody can use it. Mastery of the front-end alone confines and restricts the ways you can solve problems. Even the terms front-end and back-end start to disappear as you realize it's all one big distributed system.
Trust continues to increase as you take on larger and larger projects. Delivery isn't always exactly as planned but you communicate setbacks well and there are no big surprises. Gradually you begin to assert ownership of one particular area of the product. You understand how people use it, know where the problems are and tackle them incrementally — carefully balanced with new capabilities.
The most impressive progress I’ve seen people make has been when they’ve taken on work in unloved areas, problems with the least well defined solutions or those that require slow, unglamorous, grunt work to begin turning around. They keep an upbeat and enthusiastic mindset, motivating people around them to join in their cause.
At this stage in your career you’re no longer tackling individual problems, you own an entire space — the early stages of a complete product or a significant function of something more established.
You think strategically about what you’re building and how you’re building it. It’s not just the product manager’s responsibility to say no. You know what your competitors are doing and what makes you different, where they’re better than you too.
You’re actively involved in building your team. You develop apprentices, keep your journeypeople focused and productive while finding the best new talent to join them. Even if you’re not directly involved in people management, you understand the importance of hiring, development and retention for your team.
The people I learn from in this role think strategically and are always on top of the detail. They’re acutely aware of the biggest gaps in the product, their top source of new bugs and what’s slowing down their development team the most. They have plans that tackle all of these, in small steps, continuously iterating and improving.
Choosing a good apprenticeship
“The Joel Test” sets a minimum bar for any software team. At 15 years old the advice is still valid, there’s no good reason your company should fail.
In a similar spirit, if you want to work where you can progress, what should you look for?
- Are my limits my own? The only limits on your growth should be those imposed by yourself. The worst companies tie progression closely to tenure. Others will have artificial limits, “you must be here 18 months before you can be considered for promotion.” Choose a team that will give you the next big challenge as soon as you’re ready for it.
- Do I have peers to learn from? Books, conferences and blog posts can help you become a better engineer but the most effective way to progress is to be surrounded by people you’ll learn from. Code reviews, design reviews and pairing will push you further than you can get by yourself.
- Does the team care about my growth? Expect a weekly one to one with your manager. Their role is to remove obstacles in your way and help you develop. Make sure personal development (relevant to the team) is called out and rewarded in any performance review process.