Behind every successful career is a dream that got left behind. For me, that dream was software engineering.
The journey is far from over, but I’m proud to say that the transition has been a success. After 3 months at Hack Reactor, many late nights creating personal and open-source projects, and the stressful job search, I’m now positioned in my first full-time engineering job (at Coinbase). Finally, I get to spend every day doing what I love.
In this post I’ll share what that experience of switching careers was like and the lessons I’ve learned along the way. I’ll tackle questions like: Was it worth it? Was programming what you thought it would be? What’s your secret to learning so quickly? How hard is it to get a job as a software engineer? What’s next?
Let’s start from the beginning.
My primary goal when I started coding was to learn enough to “go pro” as quickly as possible. If you recall, I loved the thrill of building things and became obsessed with solving programming challenges. Long story short, I wanted to be a creator. And I wanted “it” so badly that I didn’t have the patience to go back to college to get a CS degree.
Was I nervous? Of course. But I was lucky to have friends and colleagues who believed in my dream and helped me keep my love of programming alive.
I remember meeting with Christopher Nguyen when I was just beginning this journey. Christopher is the founder of Arimo, a Stanford PhD who co-founded two enterprise startups with successful exits, and one of the smartest founders I’ve met at a16z. Specifically, I wanted to ask him what he thought my chances of success were, considering so many other programmers have been doing it since they were 12 years old.
He replied, “What I see in you is that you have grit and passion. If you truly put forth the effort and the hours, their competitive advantage will soon fade.”
Those words, especially since they were coming from a successful academic who I thought would frown on my decision not to go back to school, were incredibly encouraging. It made me realize that there was nothing to “disqualify me” from reaching my dreams. All I had to do was work hard and make it happen.
So I cracked open the Terminal and started learning.
Learning the Trait
People often ask how I managed to learn so quickly. The answer is actually simple: I coded every minute I had.
Since leaving Andreessen Horowitz, my schedule pretty much went like this:
The more I coded, the better I got, which made me want to code more. I was caught in a virtuous cycle, and I loved every minute of it.
However, committing this much time to coding meant that I had to give up a lot of things — including some of my favorite hobbies like reading, meeting up with friends on weekends, Napa trips, dinner outings, and even visiting my family for Thanksgiving and Christmas.
It wasn’t easy, but to be completely honest, it wasn’t a deal-breaker either — I was so passionate and engaged in what I was doing that giving up these things in the short term didn’t feel like a big deal.
But what specifically was I working on? Here are some specifics about how I structured my learning:
Step 1: Learn the Fundamentals
Notice how I didn’t mention Angular, React, jQuery, Webpack or any popular framework, library, or tool. There’s a good reason for that: the importance of avoiding learning popular tools when you’re just starting out.
Step 2: Build side projects
After a couple months focusing on the fundamentals, it was time to step up and start building projects from scratch.
Building real-world projects drives home your fundamental learning in ways you’d never imagine. Plus, small projects nurture your connection to the programming community. The projects I took on weren’t meant to be my next company or the next Facebook, but instead were ambitious, meaningful projects that tackled small problems I cared about.
My thesis project at Hack Reactor is a good example. My teammates and I chose to build an open-source library that makes building d3.js charts much simpler. At the time, this felt like it was way beyond the scope of our abilities. Building an open-source library sounded like a task for the wizards. However, we figured we might as well work on something that’s hard — something that pushes us beyond our limits. And I’m proud to say that we did one hell of a job on it!
Beyond deepening your technical skills, project-based learning also teaches a variety of high-level skills:
- How to design the right architecture
- How to pick the most appropriate tools to work with
- How to write code that is easy to read and maintain
- How to build a robust and thorough test suite
- How to build a great user experience
- … and much more
Step 3: Continuous Learning
You can’t code 24 hours a day, but you can fill the in-between time with meaningful content even when you aren’t at your laptop. (Chances are that’s why you’re reading this post right now!) Any “down time” in the past year I wasn’t coding was spent consuming programming books, video lectures, and podcasts.
Overall, getting a mix of theoretical concepts combined with practical project building experience was essential to learning effectively.
Step 4: Embrace the struggle
In short, code became my life, which helped me progress much faster than learners committing less than 110%.
Of course, this doesn’t mean that I breezed through it and that everything came easy to me. (I don’t think I’ve ever met a programmer who’s felt that way.) There were many times when I felt overwhelmed — whether it was because I couldn’t grok an advanced topic or I was stuck on an annoying bug or I couldn’t get something to work.
Getting stuck is only a problem if you give up. Instead, I learned to harden up and keep pushing forward until I saw the light at the end of the tunnel. Fighting through those frustrating moments requires us, programmers, to be diligent, resilient, and patient.
There’s no such thing as a programmer who doesn’t struggle sometimes. After all, if software engineering was easy, everyone would be doing it. Successful engineers learn to treat struggle as a chance to learn something new.
Becoming a Professional Software Engineer
One of the hardest engineering skills to learn has the least to do with computers: teamwork.
Coding simply to satisfy your intellectual curiosity and desire to build is radically different from coding on a team to solve group objectives. You can learn and build all the side projects in the world but still not be a great professional software engineer. Working with a team of engineers to build and maintain a product in production is an entirely different world.
My personal goal was to become a full-time software engineer, and so as next steps, I focused on gaining the skills required to do engineering in a professional setting. Specifically, I wanted to get more experience collaborating with other engineers to build something.
Luckily, a part of Hack Reactor’s program did just this, and I got to work on three separate group projects over the span of 6 weeks, each of which we took from idea to fully-deployed product. Along the way, we learned things like:
- How to design a spec as a group
- How to discuss varying points of view
- How to manage git workflow
- How to practice agile software development
- How to agree on the right tools to use
- How to manage team conflicts and dissimilar personalities
…Basically, we learned everything that matters outside the code itself.
First professional job
Right after graduating Hack Reactor, I got an incredible opportunity to spend a month working on a highly technical project for a brilliant open-source developer. It was the hardest project I had ever tackled up until that point and one that truly deepened my knowledge of computer engineering fundamentals, down to bits and bytes.
There were days on this project where the challenges I faced made me feel frustrated and upset. It often got so challenging that I wanted to throw up my hands and declare one coding challenge or another “impossible.”
At times like this, giving up was all too easy. I had to keep reminding myself that the only way I’d gotten this far was by pushing forward and fighting the negative feelings. So, I would take a deep breath, step back, and give the code room to breathe. Then I’d ask myself questions like:
- Am I trying to solve the right problem, or have I been side tracked into solving a tangential problem?
- What are my constraints? What do I know about this problem? Is my interpretation of the problem valid?
- Is my current approach harder than it needs to be? Can I find an easier way?
- What can I find on the interwebs that would help me with this problem?
- Is there someone or somewhere I can ask for help?
In the end, every problem ended in a solution. It’s through experiences like these that I realized there’s nothing you can’t figure out with effort — including the “seemingly impossible” tasks.
The reason this gig was so valuable to my development was because it gave me a taste for what it’s like to work for and with someone else in a real-world setting to build and deploy products. It taught me how to take someone’s idea, break it down into its small executable pieces, execute on them, and hand the final product back to them.
While the project was an amazing experience and I could have continued to look for other contracting opportunities, I realized that contracting wasn’t what I wanted to do long term. I got an amazing opportunity to work on something technically challenging and it was great while it lasted, but what I really wanted was a full-time role where I could collaborate with like-minded people to solve a problem we all deeply care about. I wanted peers that I could code with and learn from long-term. More than anything, I wanted to contribute to a company that I believed was building something valuable and important.
This is when I started my job search.
The Job search
The engineering job market is a huge topic. I can’t offer any revolutionary solutions in this post, but I’m definitely thinking on it for future writing. For now, I’d just like to distill some of the main lessons I learned:
Rejection != You are terrible
When I was getting started, I thought that if you were good enough, you could swing a homerun every time. That delusion was quickly dashed. It’s difficult to ace every programming interview. Even some incredibly talented developers I know said they’ve gotten rejections because they messed up an algorithms question or got nervous or whatever the silly reason. In fact, there’s even a “They rejected us” list (http://rejected.us/) of developers that I look up to everyday who share their stories on rejection.
None the less, rejection is always disappointing, whether it’s because of our own shortcomings, or simply factors beyond our control.
For example, one factor that surprised me is the breadth of questions you get asked in interviews. In one interview, the interviewer focused on CSS selectors for the entire hour. To be completely frank, I know how CSS selectors work and I use them in my stylesheets, but I didn’t know them to the extent that I could get grilled on complex CSS selector scenarios and their implementation details for an hour.
I probably could have prepared for this but I was focused on learning other things, and so I got unlucky. It’s frustrating, but predicting where a particular interviewer will focus their technical questions isn’t always possible.
Discovering your weaknesses
In this way, there are some companies that do a really good job of testing for strengths, where you have all the liberty to show off what you’re good at. There are others who are really good at pinpointing your weaknesses. When you’re tested on your weaknesses or tested on things you just don’t know yet, you’ll stumble and fall.
Another factor is how good your interviewer is. Some are well trained, extremely friendly, and do a great job of making you feel comfortable and at ease. They realized that interviews are stressful and so they try their best to make the experience less daunting. Others are untrained, inexperienced, distracted or unengaged. Maybe they even give off strange body language or make weird eye contact — simply put, they are not very good at putting you in a comfortable state so that you can do your best. Obviously this can have an impact on your performance. Obviously, this is not your fault.
Yet another factor is culture fit. I’ve met with many founders and engineering managers who said they’ve rejected strong candidates purely because of culture fit.
“Culture fit” is a vague word, but the point is that most companies and managers are looking to hire not just a strong individual who can code, but also someone who will be a great fit with the rest of the team — someone who will contribute positively to overall productivity. Good managers and companies know that a developer who fits into a unanimous team that has trust and respect for one another is better than a 10x developer who doesn’t share the same cultural values.
Something like this might be totally out of your hands — you are who you are. So if you aren’t a good culture fit for a company, go find one that you are a better fit with.
Don’t blame yourself
The list goes on. These are just some of the many other reasons why it’s nearly impossible to do well in every interview. And that’s okay — don’t get discouraged, don’t call yourself dumb, and don’t blame yourself.
That said, don’t completely dismiss it either. Instead, be open-minded and use each opportunity as a learning experience. Analyze what you did well and what you what you didn’t do so well. Moments like this are a testament to how much you believe in yourself, and how much you want it. Again, some of the best programmers I look up to have gotten rejections from many companies, but that didn’t stop them.
So pick yourself back up and keep running.
Learn your algorithms and data structures
The question of using algorithms and data structures to determine the quality of a programmer is one of the most controversial topics in software engineering.
My general take is that while algorithms and data structures might not be something you use every day as a web developer, they still demonstrate things like your ability to think logically, ability to communicate your thought process, ability to go from a brute force suboptimal solution to a well thought out optimal solution, ability to think on your feet, and so on.
Rather than going into a lengthy debate on this topic, I’ll leave it by simply saying: Study your algorithms and data structures. Yes, there are some companies who have put in place more practical interview processes, but unfortunately, a majority of companies still use the old school approach. This is true even if you’re only going to be interviewing for younger startups.
Final Common Sense Tips
- Be a nice person during your interviews. You’ll be surprised how far it gets you. Interviewers are not only looking for technical skills, but also for people who they would enjoy working with.
- Be confident in your skills. You might not know everything there is to know about programming, but know what you’re good at, the value you provide, and act in a way that conveys your value to others. Show that you believe in your ability to contribute.
- Be genuinely interested in the problem the company you’re interviewing with is solving. Ask thought-provoking questions about the business, the team, the future of the engineering organization and the problems they are excited to tackle. Show that you care (and if you don’t care, then don’t apply to that company).
- Get warm intros if you can (preferably from someone who the company knows well and trusts).
- Don’t settle for your first offer (unless it’s your dream offer). Push yourself to get more. Searching for a job only happens once every 2–5 years, but the consequence of that process has an effect on your life every day — so put the work into it now to get a job you’re excited about.
Who knows. You might just end up finding your dream job.
Phew. Now that I’m a full-time engineer at Coinbase and absolutely stoked about it, what’s next? Is this it?
Absolutely not. I have so much more I want to learn and so much I want to tackle. Programming can provide a lifetime of interest, even before you peek under the hood at all the other exciting disciplines open to software engineers.
Here are some of the ways I plan to continue educating myself:
- Follow the conversations happening around my favorite open-source projects. Then, when I feel comfortable, get actively involved and contribute.
- Continue to grow my professional network — through Twitter, open-source, meet ups, etc. — and then grow from my network. There are lots of phenomenal developers out there who are willing to help and mentor. I want to meet them and learn from them.
- Teach others through blog posts and presentations at conferences and local meetups.
- Seek out technical and non-technical mentors and have regular conversations with them. Ask for their advice. Use their past experience to inform my future decisions.
- Read programming books and take online computer science courses in my spare time
- Most importantly, never let myself get comfortable.
There were a lot of moving parts in my transition. It hasn’t been easy.
However, there hasn’t been a single day that I regretted it. In fact, as each day passes, I feel more confident that this is exactly what I needed.
Having the skills to build is the freedom I was seeking. Christopher Nguyen was right, when he told me grit was more important than experience. If you believe in your dreams and you’re willing to put in the late nights and hard work, you can do anything :)