The 5 Most Important Things Programmers Should Know (but never learn in school)

Over the years of leading software engineering teams, I have had the opportunity to interview students from a number of schools and at a variety of levels of education from associates degree up to PhD.  The one commonality I have found is that all of these students lack the essential knowledge of 5 topics that should be at the top of their academic curriculum.

It dumbfounds me that these topics are not taught in school.  I have mentioned it to numerous individuals over the years and have finally decided to list the items here so students and teachers alike learn what we employers want to see students carry with them along with that college degree.

And if you are reading this before interviewing with my company, read further for insight on what you need to know during that first interview.

1. Source Control

"If everyone is moving forward together, then success takes care of itself." -- Henry Ford

Over the years I have taught many developers (who wanted to become software engineers) about what source control is and how to use if effectively.  Each time I do, the response is something to the effect of "I can't believe I never used source control before" or "I will never program without it again."

Source control frees the software engineer up.  It
  • Creates a warehouse to allow the software engineer to easily share code over a network and the internet.
  • Versions off code so you can get old versions of the code, see who changed what, when they did it and why.
  • Allows for easy backups of the code and access for automated builds, testing and deployment.
  • Provides highly valuable diff mechanisms to see how the code is changing so software engineers can easily review code changed by other software engineers.
  • Frees the software engineer up to make changes without worry because they can revert their changes when they take development in the wrong direction or pull up old code in the event they make a change that breaks pre-existing code.
No team should ever develop software without the use of source control.

2. Logging

"If knowledge can create problems, it is not through ignorance that we can solve them." -- Isaac Asimov

In school they teach you Standard Out and Standard Error.  This is absolutely the most horrible way to log.  This approach hurts software engineers because:
  • They have to remove these output statements before you are done so you are constantly adding and removing code
  • They cannot turn the output back on in the future to see what is happening in the code when something starts to go wrong again
  • It confuses an application that uses Standard Out and Standard Error to communicate with the user (console applications)
  • They cannot segment the messages into multiple levels like DEBUG, INFO, ERROR, WARNING or FATAL message
  • They cannot easily pipe the Standard Out or Standard Error to logging files for future diagnostics in a flexible way (like send errors to individual log files while sending debug code to the console)
  • They cannot configure the code to capture some output messages from certain parts of the application that are causing problems while turning the output off in other areas that are working fine
There are tons of logging tools available and the use of a good one allows the construction of an application where problems can easily be diagnosed and fixed just by tweaking logging settings.  Some of the tools use compile time directives (common in C and C++) but the best ones use configuration files so that logging can be changed at load or run time (like Log4j and Java Commons Logging).

Never use Standard Out or Standard Error for anything unless you are writing a console application that must interact with a user through these output methods.

3. Interfaces (Program to the Interface)

"We are what we repeatedly do." -- Aristotle

In order to make an application more modular and make the application code easier to refactor, you should always program to the interface.  This isn't saying an User Interface.  The interface I am talking about is a programming interface: a list of methods that forms a contract that says, any code that implements the interface must have this pre-set list of methods available for use.  This allows us to swap in and out different implementations of this interface as needs change either for one specific application or when the application is used and extended by different software shops for different client needs.

4. Unit Testing

"Fool me once, shame on you; fool me twice, shame on me." -- Old Chinese Proverb

It is amazing how much time we spend manually testing our code.  What is more amazing is how this time builds up on applications we have to maintain over years.  Every time we touch the code we need to retest.  Quite often, you can spend as much time testing as you spend writing the code for the application.

When you write code that tests your code, you may spend more time testing the first time, but you will spend much less time in the long run.  Once written, this automated test can be run without any human intervention and the tests can be scheduled to run and create reports regularly for the team providing immediate feedback on whether the code was inadvertently broken.

The automated tests help greatly in teams of multiple software engineers.  When the software engineer who wrote the code creates the tests, he makes sure that any other software engineer that comes along to make changes is unlikely to break the code without the test failing.  Failed tests should be an immediate indication that the code is NOT ready for a production environment.

The tests also serve as documentation on how the code should be used and should work.  If a software engineer looks at a code library and scratches their head, they should look at the test code and see how that library is being used.

5. Design Patterns

"Learn from the mistakes of others. You can't live long enough to make them all yourself." -- Eleanor Roosevelt

History is the profession of teaching us about others' past mistakes and triumphs.  Full understanding of historical events allows us to move forward with the confidence and ability to know we are more likely to succeed and do so more easily than our predecessors.

Design patters are the recording of the triumphs that software engineers have encountered in the software world.  They are consistently implemented methods of solving common problems we software engineers encounter every day.

On the flip side are anti-patterns.  These are the mistakes made by others.  As funny as it sounds, we can often learn more from what people have done wrong than what they did right.

The knowledge of design patters allows us to create new software libraries and applications that other software engineers well versed in design patters can then quickly and easily understand and use.  It also helps us build off the greatness of those before us.  We no longer have to reinvent the wheel but instead stand on the shoulders of those before us.

Of all the design patterns out there, the very first a software engineer should learn is MVC or Model View Controller.  It is the most commonly used and is quite simple and very versitile.  It forms the foundation of all our applications.

I hope this helps those of you looking for a future job in software as well as those doing the teaching.  Maybe we will see improvements in these five topics in the coming years.  It would make my job of finding new great talent much easier!