While most people learning to code know the obvious skills they should learn like the various programming languages, using data structures and algorithms such as hash tables and selection sorts, and computer science fundamentals like learning how a computer executes code; there are many other skills that arise in a software development position that will be pivotal to learn to be successful that don’t come up in basic “learning to code” courses. In no particular order these are 9 skills that immediately came to mind when I was thinking about what has helped me achieve the best results in my current position.
- Debugging best practices for large code bases
- Source control best practices such as GIT
- Reviewing Code
- Personal Grit
- Creating logical and maintainable code
- Upfront software design
- Dealing with unknowns and changing requirements
- Software development methodologies
- Leading productive meetings
Below I will dive deeper into these topics and give examples of ways I have demonstrated these in my day to day job as a mid-level software engineer.
Debugging best practices for large code bases
- Large code bases have multiple contributors with lots of business logic that debugging can help you trace through
- Applications aren’t always console based to visualize print statements
- Debugging enables you to visualize variable states at break points
- Attaching debuggers to libraries or remote processes and stepping through code is more effective than consistently adding and removing print statements
When you are first learning to code and you have a few console based projects that are a few hundred lines it’s not too hard to insert a few prints statements and figure out what is going on in certain sections. As you grow in software development you will end up working on much larger projects with multiple contributors. The projects may be comprised of different libraries being brought into the code as a dependency or may be a micro-service which is expected to run on a virtual machine in the cloud.
With these kind of applications adding print statements may not be feasible in the development cycle as it generates churn searching through consoles and logs and adding the write lines and removing them as you are done.
These kind of applications are generally harder to hook up debugging tooling too so it’s easy to naturally gravitate towards not doing it and depending on the logging instead. However learning to do remote debugging and attaching debuggers to binaries that step through your library in certain sections will enable you to gain a deeper understanding of what data exists in memory more thoroughly then logging. Using the step through abilities of a debugger also helps you learn how code progresses through complicated logic blocks written by other developers.
I was once trying to add a new feature into the Amazon Alexa speech recognition library and wasn’t able to find my console out statements. Once a more senior engineer showed me how to connect up a debugger I learned more in a few hours of stepping through the code then I did trying to read through it and trace the methods by myself.
Source control best practices such as GIT
- Why source control
- How to work with source control
- Commiting often
- Managing merge conflicts
Have you ever written a complicated piece of code and a few days later you were adding more to this only to break everything in such a way it took you longer to remove the bad code than it did to write it in the first place? Ok well maybe you haven’t but at some point in time you likely will. Wouldn’t it be nice if you had a snapshot if this happens to be able to restore to a point you knew worked with a set of expected functionality? Source control tools such as GIT allow you to do just this. Git also allows you to save these snapshots in online repositories that are accessible by multiple developers to be able to make pull requests for, contribute code, and push back into the main production branch.
Here is my typical steps when working with code on the job.
- Clone or pull the code repository I will be working on
- Create a feature branch so that I can easily pull down new changes and separate out the functionality I am working on with clear branch naming. Keeping another branch also makes it so I can jump over to the main branch should I need to make a hotfix for some new breaking bug that is found.
- Code up functionality into the new branch
- Add the changes to the source control and commit them once they are in a good new working state. Ensure you write clear commit messages so other developers can follow exactly what this commit adds in the change log.
- Repeat step 4 for each task of the new feature so I can restore commits should anything get messy or I can post up commits into distinct code reviews to make them easier to distinguish what was added.
- Squash the commits together for the new feature after it has been reviewed and approved
- Checkout the main branch and pull the latest state
- Rebase the latest state into my branch
- Resolve any merge conflicts using an IDE or a merge tool. Often if developers are working on the same sections of a code base that Dev A may push new code into a class you are working on and don’t have between the time you pulled it and are merging the latest. The source control functionality of an IDE will highlight where this has occurred and allow you to step through each conflict to chose to keep the new change, keep your change, or keep both. You may need to make small modifications when keeping both to preserve the intended functionality.
- Merge new branch into the Main branch
- Push the code and hopefully let a continuous integration tool handle deploying it
I do the steps above at least 5 to 15 times a week and more if I am working on a feature that touches multiple code repositories.
Additionally source control is a great way to archive and track changes in a code base and see who committed what. I often use this ability of Git to look at commits done by people I perceive as excellent coders to learn how they implement new features across the organization.
- Find time to review
- Use it to learn as well as mentor
- Keep up good code quality
- Doing code reviews as a new team member
Firstly if you are working at a company that doesn’t require code reviews before adding in new functionality into production system you should try to enforce this process as it creates vastly superior code bases and engineers.
The first company I worked for was a fairly large global company but I worked on a research and development team and it didn’t require code reviews. Having worked at a company that does and doesn’t require reviews I can say with confidence and honesty that the code I produce is higher quality knowing it will be reviewed and I have learned much more in doing and receiving them.
If an engineer pushes a code review and it never gets looked at then new functionality will never be released. Also if every engineer on a team does a review of the same persons CR request than this can also lead to productivity loss and churn in revisions from conflicting feedback. Because of this you should find time to prioritize doing reviews but coordinate with the team who is doing what reviews and what are the review requirements for code to be production worthy meaning it is functional, extensible, easy to read, well commented, and contains good unit-tests coverage.
As an engineer doing a code review you can also learn new patterns and tricks from your team members that you might not have seen before since everyone on the team may be learning new and different things about software. You should also leave meaningful feedback for reviews that don’t meet the coding standard bar set by your team as well as providing suggestions to the committer from something you may have recently learned that will make their code more optimal or easier to maintain. Remember code is likely to be modified in the future so if it’s tough to follow now it will be even harder a year in the future when the person that wrote it is either gone or may have partially forgot what it does.
Also a lot of new team members generally shy away from doing code reviews because they may be timid or too unfamiliar with the code but I always suggest to them that they still try to be an active part of reviews to gain familiarity with what other people on the team are working on and to speed up their on-boarding. It also helps them to see the quality bar set by the senior members of the team.
I often use the first hour of my work day to catch up on emails as well as to go through code reviews. I used to quickly go through code reviews to unblock members and to help us stay on track for timelines but as I have grown as an engineer I’ve seen first hand where brief code reviews have resulted in code smells and limit the growth of other engineers. I now account for time to do more thorough reviews when doing our team planning and insist other team members keep up high standards in reviews.
- Keep your patience to overcome tough bugs and syntax errors
- Bigger projects come with tougher bugs and more challenges
- Learn stress management techniques to deal with challenging situations you may encounter
Have you ever found yourself getting frustrated while working on a personal project you run into some code that you can’t quite get working right or you run into compiler errors that takes 15 minutes or longer to trace back to something silly like assigning the wrong value to the wrong variable?
Well imagine you are running into this same problem on a 3000 line code base of which you are unfamiliar with and your new code is conflicting with someone’s old code that may take even longer to fix. Or you have code that worked on your development system that is doing something completely different in production because of the scale of data and you need to urgently fix some kind of bug. This could cause some serious tilt and stress for someone newer coming into this situation.
To prevent serious burnout it’s essential to learn stress management techniques as well as recognizing you may be losing patience on something and to mentally re-balance your personal state to focus and solve problems on hand to prevent time loss or worse problems in the future.
I work on my own grit by reading personal development books and through meditation or breathing exercises to be aware of my mental states.
Creating logical and maintainable code
- Small code projects aren’t maintained
- Enterprise code has a life cycle with new engineer contributing to code all the time
- Maintainable code should document itself, be easy to follow, and allow new developers to independently add features to
When working on smaller scale projects it’s common to finish the requirements of the project, see the final working product, store it in your personal portfolio somewhere such as Git and create something new. Because of this it’s easy to get into a habit early on to not think of code as something that lives, needs to be supported, and continually worked on by new developers or new teams.
Even as a newer developer working on a larger project it’s common to emphasize pushing out new features to meet timelines over breaking out code into easily testable functions, implementing SOLID objects and design patterns, and leaving thorough comments on why code is doing what it does.
I personally learned this lesson the hard way at Amazon. I ended up creating a significant internal portal that has become pivotal in how we test and deploy some of our teams artifacts. The phase 0 of this project was completed in four months by me and another junior developer without much senior guidance. We ended up meeting our timeline at the expense of maintainable code and have our team start using the portal before a lot of new Alexa devices were released. The portal release ended up saving my team a lot of manual effort. Another team member also created another web portal that would convert media into fingerprints that we could then detect coming from production devices. My manager determined these services were important enough to resource another team devoted to their continued development and growth. As a SDE1 I became the most senior member of this new team of two people after being at Amazon for 18 months and onboarded 6 more members within a couple of months. Since this code was not written in the most maintainable way for new members there was a lot of time I spent pair programming with the new team to improve the code quality and add new features. This resulted in excess time needed for both of us.
Upfront software design
- Design skew is expensive to recover from
- Software complexities and boulders should be identified before coding features
- Even a junior developer can create UML and flow charts for their tasks that will help them convert ideas into code and serve to help future developers work with those classes
It’s a known fact that a plane off course by a few degrees at the beginning of the flight will end up being off by thousands of miles hours towards the end if left uncorrected. This is also very true for software but it’s often harder to correct for any flaws in logic until much later in a project.
Because of the often difficult complexities encountered by a software project and the cost of a developers time to a company a developer should take extra care to understand the boulders a project will likely encounter as well as technologies and solutions to overcome those boulders before a single line of code is ever written. The design phase should be a document that is created laying out the goals of the project, potential solutions and pros and cons for those solutions, diagrams of the components that will be needed, high level summaries of the functionality those components will be responsible for, and estimates of how long it would likely take. This document will become the blueprint for your software and will help ensure people are working on the correct pieces in well planned way.
Even when a junior developer gets assigned a task they should still document the goal, a class design and sketch out a flow chart of how data will flow and be processed. This activity will give more insight into the problem and provide a clearer picture of what the code will achieve. The feature documentation can then be linked to in the code to help developers in the future that will be working on the class.
I go into much greater detail of the topic of software design here.
Dealing with unknowns and changing requirements
- Software projects can be disrupted mid-design from internal or political policy changes
- Use your grit to keep a level head and quickly work through changing requirements
- Identify unknowns early to create contingency plans to proactively consider changes and give accurate estimates for a project
Even the best software design is susceptible to changing requirements half way through or even after it is completed. Maybe there are new privacy concerns or government policies that come up as you are working on your current design which makes it non compliant.
If this is your teams main priority it could leave certain members without work to do while solving for a new design. To prevent this you can pre-plan contingencies and fall back items to do should your current project get blocked. You will also need grit to modify the previous design, come up with new tasks for the team, and change code to meet new requirements. The better a developers ability to adapt to such situations the less disruption that will be generated. Also having the foresight to know unknowns in software will allow a developer to come up with better tasks and provide more accurate estimates which is an extreme asset to the managers of a team.
I was once working on a software problem where the more I learned about what was needed to achieve the desired business goal the more I found it required more teams participation to solve. One of the other teams didn’t have any resources to devote to the work required and we were unable to start the project. Luckily I had several other projects in my back pocket to continue work on.
Software development methodologies
- Teams use different methods to plan and track software creation
- Take extra effort to learn your teams methodology in more detail
- If you create stories or tasks thoroughly write in the summary why this is needed, the desired outcome, and the acceptance criteria
Whether it’s Waterfall, Scrum, Kanban, or sticky notes on a board every software team uses some way to track work that needs to be done and who is working on that task. You should familiarize yourself with whatever your team uses as soon as possible to meld into your teams processes seamlessly. Spend a day researching how “Scrum” or “insert methodology” here works as well as how to lead an effective “sprint” or other terminologies your team may use.
No matter the methodology there will be some piece of work that needs to be done now or in the future. Either way be thorough when you write down the summary of what this work is and why it is needed. If this project ends up on the backlog for a period of time or some other engineer decided to do this work that isn’t the person that originally became aware of the task then a descriptive summary becomes even more important so you don’t need to remember the details and answer what the task was about later.
In my early days at Amazon I used to commonly capture ideas I had as stories in our teams backlog and only write one word sentences. Then overtime I learned changing requirements often led to these backlog stories staying there for months or even years. In this time when other members would ask about these old stories it often proved challenging to communicate why these were significant.
There have also been times where a developer would mark a story as complete when the engineer that wrote the store had something completely different in mind in terms of scope or standards. Stating these assumptions in the story will ease the situations for a growing team.
Leading productive meetings
- A software developer doesn’t only code!
- As your influence and skills grows so will your demand to organize and participate in meetings
- An effective meeting should have a desired outcome and focus on the topic of the meeting
Most software developer may spend anywhere from 4 to 20 hours a week in meetings between daily check-in,s two week planning meetings, metrics reviews, and brain-storming sessions. As your leadership grows within a company often the number of meetings you either organize or participate in increases with it and some of the times you’ll wonder why you were even pulled into that meeting to begin with.
Because of how much time is spend by employees in meetings it is very important to the business that these meetings be productive. Also as a developer you should value productive meetings because it helps clear up unknowns and allows you to be a more productive developer.
If you find yourself in a position where you need to schedule a meeting to review a design, get more insight into the way another teams software works, or many other reasons that bring up meetings follow the below subheadings to help your meeting run smoothly.
Preplan your meeting for what you want to discuss and what you want to achieve from the meeting
Try writing up an agenda on what you want to cover in the meeting and identify what you hope to get out of the meeting as goals. This can then be sent out with your meeting invite to keep everyone in sync with the goals of the meeting.
Invite the critical personal for your desired outcomes
Keep in mind if you are inviting people to a meeting that is time they will be stepping away from whatever coding or other work they may be doing. If you need help from another team on a certain piece of software it would likely be more beneficial to ask a few key members who work the closest with what you are concerned with then to invite their whole team.
Be aware of your meetings audience
I was recently in a meeting with another team where a few of the engineers on that team started going back and forth about detailed design implement for their software that I had no idea what they were talking about. I kindly asked them to take that offline and to refocus the meeting in a way more aware that several members of the meeting are unfamiliar with the exact technical details nor do they need to be informed for what the meeting was supposed to be about.
Should this meeting have had a clear agenda, objective, and moderator this side track would have been less likely to occur.
Moderate your meeting to guide discussion in a productive way
As mentioned above developers love going on tangents on potentials solutions that can side track meeting objectives. And while those conversations are likely to be productive not everyone in the room needs to be concerned with those. As the meeting leader ask them to schedule up a follow up meeting and to get refocused on the agenda item.
Send out meeting minutes and a summary of next steps with action items
While working through the meeting agenda take notes of important conversation and points that come up from the members of the meeting. Work towards identifying work and action items that need to be done to continue progress on the topics of the meeting and take note of those. At the end of the meeting address any outstanding questions and send out the meeting members to the participants. Knowing in advance you plan to send out the meeting notes will also help you keep the meeting focused on your goals and working with the members to clear up unknowns.
About Stefan Bradstreet
Stefan is a software development engineer II at Amazon with 5+ years of experience in tech. He is passionate about helping people become better coders and climbing the ranks in their careers as well as his own through continued learning of leadership techniques and software best practices.
Thank you for visiting!
Please remember if you found this content useful and would like to see more python and software development articles from us, help us conquer the google algorithm in any of the ways below:
If you didn’t find what you expected feel free to use the contact page and let us know ways we can improve or what would help you grow as a developer better! I am honored by every view and it takes a village to really make this great.