Aspiring programmers often ask a question like, "What can I learn in X amount of time that will make me a star programmer?", where X is way too little time to develop star programming skills. There are many diverse skills needed to become a truly professional programmer. It seems of late that the focus is all about learning the hottest language, knowing lots of algorithms and design patterns, and understanding the latest frameworks.
Those are all great and useful things to invest time in. However, one area that seems to receive little attention from up-and-coming programmers is developing a workflow that leads to long-term professionalism, no matter what language or framework they are using.
I like to think of myself as a Professional Software Engineer. However, nothing makes me feel more unprofessional than when I create bugs, break the build, or cause other people extra work when it could have been avoided. In software development, we can't avoid every problem, but we can avoid many of them. With plenty of unavoidable problems lurking around, there is no sense in wasting time on the ones we can avoid. I have personally caused almost every class of avoidable problem and brought upon myself plenty of well-deserved shame. Early in my career, I thought, "Hey, no big deal, nobody is perfect." Of course I would try to learn from my mistakes, but I found that I was making some of the same mistakes over and over. At one point I had a conversation with my boss in which he challenged me to do better. After some reflection, I realized that I could improve.
From that time until now, I have refined a software engineer workflow that helps me ensure I don't cause unnecessary problems and also increases the quality of the code I produce. I've also mentored and managed other programmers and tried to help them develop their own workflows. I hope that by sharing an outline of my workflow, you can develop your own workflow that will increase your value as an engineer and help you become a true professional. It's worth mentioning that while this list is fairly long, the reality is that these steps have become part of how I work. When it comes time to commit a change, most of these items have already been considered and done. However, having a formal workflow acts as a forcing function and ensures that I've done everything I intended to do before I submit my work.
1. Does it compile?
This may seem like a stupid thing to have in my workflow, but trust me, it's not. I've seen even extremely simple changes (my own and other people's) cause a build to fail and cause work to grind to a halt until fixed. You bring shame on yourself and your family if you break the master build because you failed to compile your changes before committing. You may begin to notice sideways glances as your colleagues pass you in the lunchroom--you’ll know why. You may say to yourself, “It’s just a minor change to fix a teeny tiny defect found in a code review, so I don’t have to worry about compiling, right?” WRONG! Don't be tempted to commit without compiling. If you are working in a language that isn't compiled, then load the updated code and make sure that the parser is happy.
2. Have I stepped through my changes?
Again, this may seem simple and obvious, but you'd be surprised how many times programmers skip this step and problems are found later on that would not have been overlooked if the code had been stepped through with the programmer watching. There may be exceptional cases when you can't step through your change, but keep these to exceptions and don't make excuses. You probably won't be able to step through every nook and cranny of your code, but you can step through the common code flows and make sure that the code is working the way you thought it would. If you are tempted not to take the time to do this, you will probably have an inordinate amount of bugs crop up later. Bugs that are found later are harder to fix because you are not as fresh with the code and you'll have to take time to re-immerse yourself. You may even find that other people have worked around your bugs, not understanding what the real problem is. Unwinding layers of workarounds once the code is fixed can be more complex than fixing the broken code would have been in the first place. It's worth taking the time to step through your code.
3. Have I run the automated tests?
You have automated tests... don't you? If you don't have automated tests, you should seriously think about implementing some. Start small, and add gradually. Automated tests can save you a lot of time in the long run and at least ensure that when you make changes, you haven't broken some base level of functionality. There is plenty of information available about automated testing--if you don’t know how to do it, take the time to learn. Bottom line: if you have automated tests available to you, take advantage of them by running them before you commit. It will save you time in the long run, save you from having egg on your face if you've broken something, and make you appear more professional to your colleagues. Of course, if you find a problem as a result of running your automated tests, don't overlook it--fix it before you continue with the workflow.
4. Have I created unit tests for my new code?
This one dovetails closely with the previous and probably doesn't need much additional explanation. If you are using a test-driven development approach, you will have done this as a matter of course. In any case, when you figure out what your own workflow should be, don't neglect to include creating unit tests. This will add some upfront time, and yes, it'll take longer initially, but it will pay dividends in the long run, especially if you and everyone else run them before committing. Your code will be more robust from the get-go, and in the future, many bugs will be found and fixed before they are committed -- which means no one will have to be slowed down by having to find a bug, figure out how to reproduce it, log it, figure out who to assign it to, etc.
5. Have I considered all "platforms" my change will affect?
If you work in a shop where you have exactly one target platform, then you can skip this step. However, for a large portion of programmers, there are multiple platforms involved. The platforms might be different web browsers, different operating systems, or different types of hardware. If you are in this situation, it's worth spending a moment to consider if your change could cause a problem on a different platform than the one you are developing on. In many cases, it won't and you can move on quickly, but by giving some thought before committing, you may detect problems and save yourself and others some hassle. A few things to think about are memory availability, CPU speed, and API differences. You probably already know which of these is likely to affect you in your job--just formalize your process a bit and make sure that you think about these things every time you commit. Also, you may want to take some time to research the differences between your various target platforms so you can be better informed. The more you know about your platforms, the more you can take this into account as you code. This will be an easy checkbox to mark off as you ready yourself to commit.
6. Have I removed any debug code or settings I have added?
This one bites me all the time. Oftentimes while I'm working, I'll add debug code or change some hard-coded setting that is intended only to help me troubleshoot or test my changes. Of course, I do not intend to commit these changes, but I've done it many times. I've found that if I mark these types of changes clearly when I add them, then I can find and remove them more easily. Typically I'll add a comment like "//DEBUG" in any area I need to clean up before I commit, and then it's easy to find and clear out any residual debugging code that should not be committed.
7. Have I considered the scope of my changes fully?
This is important especially if you are operating in code that you are less familiar with. A fairly common occurrence for me is to narrow in on a bug in unfamiliar code and figure out a small change that will fix it, make the change, test that the bug is fixed, and then commit (of course only after following all the other steps in my workflow). The problem that can arise is that even a small change can cause big problems, especially in unfamiliar code. It's a good practice to take a step back and look at the bigger picture. You may find that the code you are changing is used in a wider variety of ways than you knew about. From there you can decide whether you know enough to continue or if you need to get additional eyes on the change before you commit.
8. Are my changes robust?
Take a moment to consider what conditions could cause your code to fail. Does it make sense to validate parameters? Are there any security concerns? What corner cases are you not handling? Address those before committing. There is an art to knowing how much "robustness" to add to a piece of code. If you are unsure if it's worth spending more time to make your code more robust, you may want to seek advice from other engineers you respect. Over time you'll develop an intuition to know how far to take it.
9. Have I had my changes code reviewed?
Get someone else to review your changes and make sure the changes look correct. Find the best person you can. The best person is someone who is familiar with the area you are changing and understands the type of code you are writing. By doing this, you'll likely find things that you didn't think of, even if you are rigorous about following all the other steps in your workflow. Also, you'll probably learn new things and thus become a better engineer as a result.
10. Have I considered QA?
Hopefully your QA process is integrated with your development process and your testers are always aware of new things that are going into your application. If not, it may be worth looping in a QA person to alert them to the changes you've made and to discuss when they'll be available to test and how to go about testing. If possible, you may even want to have a QA person give your new feature a trial run before committing it. You'll likely get good feedback and will probably discover something you should fix before committing. Inexperienced programmers tend to harbor enmity towards QA. Professional programmers realize the value of QA and take advantage of the help they can lend to the development process. As you visit each step, if you end up making further code changes to address issues that come up, don't forget to go back and reconsider whether it’s appropriate to revisit previous steps. Revisiting the steps a second or third time as necessary will help you make sure that what you finally commit is as high quality as possible. Don’t be discouraged if you need to do this. Second and third passes are usually a lot quicker than your first pass through the workflow. You'll get better at it in time, and you'll internalize these steps into your coding process, which will make the commit workflow smoother and quicker.
This blog post serves as a reminder to my current and future self as much as it is meant to help you, the reader. I often find myself in situations where I feel driven to act quickly to complete an assignment. My experience tells me that when I rush through and skip steps, it often comes back to haunt me. Whatever language or framework you are using, no matter how many algorithms and design patterns you know, having a formal workflow will help you be recognized for your code quality and professionalism and will help you advance in your career.