Plannedscape Postings

Image

Show Some Love For PDL
Great Way To Design Code & Document It At The Same Time

Posted by Charlie Recksieck on 2019-08-01
Everybody says they're committed to documentation. But in our experience, this is the aspect of software development where the most people drop the ball. Nobody intentionally makes a decision to not document. It just kind of happens, whether at huge software firms, in-house for large or small companies and even the best software hacks. Basically, less than one-third of all software projects (reported from several 2019 sources) are completed in their projected time, and fewer are also on-budget. As a result, when documentation should be done towards the end of the project, the team is already catching heat from above about being late. The temptation is there to phone it in when it comes to documentation. If you're a developer, chances are that you won't even be around by the time somebody discovers how much the project documentation is lacking.

Mostly what I just mentioned is project documentation. But just as important is in-code documentation. These are programmers' notes, instructions, comments, references, mentions of false starts. Basically, anything that never gets processed in code is there for humans. If you look at the Visual Studio screen capture at the top of the page of some C# code, everything that is green is documentation.

The benefits of in-code documentation are huge. The most obvious one is that when Developer A has written the code but Developer B has to modify it months or years later, the notes are huge to walk the new person through what is happening. (Also important are strong variable naming conventions, anal-retentive margins and formatting, etc. but let's save that for another day.) Perhaps some insecure, mediocre developers intentionally leave out notes with the intent of some sort of job-security since they may be the only people to make sense of the code. That short-sighted approach doesn't work; anybody doing code review would drum folks like that off their team. In reality, most projects fall short from people either omitting proper commenting either because of inexperience or feeling rushed and behind in their work.

Code doesn't need to be shared of part of a collaborative effort to need documentation. If you've coded something in February, everything may have made sense at the time. But let's say you've come back to the code in July and you don't have any notes to work with, it's more than likely that you'll have to learn this code all over again. 80% of the time when I'm writing in-code notes, I'm assuming that I might be the only person revisiting this code later.

Also the comments are a great place to make notes of business decisions, keep some rejected/unused code handy, explanations of why that code wasn't used, or references to internal code repositories or URLs of relevant web pages. There are so many valid reasons for in-code documentation. As we mentioned at the top, everybody seems to intend to document well. Keeping that in mind, we should start with the assumption that everybody knows how valuable this all is.

So let me introduce the idea of Programming Design Language (or PDL) for can’t-miss, in-code documentation. I first came upon this reading the seminal book for developers in the 90's when I started, Code Complete by Steve McConnell. (Still a worthy read today.) The premise is that you just type out in simple English what you want the routine to do in your code. Leave out specific programming terms (e.g. Declare, Set) and variable names. Just describe the intent. Then between each line of "PDL" you write the actual code. When you're done, now your original PDL functions as great in-code documentation. It's that simple. Let's take a look at what I mean.

Here’s an example from a project Brad and I have been involved with. What's below is the PDL for what is going to be one routine with one purpose: to send an email to a subscriber. (Ideally, 1 function/routine = 1 purpose, which is a whole other blog topic in the future.) So, before any code is written, we want to write it out in English - in the file where code will go. In this case, that's a C# (.cs) file in a web project of ours. We want to think out what we WILL do when we write the code, but describe it in simple language that will become our notes.

   // we have already performed verification that message is initiated by a human - this routine simply sends a message
   // based on valid parameters for email


   // look up recipient first name & email address
   // get the environment, development, staging, production
   // non-production ... Brad and Charlie are members 1 and 2, so if member ID is greater than 2 don’t send email
   // in development, we occasionally might sent a 4th argument of true to this routine, so that the
   // code really WILL send an email to somebody in a dev environment
   // if on development server ONLY actually send an email to Brad or Charlie (user# 1 or 2)
   //// now, lets also see if the recipient is brad@ charlie@ in which case, still sent it
   // create message object and populate properties including network credentials
   // send email with try/catch error to validate that it was sent
   // if successful, log the email in our DB
   // sanitize a potential apostrophe which would break the quote
   // return argument of successful
   // if unsuccessful, try emailing PP that something went wrong
   // return argument of unsuccessful


That description in green should make sense, right? Now after writing it out (which is an opportunity to think out loud before jumping into coding), we write the actual code. Here's what the first PDL line looks like:

   // look up recipient first name & email address

From there, we write the code corresponding to what's described - put it right below the line of PDL:

   // look up recipient first name & email address
   string strFirstName = DatabaseTools.Get_1Record_StringFieldValue_FromTable
        ("Users", "userFirst", "userID", intMemberID.ToString(), false);
   string strEmail = DatabaseTools.Get_1Record_StringFieldValue_FromTable
        ("Users", "userEmail", "userID", intMemberID.ToString(), false);


Voila! That's PDL. Then on to the next line ...

   // get the environment, development, staging, production

... becomes:

   // get the environment, development, staging, production
   string strEnvironment = ConfigurationManager.AppSettings["environment"];

Keep on going til the routine is done and the full PDL you saw above becomes this:


  // we have already performed verification that message is initiated by a humen - this routine simply sends a message
  // based on valid parameters for email

  // look up recipient first name & email address

  string strFirstName = DatabaseTools.Get_1Record_StringFieldValue_FromTable
      ("Users", "userFirst", "userID", intMemberID.ToString(), false);
  string strEmail = DatabaseTools.Get_1Record_StringFieldValue_FromTable
      ("Users", "userEmail", "userID", intMemberID.ToString(), false);
  string strMemberStatus = DatabaseTools.Get_1Record_StringFieldValue_FromTable
      ("Users", "userRoleID", "userID", intMemberID.ToString(), false);
  int intMemberStatus = Convert.ToInt16(strMemberStatus);

 
// get the environment, development, staging, production
  string strEnvironment = ConfigurationManager.AppSettings["environment"];

 
// non-production ... Brad and Charlie are members 1 and 2, so if member ID is greater than 2 don’t send email
  if ((strEnvironment != "production") && (intMemberStatus > 2))
     return false;

 
// in development, we occasionally might sent a 4th argument of true to this routine, so that the
  // code really WILL send an email to somebody in a dev environment

  if (!bByPassEnvironmentCheck)
  {
    
// if on development server ONLY actually send an email to Brad or Charlie (user# 1 or 2)
     string strServer = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority);
     if (strEnvironment != "production")
     {
       
/// *** CODE GOES HERE, NOT SHOWN ***
     }
  }

 
// create message object and populate properties including network credentials
  MailMessage mailMsg = new MailMessage();
 
/// *** CODE GOES HERE, NOT SHOWN ***

  // send email with try/catch error to validate that it was sent

  try
  {
     objSMTP.Send(mailMsg);

    
// if successful, log the email in our DB
     strMessageBody = strMessageBody.Replace("’", "’’");
    
// sanitize a potential apostrophe which would break the quote
     /// *** CODE GOES HERE, NOT SHOWN ***

     bool bQueryResult = DatabaseTools.ExecuteQueryNoResult(strThisQuery);
    
// return argument of successful
     return true;
  }
  catch
  {
    
// if unsuccessful, try emailing PP that something went wrong
     SendEmailToPP(**OTHER FUNCTION**);
    
// return argument of unsuccessful
     return false;
  }


Hopefully you see the bang for the buck of the process. Not only does it get you to think before coding (always good) but then leaves you with very solid inline documentation. Other benefits of PDL are well discussed here in this solid article.

We try to be flexible with projects here, agile vs waterfall (usually one-offs) vs scrum and each job for each client is pretty unique. But one of the consistent things we do here is PDL. Give it a shot, or see if the programmer in your life does something like this.