The Art of Programming

From my 30 years of programming, here's my list of tips and bromides for new programmers.

  1. Read Software Theory books.

    Browse Amazon, or your local bookstore's software section. See what's new. Don't just read the latest Cookbooks on how to use technology, but try to understand the deeper aspects of software development.

  2. Read software blogs, follow significant developers on Twitter, and listen to software podcasts.

    Blogs like Eric Gunnerson's for C# or Martin Fowler's. Visit software web sites like pragmaticprogrammer. Also dead-tree publishers like Mannings and Pragmatic Programmer have daily or weekly newsletters. They are a great place to learn about new technologies.

  3. You can stay at a company too long.

    Although it is good to not jump jobs too quickly, sometimes you can stay at a job too long. If you are not learning new technologies at a job with no prospect of that changing, especially at a small company, sometimes it's time to move on.

  4. Code can be wierd for a reason.

    Don't "fix" code when you don't understand it. Also, put a comment in the code when you do something counterintuitive.

  5. Don't leave anything personal on your work computer that you want to save.

    You never know when you will be laid-off and escorted out the door without being able to access your work laptop.

  6. Senior management thinks of programmers as interchangeable. FYI: they are not.

    Management will transfer authors of one code base to another project without asking the developers. This will cause frustration and damage productivity. Don't be surprised when the author of a critical piece of Java software is suddenly switched to a .Net project for no other reason than to "Mix things up".

  7. Anonymous employee surveys are not that anonymous. Some managers will try to uncover who rated them poorly. Be careful what you say.
  8. Be an active member in a local user/professional organization.

    Join the local Java User's Group and .Net groups. You'll meet new and interesting, sometimes scary, people.

  9. Keep a daily record of major events during the day in a file.

    Things like the phone numbers of people you talk with, significant bug fixes, code snippets, URLs, SQL clauses, email addresses. It is important to keep it in a file and not just on paper, so that it can searched, transferred and backed up easily. Make sure it is copied to Dropbox or OneNote.

  10. Keep a library of interesting code that you've written and things you've learned.

    The best way is to just publish this on the web somewhere. That way you can always locate it and your knowledge can help others.

  11. Remember - It's all about people

    It's easy to forget during the crush of time pressures of a particular project that your relationship with your coworkers is the single most important long term issue. Don't ruin relationships just to get a single project done. Those same people are critical to the success of your next project. Besides, those people give you recommendations and job offers after your current company folds.

  12. Know that software is trendy.

    Don't always jump on the latest bandwagon, give it a little time to prove itself. SOAP messaging is the conical example. It was just a bad idea all the way around, but too many people went with it (I'm looking at you Microsoft). To be fair, in 5% of the use cases you need the power of SOAP, but not for the other 95%.

    What's the best JavaScript front-end framework? Backbone, Angular, Angular4, React, Vue, knockout, Ember, aurelia, polymer? It changes every 9 months. Perhaps it's better to just hunker down and learn JavaScript really well.

  13. As you code, think of maintenance.

    Try to downgrade the skills needed to maintain your system. For example, to change a parameter use an init file instead of a java class, so someone with only text editing skills can update your program.

  14. When you finally track down that hard to find bug, don't fix it immediately.
    1. Write a unit test that exposes the error.
    2. Change your code so that the error message is more descriptive.

      Then related bugs will be easier to find and fix. For example, if your servlet fails and the only indication is the "page cannot be displayed" message on a browser, change it so that it writes a page to the browser explaining the error, "Cannot find the file 'Config/Messages-en-US.txt'". Or perhaps for security reasons, give a bit more general error message and tell the reader that a more detailed message is written in the system log file.

    3. Fix the original bug.
    4. Write a brief summary in your daily log file about what the original error message was and how you fixed it.

      I'm embarrassed by how many times I was asked by someone to fix a problem, and I knew I had the same problem once, but forgot how it was fixed. But sometimes in a brief, shining moment, I search in my daily log file for my co-workers error message, and find the solution.

  15. Don't try to make your code modules reusable for some future mythical system.

    To make a module reusable takes three times as long as for single use. The odds of you, or your friends, reusing the module is really low. Don't waster your employers money doing something that may never be used. If you find a use for that module later on, then make it reusable if it makes sense.

  16. Don't spend time optimizing before all is working:

    "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil." - Donald Knuth

  17. Realize methodologies are just guidelines.

    Don't follow methodologies blindly. Just because Object Oriented Programming is a great methodology, it doesn't imply you should always follow it. In some cases speed or memory constraints force a good programmer to go against OOP.

    The same with Domain Driven Design. It is not appropriate for very small applications.

    ("Do not develop an attachment to any one weapon or any one school of fighting." - 17th Century Japanese Samurai, Miyamoto Musashi)

    "More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason - including blind stupidity." - W.A. Wulf

  18. Constantly improve your skill level.

    Always be learning. Talk to other software people about their problems and solutions. Be alert, the next software revolution often happens with very little warning.

  19. Testing

    I like this quote from a Rational brochure: "Continuous, automated testing that covers the entire development life cycle. It's the only way to manage the constant flow of changes, errors and general chaos."

    Invest in a high level of automated testing. I like JUnit for Java and NUnit for .Net. If possible, write your tests so that the input is an XML description of objects. This way your testers can write your tests, instead of programmers.

  20. Post-Installation Test for Enterprise Software

    In the administration portion of your application have an "installation test" section where all the major components get exercised. Have a link to test that the databases are connected, any web services, and that key configuration items have values. Installation is such a pain and you can relieve some of that with good tests and explanations when something is not quite cricket.

  21. OHIO/DRY

    Remember what Ray Ozzie calls the OHIO principle (Only Handle Information Once.) "If information must be entered in two places, it won't be."
    (AKA 'DRY' Principle: Don't Repeat Yourself).

  22. YAGNI - You Ain't Going to Need It

    Don't put in code that will be needed in some future release, but isn't needed for this release. In my humble experience this often goes bad and wastes everybodies time. One example was adding a language field at the end of a chain of function calls, for the day when we would go multi-language. Then we did not specify to use two-letter or three-letter abbreviations. Some people had used two and others used three letters. It was a big time sink. And no, the product was never released using anything but English.

  23. Except for the simpliest of projects, use Dependency Injection.

    Dependency Injection (DI) gives you a pivot point so you can swap dependencies for testing.

  24. Push Complexity Down

    You should push complexity down to lower objects and not clutter the higher objects with details.

  25. Command Query Separation (CQS)

    Bertrand Meyer presented it as:

    "... every method should either be a command that performs an action, or a query that returns data to the caller, but not both. In other words, asking a question should not change the answer" -Wikipedia
  26. Your biggest enemy professionally is your pride

    Don't be afraid to say "Hmmm. David, I've never heard about that before; what is it?", or "Hey Frank, could you look over this code and see if there's a better way to do this.". Don't assume you know the best way to design or code something. We can all learn from each other in this voyage called life. Don't fear constructive criticism. "Faithful are the wounds of a friend."

  27. Some Low-Level Coding Tidbits
    1. Write your methods to be testable.

      Instead of having a method like,

      public string DBCalculation(int ID) {
      int k = databasemethod1(ID);
      int i = databasemethod2(ID);
      if(k > 2) k = k/2;
      if(i < 10) i = i+20;
      if(i + k > 20) { i = 1; k = 20; }
      return Math.Atan(double(k),double(i*2);

      which would really be hard to test with dozens of values of k and i, because you have to feed the database input values. Instead, break up the code into more modules that can be driven with data.

      public string DBCalculation(int ID) {
      int k = databasemethod1(ID);
      int i = databasemethod2(ID);
      return Calculation(k,i);
      public string Calculation(int k, int i) {
      if(k > 2) k = k/2;
      if(i < 10) i = i+20;
      if(i + k > 20) { i = 1; k = 20; }
      return Math.Atan(double(k),double(i*2);

      the method "Calculation" can be tested easily with xUnit (and would hopefully reveal the flaw in this method).

    2. Methods that take an object

      If a method takes an object for its argument, it may mean that method really belongs on that object.

      int numberOfTires = HelperClass.CountTires(Car car);

      "CountTires()" would really be much happier in the Car object.

      int numberOfTires = car.CountTires();
    3. 'Declarative Testing' - Use XML or JSON data files to feed xUnit tests.

      For the above example, instead of doing the following in code

      Assertion.AssertEquals(12, Calculation(3,4));
      Assertion.AssertEquals(0, Calculation(6,1));
      Assertion.AssertEquals(4, Calculation(2,12));

      Use Declarative Testing by employing XML files which are more flexible and can be written by testers.

      <Calculation i='3' k='4' result='12' />
      <Calculation i='6' k='1' result='0' />
      <Calculation i='2' k='12' result='4' />
    4. Always check for errors

      Don't assume you know all values that will ever possibly come into your routine. Handle the cases you expect and always throw an exception for anything else

      public bool Walk() {
      	switch(val) {
      		case '&': return left.Walk() && right.Walk();
      		case '|': return left.Walk() || right.Walk();
      		case 't': return true;
      		case 'f': return false;
      			throw new Exception("KQParserCore.Walk() encountered 
      a val that was not '|', '&', 't', or 't'.  It was '"+val+"'");
    5. In boolean conditions for C and C++, put the constants on the left side
      if( 0 == currentRecordNumber )

      That way if the second '=' is forgotten, the compiler will tell you.

      if( 0 = currentRecordNumber )
    6. Don't name a major class the same as a SQL keyword like "Group" or "Order". It can bite you later. Trust me, I know.
    7. With the exception of 0 and 1, don't use integers in your code - use constants.
      //bad   int[] accounts = new int[5];   
      const int NUMBER_OF_ACCOUNT_TYPES = 5;
      int[] accounts = new int[NUMBER_OF_ACCOUNT_TYPES];
    8. Don't ever repeat key/index strings - use constants.
      //using "lastname" as a key opens possible spelling errors later.
      //what if someone accidently capitalizes "lastname" or puts a space in it?
      //you will get a silent error.
      Hashtable hashtable = new Hashtable();
      hashtable.Add("lastname", "smith");
      string name = (string)hashtable["lastname"];
      //better to always use string constants - typos will be caught by the compiler
      //and you get a handy reference list of all your keys/indexes used
      const string LAST_NAME = "Lastname";
      hashtable.Add(LAST_NAME, "jones");
      name = (string)hashtable[LAST_NAME];
  28. My Favorite Quotes about Programming
    1. "The only proof of working software is working software." - James McGovern
    2. "Everything knows nothing about anything." - a perfectly object-oriented system.
    3. "People support a world they help create." - Laribee
    4. "Every line of code is a liability." - Taka Muraoka
    5. "Software has the shelf life of bannanas." - Scott McNealy
    6. "It might be that the key to Ant's success is that it didn't try to be successful. It was a simple solution to an obvious problem that many people were having." -James Duncan Davidson, the creator of Ant, a once widely popular build tool like rake or maven .

      At our local Java Users Group James Davidson said if he had done a full requirements analysis and tried to build the perfect tool for everyone's need, he probably would have failed. Instead he just built a little tool for himself and gradually added features that his friends really wanted right then.

    7. "It has been said that the great scientific disciplines are examples of giants standing on the shoulders of other giants. It has also been said that the software industry is an example of midgets standing on the toes of other midgets." -Alan Cooper, About Face
    8. "Measuring programming progress by lines of code is like measuring aircraft building progress by weight." -Bill Gates
    9. "The most amazing achievement of the computer software industry is its continuing cancellation of the steady and staggering gains made by the computer hardware industry." - Henry Petroski
    10. "If I had asked people what they wanted, they would have said faster horses." vaguely attributed to Henry Ford
    11. "There is nothing so useless as doing efficiently that which should not be done at all." - Peter Drucker
    12. "I have quipped in various board meetings that maybe we ought to give the airplanes away and sell the software maintenance contracts," - Ned Allen, Lockheed's chief scientist.
    13. "Do not develop an attachment to any one weapon or any one school of fighting." - 17th Century Japanese Samurai, Miyamoto Musashi
    14. "Debugging is at least twice as hard as writing the program in the first place. So if your code is as clever as you can possibly make it, then by definition you're not smart enough to debug it."
    15. "An organization, sooner or later, ships its org chart as its product (Conway's Law; the Windows organization was no different." -Ben Fathi