Code quality – the client’s view

Quality (1)From a coder’s point of view there are a lot of things that lead to high quality code. The ability to stay calm and focussed helps make good decisions on the code. Then there are things like readability, maintainability, the presence of unit tests. As a programmer who does a lot of work with other people’s code, those are important to me. I’m currently working on a Moodle site and there are times when the 1000 line functions and nested statements favoured by the Moodle programmer in a big hurry make my heart sink. It’s like trying to read a book that has no chapters, endless sentences and a confused maze of circular footnotes.

But from a client’s point of view, these are invisible behind the scenes things. What they worry about are the finished product. They ask questions like: does it work? How long did it take?

I’ve worked with many clients, ranging from large digital agencies with multi-million pound clients to small businesses needing a few upgrades.  Web sites are never finished, there’s always more work to be done. It’s an iterative process which is never finished, once you’ve finished something, it’s only a matter of time before it needs to be revisited and additional functionality written for it. I’ve found that in order to keep myself motivated and also to keep my clients focussed on keeping the site moving at a reasonable pace, I’ve needed to be very clear about outcomes.

When a client comes to me to ask for a bit of work, they often have a particular outcome at the back of their mind. Getting them to communicate that to me is often about asking the right questions. The questions I want answered are:

What is a good outcome for this bit of work, what will get this work signed off? It seems obvious to the client what the answer to this is but I find that this is an area where differences in expectations can generate difficulties later on. I had a client 6 years ago who wanted a beta release of his site. Generally, in software development, that means getting a site working in a basic way and then ironing out the bugs in a later phase. What he meant by beta was a final polished, pixel-perfect, bug-free version of the site. Not checking my assumption cost me a lot of extra hours working on the finished product.

When does it need to be finished by? There’s often a lot of haggling around this one because software development and time estimates can be a cause of a lot of stress for both client and developer. I was asked to refactor a site with 300,000 users about 4 years ago and when I took a look at the code, it was fairly obvious that there were considerable time pressures on the original build. There were lots of copy and paste bits of code and lots of signs of short cuts. The bitter (and somewhat unprofessional) comments in the code were also a bit of a giveaway.

Time is something that most of us have a bit of a fraught relationship with anyway and adding in delivering code can it can be worse. After a lot of experience, I have a more intuitive feel for time on delivering code. Sometimes, there’s something that doesn’t feel quite right about the timeline, and then it’s a case of going back and checking.

Just clearing up the assumptions that everyone has is a good thing. It can seem that I’m asking obvious, even silly questions. Yet it is worth it to get a clear idea of what is needed and the processes that need to be in place to make the work happen.

How can managers get high quality code from their programmers?

Quality Code

I’ve worked as a programmer for the last 15 years in many different environments, chilled out, busy, noisy, quiet and so on. These are some of my reflections on what produces good code.

What I want to do is write good quality code. After all, that’s what is going to keep my clients happy and get me paid.

There are lots of things that go into good quality code that can be measured, things like code formatting, code meeting certain useability tests and code being delivered within a certain period of time.

Then there are things which are more subjective. Those are things like code that is organised, code that flows, code that is easier to update or maintain. Often, code that is of high quality is code that has multiple and sometime opposing qualities. Code that is organised but has no other quality may suffer from an over complicated or rigid structure. Code that is organised but at the same time simple will have enough organisation to suit the purpose it was intended, not too much, not too little.

Then there is code which fits all the quality objective and subjective criteria but somehow it turns out that the coder has forgotten the end user of that code.

It is this last one that often undermines what could be good quality code and causes managers headaches. This can be a project manager’s headache, the highly skilled but somehow disconnected coder.

And it is the state of mind of the person who is producing that code that is the main topic of of this blog. Coders talk about ‘the zone’ or ‘being in the flow’ when they are writing good code. Of being aware of the big picture behind the code and at the same time being able to produce good details.

Every line of code ever written, directly or indirectly is produced by a human body with a mind attached. Being in the zone is the ability to be with your body and your mind at the same time. It’s being able to be with the highly abstract thought processes that are the act of writing code without becoming disconnected from yourself and the environment which is producing that code in the first place.

What produces ‘the zone’ for coders? Well, there’s lots and lots of variation in that because everyone is different. For every coder who needs silence to get there, there are others who find it while having their favourite German heavy metal band on in the background. Some love the give and take of the open plan office, others find their flow severely disrupted by being around other people.

Ideally, there would be a discussion about what was best for any particular coder and the organisation that is paying their fee.

In my experience, this discussion rarely happens and when it does, it revolves around the perceived needs of the organisation. It usually happens at the time the coder is hired and is generally a reactive one, it’s about what happened in the past being prevented in the future.

Is it possible to have a discussion about this which facilitates high quality code and also meets the needs of both coder and organisation? Of course, this happens all the time. Here’s what I think needs to be on the table

  • What are the requirements of the project / work? If this isn’t understood by either then it’s very difficult to get to the next part.
  • What are the needs for connection and contact for this project / work? Every project needs a connection between the coder writing the code, other team members, project managers and the customer for the code. How often does there need to be a connection and how long?
  • What’s the best way to maintain positive feelings of respect, connection?

In fact, it doesn’t really matter what the topics are as long as there is a discussion.

What’s your experience of managing or recruiting coders when it comes to getting a high quality result?

Moodle Unit Testing with PHP Unit

I need to do some unit testing on Moodle 2.8 with a version that was pretty difficult to work on because of all the hacking of the core that had been done.

cd /mymoodle_install/public_html

#Run composer and install packages into /mymoodle_install/public_html/vendor
composer update

#Update the /mymoodle_install/public_html/config.php with test settings
$CFG->phpunit_prefix = ‘phpu_’;
$CFG->phpunit_dataroot = ‘/mymoodle_install/my_unit_tests’;

$CFG->phpunit_dbtype = ‘mysqli’; // ‘pgsql’, ‘mariadb’, ‘mysqli’, ‘mssql’, ‘sqlsrv’ or ‘oci’
$CFG->phpunit_dblibrary = ‘native’; // ‘native’ only at the moment
$CFG->phpunit_dbhost = ‘127.0.0.1’; // eg ‘localhost’ or ‘db.isp.com’ or IP
$CFG->phpunit_dbname = ‘test_db_name’; // database name, eg moodle
$CFG->phpunit_dbuser = ‘test’; // your database username
$CFG->phpunit_dbpass = ‘testpass’; // your database password

# Initialise the database
php admin/tool/phpunit/cli/init.php

#This failed as I was running MySQL 5.7.10 so I needed to change lib/dml/mysqli_native_moodle_database.php line 184
$sql = “SELECT @@storage_engine”;
#To
$sql = “SELECT @@default_storage_engine”;
# And change
$engine = $rec[‘@@storage_engine’];
# To
$engine = $rec[‘@@default_storage_engine’];

#Go to PHPStorm, bring up preferences (Mac), settings (Win)
Languages & Frameworks > PHP > PHPUnit

Use custom autoloader
/mymoodle_install/public_html/vendor/autoload.php

Test Runner
Tick ‘Default configuration file’
/mymoodle_install/public_html/phpunit.xml

Everything worked fine although the installation of Moodle that I was using was pretty broken and needed multiple updates to get the test database installing without errors.

One of the errors I needed to fix was code like this

SELECT c.id, c.fullname, c.summary from mdl_course c
                        INNER JOIN
                        mdl_block_course_bookmarks b ON c.id = b.seid

This caused a problem because using the full name of the table in SQL meant the unit test database was not able to find the right table (which would have been something like phpu_course). The correct way to do this was

SELECT c.id, c.fullname, c.summary from {course} c
                        INNER JOIN
                        {block_course_bookmarks} b ON c.id = b.seid

Moodle block ordering

Moodle has many ways to set the order of blocks on the page.

The easiest way is through the default weight variable

Moodle block admin page

 

 

There are other ways to set this, one is through the

$CFG->defaultblocks_site

variable which appears in the config.php

Recently I had to change the order of a block and found that changing the display order through the block admin tool just didn’t work at all. After some searching, I found that it had been set in the theme in theme/<mytheme>/renderers/core_renderer.php

/**
 * Gets the blocks for the side region
 * @param $region
 * @return string
 * @throws coding_exception
 */
public function blocks_for_side_pre($region) {
    $blockcontents = $this->page->blocks->get_content_for_region($region, $this);

    //Sort the blocks in defined order by closure variable $titles
    usort($blockcontents, function ($a_block, $b_block) {
        $titles = array('Block 1', 'Block 2', 'Block 3', 'Administration','Another block');
        $a = array_search($a_block->title, $titles);
        $b = array_search($b_block->title, $titles);

        if(is_numeric($a) && is_numeric($b)){
            if($a > $b) {
                return 1;
            } else {
                return -1;
            }
        }
        return 0;
    });
    $blocks = $this->page->blocks->get_blocks_for_region($region);
    $lastblock = null;
    $zones = array();
    foreach ($blocks as $block) {
        $zones[] = $block->title;
    }
    $output = '';

    foreach ($blockcontents as $bc) {
        if ($bc instanceof block_contents) {
            $output .= $this->block($bc, $region);
            $lastblock = $bc->title;
        } else if ($bc instanceof block_move_target) {
            $output .= $this->block_move_target($bc, $zones, $lastblock, $region);
        } else {
            throw new coding_exception('Unexpected type of thing (' . get_class($bc) . ') found in list of block contents.');
        }
    }
    return $output;
}

My favourite new Laravel 5 feature: Events and event listeners

Laravel 5 has been out for a while now and I’ve had a chance to write some code using all the new features. So: what stands out as my favourite feature so far? The answer is events and event listeners

In Laravel 4 you might see some code in the controller like this:

public function processContact(Request $request)
$user = new Student();
$workshop = $event->getWorkshop();
if(!$user->isStudent($Input::get('name'),$event->getRequest()->get('email'))){
    $user->fill($request);
    $user->status = 'C';
    $user->profile = $this->getProfile($request);
    $user->save();
}else {
    $user = $user->getByEmailAndName($event->getRequest()->get('name'),$event->getRequest()->get('email'));
}


if(!$user->isRegistered($user->name,$user->email, $workshop->id)){
    $user->workshops()->attach($workshop->id, ['sign_date'=>date('Y-m-d H:i:s')]);
}
 return $this->getView('contact_done');
}

In Laravel 5, it’s been tidied up so you can do this:

public function processContact(Request $request)
{
    $this->validate($request, [
        'name' =>'required',
        'email' => 'required|email',
        'comments' => 'required'
    ]);

    Event::fire(new ContactEvent($request));

    return $this->getView('contact_done');
}

All the event code in this example has been moved to a ContactListener class

Laravel Multi-tenant multi-site setup

Recently I needed to create multi-tenant set up in Laravel. I had an existing site which was running on a url. The client wanted a new site with a separate database with a different url. I could have just cloned the existing site and used it but that would have meant 2 separate code bases. Instead, I decided to have 2 databases and one code base. I found some useful documentation at:

https://medium.com/laravel-4/laravel-4-multisites-26cdc75e4810#.yeqca98z2

  • Set up new site in Nginx
  • Create config folder called construction (the site was running under a url with something like construction.myurl.com
  • Create folders for new site  with bootstrap folder
  • Sym link folders from main site
  • Created database
  • Created a new file bootstrap/environment.php
  • Update bootstrap/start.php
$env = $app->detectEnvironment(function() use($app){

    if(isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST'] == 'construction.myurl.com'){
        return require '/pathtosite/construction/bootstrap/environment.php';
    }

    if(file_exists( __DIR__.'/environment.php')){
        return require __DIR__.'/environment.php';
    }

    return $app->detectEnvironment(array(
        'local' => array('localhost.localdomain','localhost')
    ));

});


Everything worked out fine.

I then created a new config file called config/site.php and config/construction/site.php which contained all the site specific strings that I needed.

Working with the PHP Laravel Framework

laravel-logo-bigI’ve worked with Laravel for about a year and half now and it’s the third PHP framework I’ve  learned so far (the others are Code Iginiter (2 projects) and Zend (1 project).

So, what’s to like about Laravel and what are the niggles?

As a coder, there’s lots to like about Laravel. The code is clean and well written. It follows all the best Object Oriented practices, uses patterns and is generally easy to read.

Niggles: It’s definitely the pet project of the guy who created it, Jeffrey Way. That means whatever he decides goes. Expect some quite quirky bits of code.

The main niggle, which also happened with Zend, is the project structure has changed in a way to make an upgrade really complicated. With Zend, the upgrade from Zend 1.2 to Zend 2.0 meant that you had to substantially re-write your project. This was a major annoyance on lots of levels. It increased the cost to the client and it also meant I had to learn Zend again.

Having written a fair amount of code in Laravel 4.2 for a client, I took a look to see if I could easily update it to Laravel 5.1 Answer, not at all. I took nearly a whole day to experiment on this and only managed to get some basic pages up.

I’ve written a simple Laravel 5 project to demo my code. There wasn’t that much to relearn once I had got used to the project structure. The major thing I can see is the addition of middleware.

Laravel is still a great framework to work with and I look forward to doing further work on it.

Auto Deleting Gmail emails after 4 days

I’m working on a project that needs an external MySQL backup sent to an email address as an attachment. This is all working fine. I needed to install mutt on the server and then add this to the successful back up

echo "Hi, This is the database backup" | mutt -a /backups/mysql/a.sql.gz -s "Database backup" -- a@b.com

I needed to set the /etc/Muttrc set copy=no, otherwise I was getting an error message and the database wasn’t sent

This is going to result in the gmail inbox getting pretty full so I set up a script to delete all emails older than 4 days.

First I went to http://www.google.com/script/start/ to create a script. I created a blank project and copied the code below. I saved the project and then went to Resources -> current project’s triggers. I set the script to run every 12 hours and that meant that there were some current database backups if anything should happen to the server.

/**
* Adapted from http://www.addictivetips.com/web/set-gmail-to-auto-delete-emails-older-than-a-set-number-days/
*/
function cleanUp() {
   var delayDays = 4 // Enter # of days before messages are moved to trash
   var maxDate = new Date();
   maxDate.setDate(maxDate.getDate()-delayDays);
  //var label = GmailApp.getInboxThreads();
   var threads = GmailApp.getInboxThreads();//label.getThreads();
  for (var i = 0; i < threads.length; i++) {
    if (threads[i].getLastMessageDate()<maxDate)
   {
     threads[i].moveToTrash();
     Utilities.sleep(500);
   }
  }
}

Installing Redis to use as Laravel 4 cache

The following commands will install redis on a server running CentOS 6.4.

First, install the epel repo

sudo rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm 

Next, install the remi repo

sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm 

Now, you should be able to install redis using the yum package manager.

yum install redis -y http://codybonney.com/installing-redis-on-centos-6-4/
http://codybonney.com/installing-redis-on-centos-6-4/

mkdir /usr/share/redis
cd /usr/share/redis
git clone https://github.com/ErikDubbelboer/phpRedisAdmin.git
cd phpRedisAdmin
git clone https://github.com/nrk/predis.git vendor
ln -s /usr/share/redis/phpRedisAdmin /vagrant/public/redis

in local/config/database.php

'redis' => array(
'cluster' => false,
'default' => array(
'host' => '127.0.0.1',
'port' => 6379,
'database' => 0,
),
)
'driver' => 'redis',
  • Find out the name of service’s script from /etc/init.d/ directory e.g. redis
  • Add it to chkconfig
    sudo /sbin/chkconfig --add redis
  • Make sure it is in the chkconfig.
    sudo /sbin/chkconfig --list redis
  • Set it to autostart
    sudo /sbin/chkconfig redis on

					

Solving problems with Javascript and IE8

I had a strange problem, a jQuery plugin was not showing up in IE8.

When I checked in IE11, no issue but when I went into IE8 mode, the plugin didn’t seem to run.

After some experiments, I realised that IE8 wasn’t actually loading the Javascript I had written.

The solution?

Change my Javascript tag from

<script type=”application/javascript”>

to

<script type=”text/javascript”>