How to grow as a software engineer
Tags: career, beginners
Published: 2022-03-28 22:04:00

In this blog I share some advice on how to grow as a software engineer that I have collected through my own experiences, reading and observations.

In the space of about 17 years I have personally grown from not knowing programming at all to being a Principal Engineer at Atlassian. I have built some cool things I am proud of and I have worked with some amazing people. I have been involved in mentoring, interviewing and promotions, and I have some practice in thinking about how to guide, level and grow engineers.

This blog is targeted at people who are entering into the software industry. The content of this blog was originally given as a presentation to University students. I cover a fair amount of ground in a relatively short period of time. I hope that my words can carry you into deeper thought and exploration.

Giving general advice is a difficult exercise as few things are universally true. I acknowledge my advice is likely shaped by my privilege as a white native english speaking male (hard to escape my own bias).

## Summary

In order to grow as a software engineer, there are three parallel and overlapping areas that you will want to improve in:

1. 👩‍💻 Technical proficiency
2. 👀 Contextual awareness
3. ✍️ Communication skills

In addition to talking about these areas, I will also give some general pointers:

1. You are worth more than your outputs
2. Be kind to yourself
3. Adopt a learners mindset
4. Dangerous accelerant: side projects

Let's do this.

## Area 1: 👩‍💻 Technical proficiency

> How well do you know the programming language(s) and technologies that you are working with?

### Master the fundamentals

The foundation of your value as a software engineer is technical proficiency. You want to pursue an ever increasing understanding and familiarity with the programming language(s) and technologies that you work with day to day. A strong technical proficiency will allow you to craft robust, clean, valuable and creative solutions.

You will want to get a good grip on:

- Foundational language building blocks, such as: variables, loops, functions, conditions, type systems, type coercion, classes, objects, collections, input and output and so on.
- Language grammar and semantics (don't shy away from the hard parts - even if you don't use them right away, you might encounter them or find use for them at some point)
- Scoping rules (what things can be accessed when, and by what)
- Error handling
- Code reuse and sharing patterns
- Asynchronous behaviour

There are _so many ways_ you can grow in technical proficiency, and I don't think there is any one _right_ way. Find some option(s) that you find interesting and motivating.

Here are some ideas for how you can grow your technical proficiency:

- Read technical books
- Read industry newsletters
- Watch courses
- Attend meetups
- Attend conferences
- Read blogs
- Listen to podcasts
- Create your own side project (more on side projects later!)
- Get involved in open source (make your own project, contribute to another, read the source another)
- Experiment, fiddle! Find a way for you to run cheap little experiments to validate behaviour and try things out
- Seek understanding of why something does not work (or does work)
- Find (safe) people and learning communities you can ask questions to (eg twitter, reddit)
- Share your learning with others (blogs, meetups, book clubs)

My memory is pretty terrible, and knowledge that I don't use regularly tends to fade. I think that is a pretty common experience. So what I do is learn where I can find good information on particular topics, even if I cannot remember all the specifics about the topic.

> "Get the fundamentals down and the level of everything you do will rise" - Michael Jordan

### Ask questions about your code

Over time, you should get comfortable asking deeper questions of your code. Knowing how to gather good answers to the following questions will increase your impact and effectiveness:

- How confident am I that my code is behaving how I expect? (**types, testing, language familiarity**)
- How do I go about troubleshooting problems in my code? (**debugging**)

_Tip from [@AndaristRake](https://twitter.com/AndaristRake): logging is great for debugging (eg with `console.log()`), but learning to leverage a proper debugger can power you up quite a bit_

- How do I know if my code is working in production? (**monitoring**)
- How many people are using my code and how are they using it? (**analytics**)
- How can I use a server to do actions for me: tests, linting, releasing and so on? (**continious integration**)
- What are the performance characteristics of my code? (**profiling, benchmarking**)
- How do people learn how to use my code successfully? (**documentation**)
- How can people of differing abilities interact with the software I make? (**accessibility**)
- How can I (safely?) evolve my system over time? (**migrations, evolutions**)

_Not all questions will apply to every language / stack, but you will get the broad idea_

### Understanding and balancing tradeoffs

There is rarely a perfect solution to any problem in computer science. As software engineers, we are always balancing tradeoffs. Over time you will want to become familiar with identifying and balancing the benefits and drawbacks of solutions.

You will grow in your understanding relevant tradeoffs by:

- Compare answers to [↑ See: _Ask questions about your code_]
- [↓ See: _Bare the consequences of your choices_]

> Weighing tradeoffs often involves considering many non-technical considerations as well [See: ↓ _Area 2: Contextual awareness_].

### Explore popular industry solutions

For your programming language, are there popular libraries or frameworks for solving common problems? Give them a go! See how they feel to you. Try to gain an understanding of the solutions benefits and drawbacks.

### Bare the consequences of your choices

When we create code, it will generally go through a number of high level phases:

- Creation
- Iteration and long term ownership
- Deletion

Ideally, you want to try to get experience with the entire lifecycle. You won't know how particular choices pan out straight away. Often it takes extended periods of time, multiple consumers, changing requirements and so on, to expose the true benefits and drawbacks of various technical choices. You can then feed these learnings into future decisions.

### Version control

In order to successfully collaborate with other engineers, you will need to have a working knowledge of a version control tool: `git`. At this point I wouldn't recommend you learn alternative version control systems unless you need to. A _working knowledge_ of `git` is a good mental model as well as familiarity with the basic commands. `git` is also a gateway getting a server to automatically perform actions on your code (test, lint, deploy and so on).

Thankfully, there are lots of fantastic `git` learning materials which a light Google search will reveal.

## Area 2: 👀 Contextual awareness

Your (beautiful) code does not exist in a vacuum. You will be more effective the more you can appreciate the multiple wider contexts that your efforts fall into.

### Technical context

> Gain a good _general_ 'full stack' understanding

For many engineers, you will be working on applications that span multiple layers of technologies. If you work in one of those environments, it is fantastic to gain a working understanding of all of the layers in that stack. Understanding more about the requirements, features, constraints, strengths and weaknesses of various layers in the stack you work in will help you to create solutions (or pieces of solutions) that plays into the strengths of various layers.

I am not advocating that you need to become a 'full stack engineer', rather, that you have 'full stack appreciation'.

### Team context

Growing as an engineer also means helping the other people around you be successful too. Being a lone star on a project is not a healthy long term model for any project. Helping other people be successful has a multiplication effect for your project. What are the tools, processes and systems that can help your teammates be successful?

> "We rise by lifting others" ― Robert Ingersoll

### Business context

Having an understanding of the business (or project) you work for, and it's goals will help you align your efforts and advocacy. I have seen many initiatives and creative solutions be adopted because the driver of the solution understood the business goals and needs. You can burn time trying to redirect a business (or project) in a direction that _you think_ is great, but doesn't line up well with it's goals. There is a time and a place for encouraging redirections - but it is helpful to know when you are pushing with or against the currently planned destination.

### Industry context

While software engineering and problem domain foundations don't really change all that often, there is a constant evolution of ideas and offerings.

There can be benefits in observing larger industry trends:

- Exposure to new techniques, projects and tools
- Sanity check your ideas against existing solutions
- Identity market opportunities

How can you keen up to date with industry trends? Similar methods to how you can grow in your technical proficiency:

- Read industry newsletters
- Watch courses
- Attend meetups
- Attend conferences
- Read blogs
- Listen to podcasts
- Join learning communities

## Area 3: ✍️ Communication skills

The reality of creating software is that you will be communicating (a lot) with other people. Regardless of whether you are a solo open source developer or an employee at a mega software corp - communicating well with others is critical to your effectiveness.

I can almost feel some people cringe as they read this. You might be thinking:

> "I just want to write code! I didn't go into software to become a people person!"

I can empathise with this. I am not advocating you need to become a highly articulate and eloquent socialite - rather, that you grow into being able to share clear and helpful information with other people. That doesn't sound too bad - does it?

Good communication leads to increased alignment and clarity, so that you, and the people you interact with, can focus on constructive things. Poor communication leads to a lot of friction, frustration and wasted effort for you, your teammates, your organisation and your users.

### Code authoring

The code we write is just as much for communicating with your future self, and for other people, as it is for the machine to execute. Being able to have clear ways of communicating your intention and rationales in your code is essential for code that needs live more than a few weeks. Writing code that is easy to follow is a strong signal of engineering seniority as it demonstrates the understanding that code will need to be well understood by someone that lacks context at a later date.

Some general tips:

- Optimise for readability (this covers a lot of things)
- Avoid 'magic one liners'.
- If you _really_ need hard to read code, hide it behind a nice API
- Use comments when you think something requires additional information that is not apparent looking at the code itself
- Types (and their names) can be a great way to communicate extra information
- Prefer explicit behaviour rather than implicit
- Only enforce style preferences that are backed by automatic tooling

### Code reviews

Reviewing code (often through a 'pull request') is a common industry practice to help ensure software quality. There is so much to say about pull requests - you will find heaps of tips after a light Google search.

Pull requests are communication intensive. When you are creating a pull request, or reviewing it, you want to aim to be as clear as you can and who needs to do what. Pursing clarity in pull requests will lead to higher quality changes and for potential changes to be accepted / rejected faster.

### Persuasion

Other people will need to make decisions based on information that you provide them. Here are some questions people might approach you, or your outputs with:

- Which solution should we adopt?
- Why should we invest in your idea?
- Why should I buy your product?
- Why should I adopt your open source project?
- Why should I hire you?

Using established persuasive communication techniques can help make connections between a need and a solution clear and straightfoward.

Persuasive communication is a skill that can be learned and improved. I personally was exposed to formal persuasive communication through a law degree (that I otherwise do not use much now). But a small Google search will reveal a number of blogs and courses on how you can learn and improve at persuasive communication.

For me, persuasive communication is not about tricking people, but about making your proposed value propositions clear and easy to follow. Doing this well will help others buy in or opt out more quickly, and for the right reasons.

## General pointers

I have shared three general areas for you to focus on improving in order to grow as an software engineer. Here is a collection of other thoughts that you might also find helpful.

### Pointer 1: You are worth more than your outputs

My limited and subjective experience is that if you choose to define your self worth based on your outputs you will never be truly satisfied. Your self worth will rise and fall in proximity to your most recent success. I strongly believe the all human beings have dignity and worth is not tied to their outputs. Try to find a way to derive your sence of self worth from something other than your outputs. I am deeply and painfully aware this is no easy task, but I have found increasing joy in trying to decouple my self worth from my outputs.

### Pointer 2: Be kind to yourself

You could spend all your time and effort becoming a great software engineer, and you would probably become one. Being good at your craft is awesome, but I think there is also so much more of the human experience for you to enjoy. If you work in software engineering, you will likely have many decades of working ahead of you. It's okay to take your time and enjoy the journey.

### Pointer 3: Adopt a learners mindset

A great way to encourage your long term growth is to adopt a position where knowledge is not secret, but learnable (and forgettable!)

Some tips:

- Ask lots of questions
- Be okay with saying "I don't know" (espeically as you get more senior - it is license for more junior folks)
- Find ways that let you answer questions on your own quickly
- Be open to changing your mind on things. _Try_ not to emotionally invest in technical positions because it can make it harder to change your mind when you should
- Challenge existing ideas
- It is okay to forget things (even basic things). It is very human. Be open about calling out that you don't remember something.

### Pointer 4: Dangerous accelerant: side projects

I have a love hate relationship with side projects.

Side projects could be things like:

- Creating an open source library
- Contributing to an open source library
- Making your own product
- Making your own game
- Creating digital art
- Soo many more things (I don't want to limit you!)

Side projects often put you in the drivers seat of a project and let you leverage your personal time to have more agency to execute on creative / risky things often with little consequences. Side projects are a powerful vehicle of personal growth on many vectors. However, they are a _dangerous accelerant_. It is easy to soak up significant amounts of your time with side projects. Speaking from painful personal experience - side projects can cost you more than were expecting to pay. Should you do a side project if you have the opportunity and inclination? For sure! But be careful.

- [More reflections of mine on side projects](https://egghead.io/podcasts/alex-reardon-on-balancing-work-life-and-large-side-projects)

## Thanks

I hope you find the advice I have shared helpful. Thanks to the people who helped review and give feedback on this blog.

You can follow me on twitter at [@alexandereardon](https://twitter.com/alexandereardon)

Cheers