DAMP Programming: Reviving Readability

--

Background:

BlogObject.setIntroWithAnecdotalStoryString(storyString);

Before being promoted from Tech Support to Software Engineer, I had spent some time browsing the companies source code. As a lowly Tech Support Representative, I was granted access to this code because I was charged with the task of troubleshooting, identifying, (and eventually fixing) bugs and memory leaks that our Engineering department “could not reproduce”.

At roughly 2–3 million lines, the Objective-C code was intimidating to say the least. After 3 intimate months of working with the language and this bloated code base, I noticed something unique about Objective-C that has since then, changed the way I code EVERYTHING!

DRY & WET Coding (tl;dr):

[‘DRY’, ‘WET’].map(&:describe_coding_convention_string)

As the newest eager beaver Engineer on the block, every time I heard coding convention or acronym I was not familiar with, I ran straight to the Internet to learn about it. DRY and WET were the flavors of the week.

DRY: Don’t Repeat Yourself

The DRY programming philosophy was first coined in The Pragmatic Programmer by Dennis Ritchie and Francisco Granados. The philosophy is to eliminate as much repetitive information as possible.

“Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.” — The Pragmatic Programmer

WET: We Enjoy Typing

Ironically enough, the term WET is easily described as a code or a system, that is not “DRY” enough. Typically is used if someone did not execute something according to the Philosophy.

“Hey Bro[grammer], that module is totes WET!!!! DRY it up and deploy so we can finish off that Blue Moon Keg in the break-room.” -Nobody Ever

Maybe you won’t hear it used like that, but here is an example of WET coding:

var Category = function(objectProperties) {
this.childCategory = objectProperties.childCategory || [];
this.name = objectProperties.name || "";
this.description = objectProperties.description || "";
}
Category.prototype.getChildCategoryName = function() {
if (!this.childCategory instanceof Category) {
throw("Child Category is not of instance Category")
}

return this.childCategory.name;
}
Category.prototype.getChildCategoryAge = function() {
if (!this.childCategory instanceof Category) {
throw("Child Category is not of instance Category")
}

return this.childCategory.age;
}

In this case, before accessing object specific properties of childCategory, a safeguard was used check if the childCategory is instanceof Category.

This is WET because the line:

if (!this.childCategory instanceof Category) {
throw("Child Category is not of instance Category")
}

Is used more than once to provide the same functionality. (In fact, this is a snippet of a class I wrote in which that line of code was used 7–10 times, and eventually revised because of the repetition.) DRY principals would instead suggest that you store this code in a function and then reference it in one line for each method, therefore creating one source.

As I was searching through DRY and WET coding philosophies, I stumbled across this Stack Overflow answer which referenced another acronym: DAMP.

DAMP: Descriptive And Meaningful Phrases

[SLBlogController willIncludeRelevantLearningOpportunity];

DAMP has nothing to do with DRY and WET

Before you take up your torches in fear of being told to abandoned your long standing philosophy about code duplication and efficiency, its helpful to note that DAMP has nothing to do with the DRY and WET philosophies.

And no, it does not mean your code is partially DRY, and partially WET.

Descriptive and Meaningful Phrases can peacefully coexist alongside DRY/WET philosophies.

What is DAMP?

DAMP applies to how you name all the things.

DAMP (Descriptive And Meaningful Phrases) promotes the readability of the code.

To maintain code, you first need to understand the code. To understand it, you have to read it. Consider for a moment how much time you spend reading code. It’s a lot. DAMP increases maintainability by reducing the time necessary to read and understand the code. Chris Edwards

Chris is right! How many hours have you wasted trying to decrypt and decipher poorly written, unreadable code? It’s up there in the thousands for me. If I had a dollar for every time I saw this:

NOT DAMP!


//dataLog.js
var data = [1, 3, 4, 6, 7, 9];
var logData = function(data) {
data.each(function(i, idx) {
console.log(i);
});
};
logData(data);

Now I know: this is a pretty easy-to-read JavaScript code example, and yeah, perhaps a non-JavaScript developer could figure out what is happening here.

However, every time I look at the above example, a small nuclear weapon explodes in my cerebellum begging to know more about what is happening.

// What is this data for? If it wasn’t defined here, would we know 
// what data type it is?
var data = [1, 3, 4, 6, 7, 9];

// What kind of data are we logging?
// What is the data type of the argument?
var logData = function(data) {

// What are the arguments inside the each function?
data.each(function(i, idx) {
console.log(i, idx);
});
};
// Well at-least I know something happens here...-_-'
logData(data);

These would be the same questions that ANYONE would ask, not only developers. If I showed this code to someone without programming experience, there is nothing they would find that describes what is trying to be accomplished.

Lets get DAMP:

Name ‘all the things’ as if you were going to describe it to someone.

If your variable is a primary array of baby names, then describe it that way:

In a duck typed language like JavaScript, where variable types are not explicitly declared, I tend to include the data type in the name:

var primaryBabyNamesArray = ["Spencer", "Mallory", "Collin", "Connor"];
var secondaryBabyNamesArray = ["Lily", "Janet", "Greta", "Tearlach"];

However in Objective-C:

NSArray *primaryBabyNames = @[@”Roger”, @”Wendy”, @”Richard”];

Lets take that first brain-melting example and make it DAMP:

//slPrintChildArrayNamesModuleButCommentsAreNotNeededWhenYouProgramWithDAMPFundementals.jsvar childAgesArray = [1, 3, 4, 6, 7, 9];var logEachAgeInArray = function(agesArray) {
agesArray.each(function(ageInteger, index) {
console.log(ageInteger, index);
});
};
logEachAgeInArray(childAgesArray);

The whole point of DAMP is that my anyone could understand what this code is trying to accomplish, even if I removed all of the guts from it, leaving only the function, variable, argument and file names.

In fact can you still tell whats going on when I remove its guts?

//slPrintChildArrayNamesModule.jsvar childAgesArray; //Guts get assigned here
var logEachAgeInArray = function(agesArray) {
//Guts here
};
logEachAgeInArray(childAgesArray);

Here is a shorted example of a predictive search example I worked on, that has the “guts” stripped out:

function slGutlessPredictiveSearchCtrl($scope) {// ... omitted for brevity

$scope.inputValueIsPreFilledFromNttParam = GUTS
$scope.requestedSearchTermForHighlighting = GUTS
$scope.searchAsYouTypeArray = GUTS
$scope.indexOfLastItemInSearchAsYouTypeArray = GUTS
$scope.selectedSearchTermResultIndex = GUTS
$scope.searchQuery = GUTS
if ($attrs.value && $attrs.value !== “”) {
$scope.searchQuery = $attrs.value;
$scope.inputValueIsPreFilledFromNttParam GUTS
} else {
$scope.searchQuery = GUTS
}
$scope.shouldHideResultPaneBasedOnInputBlur = GUTS
$scope.freezeResultPane = GUTS
$scope.preRequestValidation = function(newValue, oldValue) {
return {
GUTS
};
};
$scope.postRequestValidation = function(data) {
GUTS
};
$scope.sendSearchAsYouTypeRequest = function(searchTerm) {
$http({method: ‘GET’, url:url})
.success($scope.searchAsYouTypeRequestDidRespondWithSuccess)
.error($scope.searchAsYouTypeRequestDidRespondWithError);
};
$scope.searchAsYouTypeRequestDidRespondWithSuccess = function(data, status, headers, config) {
GUTS
};
$scope.searchAsYouTypeRequestDidRespondWithError = function(data, status, headers, config) {
GUTS
};
$scope.shouldShowResultsPane = function(){
GUTS
};
$scope.shouldShowProductCategorySubList = function() {
GUTS
};
$scope.shouldShowSearchSuggestionsSubList = function() {
GUTS
};
$scope.shouldBeHighlightedBasedOnResultTypeAndTypeIndex = function(resultType, typeIndex, nameValue) {GUTS};$scope.upArrowKeyPressed = function() {GUTS};$scope.downArrowKeyPressed = function() {GUTS};$scope.setSelectedIndexViaMouseOver = function(resultType, typeIndex) {GUTS};$scope.submitProductCategoryToAnalytics = function(productCategory, $event) {GUTS};$scope.submitSuggestionToAnalytics = function(suggestion, $event) {
GUTS
};
// ... omitted for brevity};

Do not be afraid to spell out everything. In this example. I wanted to write this directive as a story, a description, a meaningful roadmap from one step to the next.

Determining the name of whatever you are writing (file, method, function, variable, class, namespace, etc.) should be the most important thing you do before you add the ‘guts’. In the same manner, it should also be the easiest thing to do!

Need a function expression that determines if a loading screen should be visible?

  shouldShowLoadingScreenOnStart

Have an array of objects which has color mappings?

colorMappingsArray //Adding "Array" for duck-typed langs

Need a NSValueTransformer subclass which converts true to red and false to black?

SLBoolToRedColorValueTransformer

Once you can describe your feature, type it out!

// My variable stores local user sessions
var localUserSessionArray;
// My function executes as a callback to a successful ajax response which is for my news feed.
var newsFeedResponseWasSuccessful = function(responseObject) {
//...
}
// What if its just my late night news feed?
var lateNightNewsFeedResponseWasSuccessful(responseObject) {
//...
}

Why DAMP?

Your Code stops becoming ‘Code’

Have you looked up “code definition” on Google lately? This is the first definition you find on one of their fancy cards:

Maybe Google’s trying to send a message about their code…

When you fail to describe what your code is trying to accomplish, then I suppose you really writing ‘code’. But when you write DAMP code, you tell a story.

Your ‘Code’ (Story) Becomes Supportable

Before using Descriptive and Meaningful Phrases, I found that I was always called back in to assist coworkers change or modify the code I wrote. I found I wasted more time describing what my code does to other when I could have baked it right in. When you develop in the DAMP philosophy, people won’t have to rely on your secret decoder ring to add a new function or variable. DAMP cracks the cipher, and saves everyone time.

You write less!

With Descriptive and Meaningful Phrases, you make code comments obsolete! If you are telling your story in the code, there’s no need to explain it elsewhere. If you added a comment above every function or method in your projects code, you could be cutting the total size in half by using DAMP.

So why did Objective-C make me realize this?

Objective-C/Cocoa are notorious for having extremely long method, property, and class names. This was so bizarre to me, until I realized, IT IS DAMP!

Take a look at some of the list of the longest Objective-C/Cocoa variable and name declarations. Here are some examples:

Method Names:

copyFromTexture:sourceSlice:sourceLevel:sourceOrigin:sourceSize:toBuffer:destinationOffset:destinationBytesPerRow:destinationBytesPerImage:

Interface Names:

AVCaptureManualExposureBracketedStillImageSettings
AVCaptureAutoExposureBracketedStillImageSettings
AVAudioEnvironmentDistanceAttenuationParameters
AVAssetResourceLoadingContentInformationRequest
MTLRenderPipelineColorAttachmentDescriptorArray
UICollectionViewFlowLayoutInvalidationContext

Property Names:

automaticallyEnablesStillImageStabilizationWhenAvailable
automaticallyConfiguresApplicationAudioSession
modalPresentationCapturesStatusBarAppearance
usesAirPlayVideoWhileAirPlayScreenIsActive

Longest Single Parameter Method:

navigationControllerPreferredInterfaceOrientationForPresentation:

So sure, it may not be a new concept, but in an age where we have compilers, minifyers, uglifyers, and obfusicators, we have no excuse for not telling our code’s STORY anymore!

--

--

Sean T. Larkin
Mutual of Omaha - Digital Experience and Design Team

@Webpack Core team & AngularCLI team. Program Manager @Microsoft @EdgeDevTools. Web Performance, JavaScripter, Woodworker, 🐓 Farmer, and Gardener!