Main Points

History is Now

We've examined the Pseudocode Programming Process in great detail, at least in principle. I've had a chance to outline Steve McConnell's approach to PPP and why I think it's successful, as well as the modifications I've made and why I disagree with Steve on those points. However, Steve (and most developers) discusses PPP as something that can be documented in many ways and I don't really agree. While its "possible", I don't believe any alternative is really competitive compared to documenting PPP in an XHTML webpage. There are two key advantages to approaching PPP this way.

One, it gives you a single point of contact; XHTML is designed to be web-based. You can post the pseudocode design online and all stakeholders can refer to it. If you use a white board, it's physically stuck in one location (nor can you document all the PPP at once unless it's a really small project). If you take photos to document your white board work (a popular method), the text is not accessible and someone still needs to type it up in order to become program comments. Writing it down on paper suffers from this same problem. Writing the PPP up in an electronic document is easy to pass around and the pseudocode can be copied and pasted into code files for use. However, doc files don't give you a single point of contact. When you share the PPP with your design team and stakeholders, doc files are sent as attachments, but that means everyone has their own copies. Handling change management like this can be difficult, consolidating modifications problematic, and communication becomes nightmarish. If you don't believe me, try wasting the first thirty minutes of your next design meeting in arguments only to discover that the problem is one person who came to the meeting with an old copy of the pseudocode. An XHTML document posted either publicly on the internet or in a secured intra/extranet location ensures everyone is talking about the same thing and that there is an "official" version that keeps everyone on the same page.

Two, and maybe more importantly, XHTML provides easy use of in-page links. That means when you write a function call, you can link the text directly to the location in the PPP where that function is defined. While electronic documents can be made to duplicate some if this functionality, it's a somewhat clumsy process that few people even know about; certainly nothing like XHTML where links are simple and natural to create and use. The ability to follow function calls in XHTML is critical; it gives you the ability to swiftly and easily follow various logic paths through your design exactly the way that your code will execute in production.

This is an unbelievable advantage which I would never give up, even if I did not see it in advance. My first pseudocode design was conducted on paper and suffered from all the attendant drawbacks. What can I say, no one really recommended an alternative, and it was my first formal design. I rendered it into XHTML merely so I could describe the process for EC Beta. When I was working the XHTML up, I became concerned that not all developers would have the patience necessary to follow everything through the way someone committed to this application, like me, would do. So I linked up the functions to make the description easier for visitors to follow. It was so convenient I've never documented PPP any other way since. While I will still make notes and draw diagrams on paper, XHTML is where I keep all relevant information for permanent documentation.

Pseudocode Demo

We've talked a lot about the theories and requirements of pseudocode. Here's an example of how I actually construct my pseudocode. I will say that this is a finished pseudocode design. We'll look at the process of creating it a little further down.

functionName() Function

... outputXhtml createXhtml()

Detailed statement of step one in processing this function: get a key to create a custom object
call unfinishedFunction(): retrieve CustomObjectKey (_)

Detailed statement of step two in processing this function.

Detailed statement of part one of step two in processing this function: pass in the key to create the custom object
create UnfinishedCustomObject(CustomObjectKey): retrieve CustomObject (_)

Detailed statement of part two of step two in processing this function: using the custom object to create output XHTML
call Class2.finishedFunction(CustomObject): retrieve outputXhtml (X)

Output the XHTML code

Class 2

finishedFunction() Function

... outputXhtml finishedFunction(Parameter1)

Detailed statement of step one in processing this function.

Detailed statement of step two in processing this function.

Output the XHTML code

This is a quick working demo to show off how it works. If you'd like to see a full-scale PPP, you can check out one of my PPP designs (with multiple versions) at Earth Chronicle Beta.

You'll note how this imitates the natural look of real code. For me this was the most natural way to structure it mentally and to read it visually. This is also convenient because this will be the skeleton for the real code; therefore, this structure requires virtually no adaptation when we move on to construction. The function declaration is highly recognizable; for semantic reasons I'm even discussing the return value though this will need to be changed to the data type when formalized. I'm also including the parameters which the function accepts so I can consider function signatures, overloads, interfaces, etc. as part of the design phase.

Following the function declaration, I write out each step in plain language. In some cases, we may be at a low enough level of abstraction that during construction, we can translate the pseudocode into a few lines of code. On the other hand, if we can't, then we include an additional line providing details about the function call including an inpage link to the pseudocode of the other function. This is the most important technique that I use during PPP, because it simplifies examining the application and tracing the application logic through each function call in a way that no other form of documentation can do.

I also note the return type of the function, again, as an abstraction, not a data type because this is more relevant to the application design. Finally I end the function call with one of two symbols: (_) indicates the called function still has to be written in pseudocode, (X) means the function is complete. This isn't important to the completed design, but it's critical when you're writing function calls in pseudocode; it's the only convenient way I've found to track which functions I know I need but have yet to write. That's how I make sure that everything gets done.

When the entire pseudocode design is complete, I can start following links through the program and work up a full diagram of the application design. Between examining the generalized application diagram and cruising the PPP (via the links) for a detailed view, this gives me a chance to evaluate the design, form consistent levels of abstraction, and reshape the application design at a high level until it looks good.

Determine Your I / O

functionName() Function

... returnValue functionName(Parameter1, Parameter2)

.
.
.

Output the return value, if it exists.

You can see that different things are happening at different points in the process, so let's break it down step by step. The first thing to do is define the input and output of the function. At its most basic, this is all the inside of a computer can do, so this helps me focus on the real guts of what I want to accomplish. What output do I need to generate? And what is the minimum amount of input I need to create that output?

The last line of the pseudocode defines the output, if any. If the return type of the function is void (or whatever keyword your language uses), then there will be no output from the function. In my opinion, this is not a good practice. It makes it more difficult to operate on the results of the function's actions and makes it Much easier to write functions that do more than one thing. It's hard to write poorly cohesive functions when you can only return one value. If I need to execute a DAL update or delete action, there's nothing to return, so I write a function that returns void, but otherwise I avoid them whenever possible.

The first line defines the function and becomes the function declaration. It specifies the abstraction we're returning (though in some cases I might not be certain yet exactly how I want to return the information). I also have the name of the function so I can consider the semantics, and as I get a feel for the application, I'll create the input parameters of the function. When I write my first rough draft of the function, however, I frequently have no parameters at all.

Lay Out the Procedure

... returnValue functionName(Parameter1, Parameter2)

Detailed statement of step one in processing this function.

Detailed statement of step two in processing this function.

Detailed statement of part one of step two in processing this function

Detailed statement of part two of step two in processing this function

Output the return value, if it exists.

While not complicated, this is where the steps of the function are laid out in plain language. This is traditional PPP at its finest, using the abstraction of your current function to break the program down into smaller steps. Nor is this used as some kind of separate documentation; this is used as the beginning of your function. Just clean up the syntax of your declaration, add your braces, and comment out each line of pseudocode. Now you're ready to start coding.

PPP – when used properly like this – allows you to start at a high level of abstraction and work down through progressively lower-level abstractions until you get to the point that you can see how the comment that you've written will translate directly into code. Detailed design is about taking the entire application down to this point; the point where you can "see" all the code that you have to write for the entire application. Essentially detailed design is a middle ground between the sins of the older waterfall methodology (Big Design Up Front) vs. minimalist design phase practiced by many agile methodologies.

Determine Semantics and Structure

... returnValue functionName(Parameter1, Parameter2)

Detailed statement of step one in processing this function.
call unfinishedFunction(): retrieve CustomObjectKey (_)

Detailed statement of step two in processing this function.

Detailed statement of part one of step two in processing this function
create Class1.unfinishedObject: retrieve CustomObject (_)

Detailed statement of part two of step two in processing this function
call Class2.finishedFunction(Parameter1): retrieve outputXhtml (X)

Output the return value, if it exists.

This is another step that I carry out a little more formally than traditional PPP; the emphasis is on giving some consideration to semantics. I'm also clearly addressing some issues of class structure as well. In fact, when I put together a detailed pseudocode design, I group related functions by their class name. Sometimes your comment will translate directly into code, then nothing more is required. However, especially in the higher-level abstractions, there is too much code to write. These comments won't translate into code you can implement, so you will have to delegate the responsibility to another function.

As you can see, when I need to call another function, I create a second line of pseudocode. At first, the function name and the abstraction returned is all the information I write down. I also create the function call as a link to the appropriate function – though the link won't go anywhere until I write the pseudocode for the function it links to. This is the key; as the other functions are added, the links let you easily walk the pathways of the application to get a feel for the design and how it will actually work. This is how I will read the application typically, though I can also read it top down to review each class in turn. Finally, I include "(_)" to clearly indicate on a visual inspection that I still need to write the function I'm calling. When the function is completed I change this to (X). Now, by doing a simple search in my code editor for (_), I can find the next function to create for the design.

Step one demonstrates a function call to a function that's in the same class. However, there will be times that I instantiate another object in my function and call it's members. In step 2 - part 1, I demonstrate this using a class (Class1) to create a new object. This not only demands that we consider the name of the function and the name of the class, but which class each function is going to live in. Considering the ramifications of these details and working them out as early as possible, will make it that much more likely that our design will be strong and easy to construct.

In step 2 - part 2, I've finished the function so I've crossed it off "(X)" as a visual indication that it's done. I have included the parameters in the finished function, though finalizing parameters is one of the last things that typically come together for me. However, this phase is where I'm playing with different signatures for the function and determining if I'll need to overload the function and how.

Once I've included the parameters, any change to the function signature probably requires me to change all the links as well. If I have defined my helper functions well, this could be a huge job so I like to be reasonably sure I won't have to do that much; including the parameters is something I hold off doing until late in the design (at least for the links). This may be a reason that McConnell does not implement PPP this way. However, including the parameters in each function call lets you move back and forth between the call and the function to ensure that you didn't change one, and forget to update the other. Given the nasty surprises that common mistake can cause during construction, I find the advantages significantly outweigh the drawbacks.

Repetition

One thing you'll notice is that the work in this phase keeps bringing up phrases like "I don't know at first" and "I'm not ready until..." Determining the I / O and constructing the procedure is really about getting the pseudocode of each function written up the first time through. Once that's done, we start looking over the design again and again and again. Once you've got all the pseudocode written, you have the tool you've wanted to maximize your ability to review the high level abstractions and logic in your application repeatedly. Each time through, you can focus on particular details to the exclusion of all others. Do all my classes conform well to their abstractions? Review the design to see. Is there any repetitive code in the application that I could break out into utility functions? Review the design to see, etc.

Steve McConnell even recommends repeating the entire PPP process a few times. That takes a lot of discipline, but I have seen the process produce important results; at the very least, I'd recommend running it a second time, without referring to your first pseudocode design. Even if you sit down with the purpose of replicating it from memory, in any non-trivial application you'll be shocked how different your second attempt turns out to be. Ideally you will really sit down from scratch and write out the application pseudocode as seems best to you for the second time. Each divergence from the first pseudocode design gives you a good point where you can consider your options and determine which way to go.

While repeating the entire PPP process is a major undertaking, I've seen it actually save time. In any design, developers stress about particular decisions and waste a lot of time trying to decide what to do, whether they're in design or construction or wherever they find it. Repeating PPP can solve some of these intractable problems really easily; as you go through and write the pseudocode several times, there's no reason to question a choice if you keep making the design the same way. No matter how "close" a decision seems in your head, if you keep making it the same way in the end, it's really not close at all. This is another place where formal PPP tells you a lot more about an application design and saves you a lot of time compared to less formal methodologies.

XHTML Sample

Last but not least, here's how the XHTML documentation is created. As you'll see, it's very simple, which is one of the advantages of this technique. I will use a level one heading to introduce the PPP page and the level two headings organize each layer / class in the application. That leaves the level three headings to define the functions and custom objects, and the id of the <h3> tag defines this as the landing point for the all-important link to this function. I've also wrapped everything in <code> tags to clarify that this is computer code. The code fragment even takes my standard computerCode class so that it has the correct appearance I've written into my stylesheets.

<h3 id="functionName">
<code>functionName()</code> Function
</h3>

<code class="computerCode">
... returnValue(if known) functionName()<br />
<br />
Detailed statement of step one in processing this function.<br />
<a class="#unfinishedFunction">call AppLogic.unfinishedFunction()</a>: retrieve functionOutput (_)<br />
<br />
Detailed statement of step two in processing this function.<br />
<br />
<code class="codeNewIndent"><br />
Detailed statement of part one of step two in processing this function<br />
<br />
Detailed statement of part two of step two in processing this function<br />
<a class="#finishedFunction">create AppLogic.finishedCustomObject(Parameter1)</a>: retrieve customObject (X)<br />
</code><br />
<br />
Return whatever is the return value.<br />
</code><br />

<p>
Discussion of functionName.
</p>

Most everything else is simply written into the code as plain text. There are extra code elements, the elements with the codeNewIndent class that organize and indent the code correctly. Each call to create an object or call a function is wrapped in a link (the <a> tag) which is directed at the name of the function. I also build in a starting paragraph to discuss the function, how it works, its role in the application, and any special thoughts or concerns which I want to document. This is all there is to the XHTML structure for documenting PPP, yet it yields the most efficient and usable tool for evaluating and improving your design.

That's a pretty complete overview of PPP. If you're interested in more details, I would recommend looking at the real design documentation, for some of my C# projects. Most of my completed work includes detailed pseudocode designs.

One of the things I like best about PPP is that it allows me to attempt to build consistent levels of abstraction. While abstraction is a powerful concept, it is even more useful to be able to engineer an application where modules are built with similar architectures. These touchstones serve as an important way for a programmer working in one module to quickly orient themselves when they have to pop over to work in another module and then come back. If different modules are engineered too differently, it's like shifting from English to Japanese and back again. Is it possible to do that? Certainly. Is it efficient? Absolutely not.