Browsed by
Tag: OOP

Who do we write code for?

Who do we write code for?

Recently, while reviewing some code, I came across the snippet below.

Now a keen mind can spot many issues with this.

The ones I am referring to are something specific and relevant to the business though. The code is supposed to fetch all active clients, loop through, get job specifications from some DataSources defined for those clients, build a config object and return those values to calling function so that those jobs can be fired. Interestingly DataSourceInstance, DataSourceOriginConfig and DataSourceJobConfig definitions have nothing named as triggers, report or client_id_internal! Moreover, destination_params is a property of Client object, not of DataSourceJobConfig. I could not make heads or tails of it. To top it, I was told the code is already working and tested, review is just a formality (like it usually is in many places).

When I started digging through the code further, I found that getDataSourceJobConfig, was accepting list of dsConfigs, but instead of returning a list of jobConfigs it was enriching objects in dsConfigs and returning the same list. Further digging revealed that the same was being done in both the methods above. Effectively, all these variables were the exact same list of exact same objects, mutated in every call, were actually the list of Clients!

Now, I understand that JavaScript is loosely typed, you can modify objects on the fly without adhering to any defined structure. But because one can, does not mean one should. This code was so cryptic that I was forced to ask the question: “Who have you written this code for”, and the answer was unexpected, “the clients who are paying for it”. I gathered courage and asked again, “What do you hope to achieve specifying these steps in code”, this time the answer was expected: “So the program does so and so”.

This is a question I always loved when I first read Clean Code by Robert Marin (Uncle Bob). The answer takes some thought, but once you realise it, it all makes sense. We write code to tell our team members what we are trying to instruct the machine to do. The primary consumers of the code, even before the destined machine are the author and the peers who see, read, understand, refactor and maintain the code. If all one wants is for the machine to get the message, then one can talk in binary, computer languages are for people to convey to each other what they want the machines to do, along with instructing the machines.

To prove this point I have built a small snippet (and a cryptic language) and compiler. Here it is, can you guess what this code does:

Before you say it is invalid, gibberish and would just fail, let me assure you that every word in that snippet is useful, and has an appropriate meaning for what it is doing. If I were to compile this and execute it, it will work. In fact I used this snippet in a presentation to make this very point, when it worked, the output was even more confusing. Now I would be lying if I said that the compiler just compiled the java like file, it also did some transformations, like ‘afdrukken’ (Google Translate says that is dutch for ‘printing’) was being replaced with System.out.println, as if it was a function similar to python’s print.

The point I am trying to make is that instructions to a computer can be given is many ways, we use ‘Computer’ languages, with meaningful constructs and words so we understand what others are trying to instruct the computer to do.

Even before it executes, the code is read first by the writer, is read often by peers and so the goal of the code is to get the intent correctly across not only to the computers but also to other humans.

We code first for humans and then for machines.

Just another object-oriented approach to jQuery plugins

Just another object-oriented approach to jQuery plugins

It has been almost a year since I have been working primarily in JavaScript. During this time I have written three jQuery plugins and loads of other scripts.This is the story of how my approach to writing jQuery plugins has evolved.

I was working on my first plugin, which was supposed to be a large (in LOC) and went through the authoring mentioned on the jQuery site. In the beginning- it was great, a few exposed methods, well organized code, private functions, everything looked pretty. Soon the code reached some 1000 lines and it started becoming messy for me. To clarify, I am basically a java developer. I accept that the coding practices will obviously differ in every language, but for me, object oriented approach to code seems much more understandable and tidier than ‘functions everywhere’ thing!

I began searching for object oriented approaches people take in writing jQuery plugins. There are many, but mostly at the cost of some other flexibility. Some approaches allow only one public method, claiming only one namespace is must but more control was needed in the calendar. Some allow complete public access to the options object, but additional control was needed. There were one time calculations based on options that were necessary for the required functionality. Now making the options object public won’t give me that control, will it? But apart from that, I could not understand the requirement of making it fully public. Pardon me, this statement is not to question those who follow these approaches, but this is what was thought.

A better approach was needed, where all the flexibility of making it a ‘functions everywhere’ is retained and a little more organization is achieved in the code. So there emerged a merger. A merger that:

  • Allows multiple methods to be made available.
  • Claims only one namespace.
  • Does not make options simply public.
  • Keeps a context, maintains a state.
  • And follows every other requirement mentioned as a guideline while writing plugins by the jQuery authors.
That merger has now evolved into a simple, precise plugin template! All you need is a case-sensitive, replace-all and you are ready with a working plugin, set with the basic features ready for more, organized plugin…
Here’s the code:
/**
* Plugin comments
*/
(function($, undefined){
var MyPlugin = function(element, options){

/*
* *************************** Variables ***************************
*/
var defaults = {
defaultValue : '2'
}; //default options

/*
* *************************** Plugin Functions ***************************
*/

/*
* Initializes plugin.
*/
function initialize(options){
extendOptions(options);
sl.log("Got Options- initialize: ");
sl.log(options);
}

/*
* Updates plugin.
*/
function update(options){
sl.log("Got Options- update: ");
sl.log(options);
}

/*
* Destroy plugin changes
*/
function destroy(options){
// Remove all added classes.
// Remove all bound methods.

// Remove plugin data
element.removeData('myplugin');
}

/*
* Updates plugin options after plugin has been initialized.
*/
function setOptions(options){
extendOptions(options);
}

//expose plugin functions
this.initialize = initialize;
this.update = update;
this.destroy = destroy;
this.setOptions = setOptions;

/*
* *************************** Utility Methods ***************************
*/
/*
* Extend the default options using the passed options.
*/
function extendOptions(options){
if (options) {
$.extend(true, defaults, options);
}
}
};

var mP = $.myPlugin = {version: "0.01"};
$.fn.myPlugin = function(options){
var args = arguments; // full argument array passed to the plugin.

// Available methods in plugin
var pMethods = {
init : function(options){
// Get the plugin data
if (this.data('myplugin')) return;
// Initialize the plugin
var myplugin = new MyPlugin(this, options);
// Add plugin data to the element
this.data('myplugin', myplugin);
myplugin.initialize(options);
},
update : function(options){
// Get the plugin data
var myplugin = this.data('myplugin');
if (!myplugin) return; // do nothing if plugin is not instantiated.

myplugin.update(options);
},
destroy : function(options){
// Get the plugin data
var myplugin = this.data('myplugin');
if (!myplugin) return; // do nothing if plugin is not instantiated.

// destroy data and revert all plguin changes.
myplugin.destroy(options);
},
setOptions : function(options){
// Get the plugin data
var myplugin = this.data('myplugin');
if (!myplugin) return; // do nothing if plugin is not instantiated.

// Update the plugin options
myplugin.setOptions(options);
}
};

// For each element, check and invoke appropriate method passing the options object
return this.each(function(i, tElement){
var element = $(tElement);

if (pMethods[options]){
pMethods[options].call(element, args[1]);
} else if (typeof options === 'object' || !options){
pMethods['init'].call(element, args[0]);
} else {
$.error( 'Method ' + options + ' does not exist in jQuery.myplugin' );
}
});
};
})(jQuery);
Now what you need to get going is the replace-all, this is what you replace:

MyPlugin : PluginName
myPlugin : Plugin JQuery Method Name/pluginName
myplugin : Data Name/Variable Name
mp       : pN
pMethods : pluginNameMethods
defaults : defaulsObjectName

That’s it!
You are ready with a working plugin!
Oh yes, that sl there in the code is actually the SmartLogger. Read about it here.
This is a quick post and I plan to update the post with more explanation of the code, do visit again!

Let me know how you find it in the comments.