14 Things Every Software Engineer Should Know
In no particular order -
- Common Design Patterns – Design patterns are tools to let us solve common problems. Knowing your design patterns can make the solution to a problem easy.
- At Least One Assembly Language – One can program quite well without this, but when it comes time to debug something for which the source isn’t available or when it comes time to create a new language or when it comes time to optimize to the metal, you will have a good understanding of what does the heavy lifting. It also is vital in understanding common calling conventions and why they are the way they are.
- Basic Set Theory/Boolean Algebra – there are so many problems that come up that are easily solvable through set modeling or can be simplified with judicious application of DeMorgan’s Laws. It will, at least, clean up your if-statements.
- At Least One Bit Banging Trick – My favorite two are removing the leftmost bit (x &= (x-1);) and value swapping without a temp (x ^= y; y ^= x; x ^= y;). Some of these little hacks, while they may drop readability, can be used to shed cycles in tight loops or simplify code paths. Here is a handy list of some.
- Physical Self Awareness – Are you in software for the long haul? If so, you should know your body and know the things that happen to it under stress. I’m the worst offender in this category – to the point where a former coworker suggested that maybe I should stop taking my vacations in the hospital.
- Functional Programming Techniques – While I do not believe that mainstream coding is ready for functional programming, I do believe there is a lot to be learned from the techniques of functional programming. I also believe that exposure to non-mainstream thinking and reasoning provides intangible and tangible benefits to your mainstream work.
- How People Communicate/Argue – Much as we sometimes like to hide from social interaction, one of the most valuable skills is the ability to communicate ideas with your peers. It allows you to spread your workload to others and to get the sense of “many hands, one voice” across your codebase. In addition, you will be required at some point to defend your ideas. Learn how to argue constructively – part of this should include understanding Aristotle’s Appeals, and Logical Fallacies.
- Functional Models of Your Tools – Knowing your tools means knowing how you can use and potentially misuse them to the greatest benefit or detriment. Do you know all the stages that a C compiler goes through to generate your executable? If you don’t then you might miss out on how to use the preprocessor on its own for other purposes or how to inject extra code into your own code stream.
- How and When to Implement a Language – one of the sexiest jobs in software engineering is the ability to create a new programming language that (a) works and (b) solves a problem for you in a way that would be painful otherwise. It is a wonderful sageful state of metacircularity to be able to create a program for the creation of new programs. It can also be one of the greatest wastes of time when other (better) tools probably already exist for your problem.
- How Pointers Really Work – I’ve always thought that pointers were a very, very simple concept – then again, I more or less started with an assembly language, so pointers were fundamental. One of the scariest things I’ve seen is code written by someone who doesn’t understand pointers. I’ve seen code that shotguns the heap, the stack, returns pointers to local variables, and so on. I believe all of the heinousness was due to a basic ignorance of pointers and memory.
- Algorithmic Analysis – This is one of the fundamental tools of assessing the performance of your code. Understanding how to do this will also help set your expectations for how code should perform. I have seen a version of string comparison that took factorial time. Yikes.
- When to Design Beyond the Horizon – I have had the pleasure of using a number of systems that were way stronger than they needed to be – but for very good reason. I hold the PostScript language up as a model of this. While not a perfect language/runtime by any means, its imaging and operational models made it far simpler to get consistent, high quality print across an array of different devices. This was because of the strength of its design – which in 1984 was barely implementable in an affordable way, but it has held the test of time and it is telling that it quickly because the standard for printing and publishing.
- Fundamental Understanding of Human Anatomy – most of the work that is done on computers is made to interface with people. Without understanding how people work (or don’t), how can you expect to build useful tools? 5-8% of the men using your software won’t be able to tell red from green. Are you using these colors to indicate success/failure? What is the best frame rate for a game? Why do IR remotes use a 40KHz carrier? Why are icons alone a bad solution? Why do menu bars work best when glued to an edge of a screen? What is muscle memory and how does it affect user experience in dynamic UI?
- State Machinery – state machines are one of the most beautiful models of computation. No, they can’t solve all computability problems as they are not Turing complete on their own, but they are one of the few models that spans the domain of math to transistors and loses little in the process. One of the defining moments for me in studying computer science was the realization that there is a straight forward transformation from a state machine diagram to hardware. That is glorious.
Bonus items: know the difference between lose and loose, your and you’re, its and it’s.