The Value of Code Documentation

Frank Meza · Feb 06, 2018

Documentation

Code documentation is the collection of easy to understand images and written descriptions that explain what a codebase does and how it can be used.

It can be simple explanatory comments above functions and blocks, or a full-fledged developer handbook, complete with prescriptive style dos-and-don'ts, overviews of each part of the application, and approaches to the most common types of coding tasks.

It's often best to find a happy medium between these two extremes when you make the conscious decision to comment your code and outline the gnarlier areas of a codebase in plain language.

Why document your code?

Why go to the trouble writing about your code, instead of just writing code? Wouldn't that just be more productive anyway?

condescending wonka meme

Mental Save Points

Documentation is like a mental save point for those times when you finally get what's going on at the end of the day and don't want to lose momentum. Well documented code will ensure that when you need to dive back in tomorrow morning (or several months from now), you won't have to take as much time getting up to speed.

Documented code gets reused

The difference between a used library and an unused library often comes down to its documentation.

Who wants to use an undocumented open-source library or contribute to an undocumented project? Almost no one.

In most cases, you'd rather use a less powerful library that has docs. Why? Because the documentation conveys other points of information about a codebase. The developers believe that the project is worth the time and energy to write about it in plain language so anyone who might be interested can quickly get started and learn how it works, and why key decisions were made.

Finding a new, interesting, and well-documented project in your favorite language can be very exciting and fun. Let's look at the extreme alternative: being required to use an undocumented code library and potentially contribute to a seemingly byzantine codebase... it sounds pretty painful, right?

So why haven't you documented your own code?

Documenting code is part of writing good code

A cornerstone of good code is maintainability, achieved through understandable, legible documentation.

There are multiple ways of documenting code:

  • choosing good names for variables and functions
  • leaving brief comments within the code to help give context to future readers
  • adding illustrative images such as sequence and entity relationship diagrams
  • providing API docs, describing each class, method, argument and return value
  • using a statically typed language, such as TypeScript (types as documentation)

Compare two examples

Let's say you're getting some data from a backend API and "ingressing" it - converting it into a more useful shape for a front-end UI. Here's the first of two possible solutions.

// wdgt.js

export const converter = (w) => {
    wdgtHdr = {
        name: w.nm,
        id: w.id,
        ts: w.lastTS
    }

    wdgtDtl = {
        dtlId: w.dtlId,
        dtlName: w.dtlNm,
        openTS: w.oTS,
        closeTS: w.cTS
    }

    wdgtRev = w.revs.map((r) => {
        const { note, prsn1Id, prsn1Ln, prsn1Fn, amt, cTS } = r
        const rr = {
            assocId: prsn1Id,
            assoc: `${prsn1Fn} ${prsn1Ln}`,
            amount: amt,
            note: note,
            revTS: cTS,
        }
        return rr
    }

    return {
        wdgtHdr, wdgtDtl, wdgtRev
    }
}

The above code has the potential to be painful. You can see by the name that this is some sort of converter that takes w as its param.

It looks like it returns a header, maybe details, and something called revs. Where did revs come from, anyway? Of course, there's no details about the incoming variable names note, prsn1Id, prsn1Ln, prsn1Fn, amt, cTS... or is there? Is rr short for returned rev? Who can say.

Let's look at the second example.

// widget_utils.ts

// widgetConverter :: widgetRespDTO -> widget
export const widgetConverter = (wResp: widgetRespDTO): Widget => {
    const widgetHeader: WidgetHeader = {
        name: wResp.nm,
        id: wResp.Id,
        ts: wResp.lastTS), // timestamp
    }

    const widgetDetail: WidgetDetail = {
        id: wResp.widgetId,
        name: wResp.dtlNm,
        openTS: wResp.oTS, // timestamp
        closeTS: wResp.cTS // timestamp
    }

    // [WidgetRevisionsRespDTO] is nested inside of WidgetRespDTO

    // [WidgetRevisionsRespDTO].map -> [WidgetRevision]
    const widgetRevisions: ReadonlyArray<WidgetRevision> =
        wResp.revs.map((wRevs: WidgetRevisionsRespDTO): WidgetRevision => {
            // how that other team names their variables...!
            const { cmt, prsn1Id, prsn1Ln, prsn1Fn, amt, cTS } = wRevs

            const comment: string = cmt
            const associateId: string = prsn1Id
            const associateName: string = `${prsn1Fn} ${prsn1Ln}`
            const amount: number = amt
            const revisionTS: number = cTS // unix timestamp, and "closeTS" fyi

            return {
                associateId,
                associateName,
                amount,
                comment,
                revisionTS,
            }
    }

    return {
        widgetHeader,
        widgetDetail,
        widgetRevisions,
    }
}

Wow, how different! This function is in a util file, so the main file is less cluttered already. It's also written in TypeScript instead of plain JavaScript, so we have the benefit of type defintions to help guide us.

We're converting widgetRespDTOs into widgets. Though shortened, we have full knowledge of what wResp is. We're creating a widgetHeader, and a widgetDetail, that's easy to see. We also understand what oTS and cTS are. We can tell WidgetRevisionsRespDTOs are nested inside of WidgetRespDTO.

Someone very kindly renamed the incoming variables so everyone who sees this code knows what they are. Finally, we see a Widget must be composed of the returned {widgetHeader, widgetDetail, widgetRevisions} object, since it must match the return type Widget specified at the top.

Which code would you feel better about using?

Who benefits?

Well documented code benefits many people:

1. Junior developers

Because it's in plain language and easy to understand, documentation helps junior developers and new team members feel confident jumping into a codebase. This prevents frustration and early abandonment of a task because it gets too complicated too quickly.

It's also helpful for junior developers to write their own documentation so they can share their code with others and so they can get a better understanding of their code.

2. Senior developers

By taking the time to document now, senior devs spend less time explaining their code to others in the future.

They can also write more complex code. Plain language documentation lets others use it like a black box, without having to understand the inner workings.

3. Teams & open source projects

Personnel changes can bring a tremendous slowdown to a project. Up-to-date and well documented code can serve as insurance against such slowdowns and allow the remaining team members to take a step back, review the code from a high level and decide on the best course of action moving forward, and if needed, on-board new employees.

4. You

When documenting code, you must summarize it. In order to summarize properly, you must be able to understand it, holding the different parts in your head at the same time. Writing or contributing to the documentation is a shortcut to really understanding a codebase, making huge contributions, and feeling like a great part of a great team.

Good documentation can DRY up our coding experience

As a programmer you've probably heard of the Don't Repeat Yourself principle as a key to writing clean and concise code. Instead of repeating the same code block several times, write a function that can be written once and employed all over your application.

In the same way, you and your team shouldn't be running into similar problems and then reinventing the wheel each time you attempt to solve them. For example, have you ever heard one of your coworkers or found yourself saying:

"Agh, I solved something very similar to this but I never remember how I do it when it comes up... I should probably write it down somewhere, huh?"

You then find yourself scanning the same Stack Overflow threads again and again.

Save yourself and your coworkers this grief by following the spirit of the DRY principle and writing a document that you can employ every time the issue comes up! This will help you and others on your team save time, and be more effective in writing simpler, more manageable, and more efficient code.

How has code documentation, or the lack thereof, affected you?

Interested in working with us?