Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Thursday, February 17, 2011

Good code, great code

When you do software development (or any other work for that matter), getting to the first 60% is comparatively easier than the rest 40%. The initial 60% work usual is bulk work, broad plans, overviews from 3000 feet high and all. But the more you cross that mark of broad planning and go into the details, work becomes art. The first lot is almost always science. The last part is true craftsmanship. This is something that any team must consider when they work on projects of any size where quality matters. Of course if you can pass your project with just coarse details then do not even bother to read this blog.

I have myself been programming with web languages (mainly PHP) for the last 7 years at least. Before that I had C, C++ in school and college. And even before that BASIC in lower classes in school. And it all started with LOGO when I was just 6 years old perhaps. Yes these many years and it still takes time to think through a large project. The initial outline comes within the first 30 seconds. But as I go deeper into the details, the architecture shifts. It is not always performance that you need to take care of. Code maintenance is also a big headache. You do not want to be stuck with code which is difficult to hand over to team members. That is basically dead code.

Also the modern stack of code for the web has changed dramatically. It has become a habit to think in terms of APIs. This enables loosely coupled architecture which is probably the best thing about the web itself. When designing web software though one thing I had to learn the hard way is that UI is most important. I have always thought of it, but still failed many times to stick to that rule. Slowly we have almost got to that point though and soon it will be better. But it is very essential to understand usability in user facing software. Code comes later.

A good software product is made of many components. Raw lines of code are just a part of it, very important ones though. But a very efficient data crunching tool will fail if it allows only XML files to be imported. People may have Excels, CSVs and what not. So it is most important to understand the audience. All these go in that ultimate great piece of code. In the end a product is also the packaging, the color, the logo, the manual that comes with it right? Same for software.

So from the next time you start a project by coding, think. Do the above points apply to it? If so try avoiding mistakes noted here. Go make some new mistakes :P

Tuesday, February 15, 2011

Templates with Mustache in JavaScript and PHP

For a long time I have used PHP as the template language with nothing else on top of it. No template engines ever. This was all fine till the point that we wanted a full AJAX UI in forums.com and also support basic view in non JavaScript mode. We also wanted to also change to a template structure which is more graphic designer or HTML developer friendly where only knowledge of HTML/CSS is needed. Thus we needed a logic-less no-frills template engine which has support in JavaScript and PHP at the minimum.

After searching a little we came across Mustache, a logic-less template engine with support in many more languages than we needed. But we were certainly happy to see support in Python and Scala, just in case... Well a brief look at the readme in JavaScript version and PHP version will tell you the story: it is damn simple.

Mustache supports Number, String, Array or Object like data structures as its data source (view). It can also check for Boolean and function returns. Well that is more than sufficient for our needs. The major benefit was not that though. If you continue using any PHP based template system which you may end up having some PHP logic stuff somewhere in your templates after a while. This happened to us and we hated it. Our design team obviously wants to keep templates to themselves and thus the need to move to very clean templates.

Now how do we deal with PHP and JavaScript versions? We make one file per module in our system. So say discuss.html for templates related to discuss (Gab) system. Similarly user.html and usermanage.html and so on. Each file contains multiple individual templates which correspond to the sub-feature being requested. These are separated by HTML comments. The files are read in by a PHP code and provided as PHP array of strings to the PHP rendering engine or as JSON array of strings to the JavaScript rendering engine. This rendering engine is not Mustache, its a layer on top of it, which collects templates and data (view in Mustache language) and then send them for rendering.

The major difference between the PHP and JavaScript version of rendering is the way the layout is built. In the case of PHP, every sub-template is parsed, every inch of data prepared and then actual Mustache rendering starts. All this is synchronous. Smaller parts are fed to larger ones as strings, and so on. So we use View Partials in Mustache. But in the case of JavaScript rendering it is a different world. We only render outer portions first. For partials we render them later and modify DOM to insert them back to the page once the partials are rendered. So this allows us to have partials request their own data in totally asynchronous manner which is what we wanted.

We are still in process of developing this whole system. Of course we threw away hundreds of lines of old code to put this new system in place. And much of utility has shifted to JavaScript mode only. Also the back-end now behaves more like an API which just server JSON/PHP arrays.

Monday, February 14, 2011

A simple clean good looking pagination

We are re-writing few base codes in forums.com and one of things re-written is the pagination logic. We needed something very simple, good looking, yet works.

The logic boiled down to having 9 slots in total for the pagination labels. First and last ones were fixed at page number 1 and n. They were labelled "First" and "Last" too. Then we chose to keep 5 slots around the current page. So if page 8 was selected, then the labels (and corresponding pages) were 4, 5, 6, 7, 8. This allows users to browse nearby pages. The rest two slots we simply divide equally on both ends. We fill the gaps between the segments with '...' which links to nothing (FALSE here).

If the current page was near the start or end then we simply print 5 slots in that end and put the rest remaining 2 slots at the other end.

If the total number of pages is 9 or less then of course no use of all this logic, simply print them serially.

Well that's it! Here is the code, we build an array of the pagination slots.
  if($num_of_pages > 9) {
    $pagination_slots = $num_of_pages > 9 ? 9 : $num_of_pages;
    $selected_slots = array();
    if($page > 3 && $page < ($num_of_pages - 3))
      $selected_slots = array_merge(array(2, '...'), range($page - 2, $page + 2), array('...', $num_of_pages - 1));
    elseif($page < 4)
      $selected_slots = array_merge(range(2, 6), array('...', $num_of_pages - 2, $num_of_pages - 1));
    elseif($page > $num_of_pages - 3)
      $selected_slots = array_merge(array(2, 3, '...'), range($num_of_pages - 5, $num_of_pages - 1));
    $pagination = array();
    $pagination[] = array('url' => '?page=1', 'title' => _('First'));
    if(count($selected_slots) > 7) {
      foreach($selected_slots as $s) {
        if($s == '...')
          $pagination[] = array('url' => FALSE, 'title' => $s);
        else
          $pagination[] = array('url' => '?page=' . $s, 'title' => $s);
      }
    }
    $pagination[] = array('url' => '?page=' . $num_of_pages, 'title' => _('Last'));
  } else {
    $pagination[] = array('url' => '?page=1', 'title' => _('First'));
    for($i = 2; $i < $num_of_pages; $i++) {
      $pagination[] = array('url' => '?page=' . $i, 'title' => $i);
    }
    $pagination[] = array('url' => '?page=' . $num_of_pages, 'title' => _('Last'));
  }