“Experience is a dear teacher” – Benjamin Franklin
In previous posts, I’ve focused a lot on getting the right people in the door – great coders with great attitudes who communicate status aggressively, don’t wait for someone else to fix problems, and never let bad news wait. At which point, of course, there’s nothing for a manager to do but lie back on the couch and eat bon-bons.
Ok, maybe there’s still some work to be done. In particular, helping your engineers to develop their skills is key not only for improving their work result, but also for maintaining motivation and reducing attrition. With this in mind, this post will describe a variety of strategies for software engineers to improve their skills. Some of the things in the list will be blindingly obvious, others a bit less so. Likewise, some will be easy to implement individually, others will require institutional buy-in. Hopefully, this will be a useful set of tools both for managers looking to help their teams, and for individual contributors seeking concrete ideas on how to level up.
Whether it’s to share exciting new advances in a particular technology or important best practices in working with the codebase, to help new employees come up to speed, or just to give your engineers a reason to get together and eat pizza, regular tech talks are great for a variety of reasons. They help build cameraderie, give engineers an opportunity to demonstrate initiative (i.e., by giving a tech talk), are a chance to bring industry luminaries into the building, and tell your engineers that you’re interested in investing in their development. And did I mention the pizza?
Unfortunately, you’ll notice that I didn’t mention that they’re great for improving skills, and in fact I’d say they’re probably the least valuable method for doing so. Consider: someone gets up and talks, the audience listens passively, a couple of questions are asked… but unless the information is immediately actionable, and/or the talk is combined with a workshop or exercises, the majority of the value will be lost. The reason they’re so common, and the least useful, is because they require the least effort from the majority of participants. The main technical benefit is generally from associated workshops, exercises, or the excitement they create, which might encourage individuals to act on (and reinforce) the information immediately.
Conferences are a special case of tech talks, with a couple of caveats. On the one hand, they suffer from the same weakness – most people in the audience won’t get any long term benefit, because they won’t do anything to use or reinforce the knowledge immediately afterwards. On the other hand, workshops can be helpful, and conferences can be very useful for networking. Also, multiple sessions on a particular topic can potentially lead to more excitement, which in turn can lead to an individual doing more to learn about it on his or her own.
The next rung up the ladder is the reading group. Every week, a group of engineers read one or more chapters in a book, then get together to discuss. Typically, a more experienced engineer leads the discussion, describing real-world examples related to the book’s points. Reading isn’t going to be as effective as doing, of course, but it keeps a topic in the reader’s mind for the duration, and the discussion around the chapters can be very effective in reinforcing the ideas.
As an example, TripAdvisor is a Java shop, and one of the first things we do for all new engineers and interns is to hand them a copy of Effective Java and get them into weekly discussion groups. There are plenty of ways to misuse Java (or C++, or Rails, or <insert your favorite language here>), and the first goal is to make sure everyone has the same understanding of common techniques and anti-patterns. Because the group members are actively coding in Java while doing the readings, and are presumably running into some of the things being described, the points get reinforced naturally. We’ve found this to be an effective way to make sure everyone has a baseline understanding of key Java best practices.
Lastly, it can be very helpful to add exercises and/or workshops to the reading sessions. The more opportunities the engineers have to actively use the concepts, the more useful the readings will be.
Here are some books we’ve had good experiences with:
- High Performance Web Sites: Essential Knowledge for Front-End Engineers
- Java Concurrency in Practice
- Don’t Make Me Think: A Common Sense Approach to Web Usability, 2nd Edition
- Gamification by Design: Implementing Game Mechanics in Web and Mobile Apps
And, of course, some of the classics:
- The Pragmatic Programmer: From Journeyman to Master
- Peopleware: Productive Projects and Teams
- Design Patterns: Elements of Reusable Object-Oriented Software
Learning new languages / different paradigms
“A human being should be able to change a diaper, plan an invasion, butcher a hog, conn a ship, design a building, write a sonnet, balance accounts, build a wall, set a bone, comfort the dying, take orders, give orders, cooperate, act alone, solve equations, analyze a new problem, pitch manure, program a computer, cook a tasty meal, fight efficiently, die gallantly. Specialization is for insects.” – Robert Heinlein, Time Enough for Love
You’re lazy. So am I. So is every one of your users, which is why you spend so much time trying to simplify your app’s flow to improve conversion. Learning a new programming language is the equivalent of a large number of clicks between a problem and its solution – it’s much easier to code something in a language you know, using a familiar paradigm, than to learn a new one first, even if it would be a better fit for the problem. There’s a psychic weight to this additional step that’s out of proportion to the actual time required.
In general, picking up a new language isn’t that hard, and pays dividends outsized to the investment – especially if it forces you to use a different paradigm. OOP, functional programming, mixing inter-operable JVM languages, mobile apps, bash scripting, bizarro language X – there are lots of different options, and the only requirement is that you choose something different from what you’re doing now.
Sure, you might not become a hardcore Rails developer if you’re only doing the odd project here and there, but it’s going to force you to think in different ways. And the more languages you’re comfortable in, the more tools you’ll have – both cognitively and functionally. Here’s an example of a useful course of study:
- Learn Python. It’s incredibly easy to pick up – the programming equivalent of juggling with one ball – and very useful for writing quick and dirty scripts. There’s no reason to write an unnecessarily complicated Java program (for example) to handle something that Python can do in a couple of lines.
- Write a Mobile app. There are good tutorials out there that can take you step by step through the process of writing a mobile app for your favorite platform. Once you’ve worked your way through a number of examples, you’ll have a pretty good understanding of how the system works. You may never publish it, but writing a mobile app will demystify the process.
- Build a tool in Ruby on Rails. It doesn’t have to be pretty, and it doesn’t have to be for anyone else, but working your way through one real (if small) project will help get you up the initial learning curve. Knowing Rails can be incredibly useful, even if your company isn’t a Rails shop – I know one engineer who had a habit of throwing together tools using Rails over the weekend, many of which are still in use years later.
- Learn a Functional Language. Lisp, Scala, Clojure, OCaml, Haskell, Erlang… There are lots of choices, and more important than the specific language is to understand the underlying paradigm. Choose one, read through the tutorials, and use it for some small projects to come up to speed.
- Learn C++. This is a bigger bite than the other items, primarily because the reasons for learning it are different. Whether or not you use it professionally, understanding C++ will help you to understand how every other language works under the hood. How pointers work, why objects are more expensive than primitives, what virtual functions are and how they work, why garbage collection is important (and hard), how inheritance actually works. Every modern language does its best to hide all of these from you, but you’ll never approach your full potential unless you understand how things work at a deep level.
Get a surplus machine and install Linux
This doesn’t have to be an expensive machine – if money’s a problem, Raspberry Pi is fine (and gets you huge nerd points) – but even if you’re a .NET programmer, you need to be able to get around in Linux. Install git, a relational database (MySQL, Postgres), Hadoop, Hive, a web server, etc. Know how to use grep (but mostly use ack for quick searches) and sed. Be able to do basic bash scripting.
If you’re already a competent Linux user, don’t rest on your laurels. Build your Linux install from scratch. Learn how makefiles and ant work, find an open source project and read through its code. Fix a bug or three. Use this machine as your playground for fooling around with new technologies. Do everything from the command line.
Go deep and wide
There’s a natural tension between the desire to experience many different kinds of problems, and to get really deep into a specific problem. In most organizations it’s easiest to develop a very deep, narrow expertise, and this is good – as long as you’re also taking opportunities to expand into new areas as well. This can sometimes be a tough sell – there are a lot of interests pushing for “resources” to work as efficiently as possible by staying within their areas of expertise. The engineers are also often skeptical.
It’s the manager’s responsibility, though, to be constantly pushing engineers out of their comfort zones, and pushing back against institutional forces seeking to constrain engineers to their current areas of expertise. Likewise, it’s your responsibility as an engineer to keep seeking new technical challenges, and not to take no for an answer. It’s easy to get comfortable with a well-defined set of tasks, but anytime you feel like you’re no longer learning something new, it’s time to change gears.
With this in mind…
Swapping with other teams
Hands down, the best way to improve coding skills is to solve real-world problems in a wildly divergent problem domain. Encouraging (or even requiring) engineers to regularly transfer to different teams creates a much stronger set of developers with a broad understanding of the codebase. It also helps to reduce turnover, as the engineers are constantly moving to new challenges within the organization.
Unfortunately, it’s hard to give up a productive member of the team, even if only temporarily – especially after you’ve spent so much time getting them up to speed! It’s common for a manager to hold on to his or her engineers with a deathgrip, and to view any desire to swap as a betrayal. It’s also not unusual for engineers to get comfortable on a team and resist even short-term change, but this is slow death for a high performance culture. Pushing your engineers out of their comfort zone, even if it means trading a more experienced engineer for a newbie, will pay significant dividends in the long term.
At TripAdvisor, we have very short projects (typically on the order of 3-7 days), so it’s possible for an engineer to come up to speed and make a significant contribution in just a week or two. Two month swaps work pretty well for us, but longer project cycles would probably require longer swaps.
When you join a new company, you don’t know the code base. You don’t know the teams. You don’t know the (official and unofficial) processes. You don’t know the people. Unless you have a passion for a very specific technology or problem space, the probability that you’re going to magically join the perfect team without having first spent some time in the company getting to know the options, is going to approach 1/(number of teams) asymptotically.
Well, too bad. You were interested in technology X, and the first hiring manager you talked to was on team A, so that’s where you ended up. Of course, the company has twenty teams with open positions, and if you’d only known that there were openings on teams B, C, D, and E, you might have chosen one of those instead! Oh well, maybe in 18-24 months you can put in for a transfer if things don’t work out…
From your hiring manager’s perspective, this is ideal. They fought to get you onto their team, and now you’re locked in for the next couple of years. Profit! Unless things get so bad that you’re willing to quit, they have zero incentive to let you transfer to someone else’s team. In a highly political organization they might even have negative incentive, if another manager’s success might reduce their chances for promotion.
This is terrible for everyone – the individual, the managers, and the organization. As a company grows, teams and people specialize, and it’s harder to find engineers with a broad understanding of the entire codebase. Sure, there are a few oldtimers who were around before the specialization and seem to know everything about everything, but everyone else is working with increasingly constrained / specialized sets of knowledge. How much better would it be for the company if everyone knew how all the different areas fit together? How much better for the managers if their engineers were significantly more effective at their jobs? How much better for the engineers if they were able to develop a very broad expertise, and to have the opportunity to understand the different teams, the code, the processes, and the people before they had to make a choice about where they’d spend the next couple years of their lives?
The Web Engineering Program at TripAdvisor is specifically designed to fit this problem. New hires can choose to spend their first year on four different teams, learning about different problems, processes, and people. As they move from team to team, they bring this knowledge with them, providing benefit to their new teams. And, at the end of the year, they get to choose which teams to join (assuming there are open spots and the hiring managers agree). Sometimes, people choose different teams than originally expected (I’ve personally “lost” people who were initially planning on ending up on one of my teams, but fell in love with another team along the way) – this can be disappointing, but in aggregate creates a much stronger set of engineers working on problems they’re truly interested in.
I haven’t tried programming competitions yet, but anything that gets the creative and engineering juices flowing seems like a Good Thing™. I’m hoping to try this soon – comments and suggestions welcome!
A final word on responsibility
As a software engineer, your career is ultimately your own responsibility. Complaining that your manager isn’t giving you opportunities to learn might feel good, but ultimately it’s just victim thinking that isn’t going to help anyone. At the end of the day, you’re the one who needs to put in the work, and you’re the one who’s going to be most affected by stagnation, so if you aren’t getting a push from above, it’s time to start shoving on your own. This is also an opportunity – if no one else is organizing tech talks or book discussion groups, or getting people together for lunch to share notes on their personal Linux configs, being the one to organize it will show initiative (hey, someone’s got to do it).
Having said so, if you’re a manager then your people’s development is your responsibility – just as much as risk management, task allocation, and managing project schedules! You can’t make your team read books, or go to tech talks, or maintain their own Linux machines, but you can help to create a culture in which this, and swapping, and wide-ranging task assignments are the norm.
In case I haven’t mentioned it, I’m hiring! Please send resumes to dblumenthal at my company. Thanks!