Showing posts with label Chris Kobrzak. Show all posts
Showing posts with label Chris Kobrzak. Show all posts

Monday 16 May 2016

"There, and back again" (or: I suck at JavaScript sometimes)

G'day:
Sometimes I think I'm OK at JavaScript (well: I guess I'm OK at it [he says, whilst seesawing his hand]), and then sometimes I put this to the test and conclude I'm actually a bit shit. In this episode, I cover the journey from former to latter.

Important note:

Given the nature of this article, most of the code in it is wrong, and I am in no-way advocating its usage. The raison d'ĂȘtre of the article is demonstrating bad / wrong / pointless code. Do not copy this code. Do not think the code in here is a solution to any problem you might have.

We've been trying to get coherence in our approach to JavaScript for years. But it always just seems to be a series of false starts, for one reason or another. But I still chip away at trying to improve things where I can. This tends to involve a lot of experimentation, and not much ground made.

A number of years ago we had my mate Chris Kobrzak on the team, and he'd migrated from being a CFML developer to being a dedicated JavaScript developer. This was excellent as he say to it we had a formal JavaScript coding standard, and actively mentored it. During his tenure I think all of us improved our JS no end. However his tenure was short, and he moved onto other challenges after a while. For one reason or another the role was never re-filled (although we needed it more than ever), and our progress on that improvement has stalled. I think we're all still a bunch better than we were then, but this is more down to repetition and attrition more than anything else.

One legacy that Chris left us was a formalised approach to defining JavaScript "classes", wherein we unified on the standard "prototype-based" approach. This won't seem like news, but we had several different variations of inline-objects / kinda-classes / wodges-of-procedural-code going at once. Basically each dev started a new file however they felt like at the time. Or sometimes in the middle of a file, change tactic / style.

The basic rules of the coding standard were:
  • acknowledge that JavaScript is OO but not in the sense we were used to (coming from CFML), and don't bother trying to pretend it's traditional OO by trying to do inheritance or non-supported stuff like that.
  • Namespace everything.
  • We emulated classes using  the prototypical function approach, with a consistency rule that the there was only one class per file, the file was named the same as the class, and the namespace of the class was reflected in the directory hierarchy.
  • Separate the definition of the class from the usage of the class, ie: in different files, indeed different directory trees.
  • Object methods were always added to the main function's prototype.
  • "Class methods" were added to the function directly.
An example of this might be:

var ns = ns || {};

ns.Person = function(firstName, lastName, dob, status){
    this.firstName = firstName;
    this.lastName = lastName;
    this.dob = dob;
    this.status = status;
};

ns.Person.capitaliseName = function(name){
    return name.replace(/(^|\b)([a-z])/g, function(match){return match.toUpperCase();});
}

ns.Person.prototype.getFullName = function(){
    return ns.Person.capitaliseName(this.firstName)
        + " "
        + ns.Person.capitaliseName(this.lastName);
};

ns.Person.prototype.getAgeInYears = function () {
    return new Date().getFullYear() - this.dob.getFullYear();
};

ns.Person.prototype.setStatus = function (status) {
    this.status = status;
};

ns.Person.prototype.getStatus = function () {
    return this.status;
};

ns.Person.prototype.toJSON = function(){
    return {
        firstName : this.firstName,
        lastName : this.lastName,
        fullName : this.fullName,
        dob : this.dob,
        status : this.status
    };
};


Don't worry too much about the code, but here we have a class for a Person which has properties firstName, lastName, date-of-birth, and status. We have object methods to get the person's full name; their age in years; plus set and get a status; and also a method for JSON.stringify() to use when serialising the object. The class also exposes a class method capitaliseName() which can be used for out-of-object situations where one just needs to capitalise a name, but doesn't need an object. The whole thing is namespaced (unimaginatively "ns" in this case) to keep our application's stuff away from other JavaScript stuff.

This file is called Person.js and is at something like /webapp/public/js/lib/ns/Person.js.

It could be used like this:

var person = new ns.Person("kiri", "te kanawa", new Date("1944-03-06"));
console.dir(person);
console.log(person.firstName);
console.log(person.lastName);
console.log(person.getFullName());
console.log(JSON.stringify(person));

console.log(ns.Person.capitaliseName("jean batten"));

var secondPerson = new ns.Person("georgina", "beyer", new Date("1957-11-01"));
console.dir(secondPerson);
console.log(secondPerson.firstName);
console.log(secondPerson.lastName);
console.log(secondPerson.getFullName());

secondPerson.setStatus("Active");
console.log(secondPerson.getStatus());

console.log(JSON.stringify(secondPerson));

Now I hasten to add that all the JavaScript code we're talking about here is client-side JavaScript, I perhaps shoulda mentioned that before. That said, I'm running it via node as the output is easier to copy/paste here:

{ firstName: 'kiri',
  lastName: 'te kanawa',
  dob: Mon Mar 06 1944 00:00:00 GMT+0000 (GMT Standard Time),
  status: undefined }
kiri
te kanawa
Kiri Te Kanawa
{"firstName":"kiri","lastName":"te kanawa","dob":"1944-03-06T00:00:00.000Z"}
Jean Batten
{ firstName: 'georgina',
  lastName: 'beyer',
  dob: Fri Nov 01 1957 00:00:00 GMT+0000 (GMT Standard Time),
  status: undefined }
georgina
beyer
Georgina Beyer
Active
{"firstName":"georgina","lastName":"beyer","dob":"1957-11-01T00:00:00.000Z","status":"Active"}

C:\src>

OK, so that demonstrates everything works A-OK, but also demonstrates something that tends to irk me with JavaScript: for the object methods to access the state of the object, the state needs to be public (accessed via the object's this reference). There's no sense of privacy to the object's properties, and it means all (shared) methods are also really public. In reality this is not often an issue, other than the fact sometimes we find ill-thought-out code battering into a property directly instead of using the class's API. This is a non-theoretical issue: it has caused us problems in the past. Mostly with refactoring. It's always best to keep one's API "on point", as it reduces refactoring challenges.

And it just irks me. I also know I am not alone in this irkery.

One thing some of the bods at work have been looking at recently is YUI's Module Pattern, which kinda deals with the property privacy thing by leveraging closure. Outwardly this sounds all right actually, and when I only fleetingly looked at some example code it looked like the business for us. Here's a reimplementation of the above class using the traditional Module Pattern.

var ns = ns || {};

ns.person = (function(firstName, lastName, dob){
    var fullName = firstName + " " + lastName;
    var private = {
        status : undefined
    };

    var capitalise = function(name){
        return name.replace(/(^|\b)([a-z])/g, function(match){return match.toUpperCase();});
    };

    return {
        getFullName : function(){
            return capitalise(fullName);
        },
        capitaliseName : capitalise,
        getAgeInYears : function () {
            return new Date().getFullYear() - private.dob.getFullYear();
        },
        setStatus : function (status) {
            private.status = status;
        },
        getStatus : function(){
            return private.status;
        },
        toJSON : function() {
            return {
                firstName : firstName,
                lastName : lastName,
                fullName : fullName,
                dob : dob,
                status : private.status
            };
        }
    };
})("jerry", "mateparae", new Date("1954-11-14"));

And some calling code:

console.log(ns.person.getFullName());
console.dir(ns.person);

console.log(ns.person.capitaliseName("temuera morrison"));

ns.person.setStatus("governor general");
console.log(ns.person.getStatus());
console.log(JSON.stringify(ns.person));


And output:
Jerry Mateparae
{ getFullName: [Function],
  capitaliseName: [Function],
  getAgeInYears: [Function],
  setStatus: [Function],
  getStatus: [Function],
  toJSON: [Function] }
Temuera Morrison
governor general
{"firstName":"jerry","lastName":"mateparae","fullName":"jerry mateparae","dob":"1954-11-14T00:00:00.000Z","status":"governor general"}

C:\src>

OK, so this works, in that it hides the properties from the calling code. But - thanks to the IIFE approach - it just creates a one-off object. That's a pretty shit pattern, IMO: the "class" code is not at all reusable... if one wants a second person, one needs to repeat the code. It's also a wee bit shit cos if we want to change the state of any of the private values we need to call them something different from any argument name that might be used to pass-in the values. EG: one cannot do this:

setStatus : function (status) {
    status = status;
},

One needs to do this (or some variation on this, eg have an _status internal variable or something:

ns.Person = function(firstName, lastName, dob, status){
    var private = {
        // ...
        status : status
    };

    // ...

    return {
        // ...
        setStatus : function (status) {
            private.status = status;
        },
        // ...
    };
};

It's not the end of the world, but it's all getting a bit "let's pretend we can do some stuff that we actually can't".

I don't quite know what the thinking was here. We're not gonna be using this approach.

Tuesday 15 July 2014

2

G'day:
I'm frickin' lousy with dates (as in "calendar", not as in "romance". Although the same applies, from memory ;-). Well: remembering dates is never a problem, but remembering what the current date is is something I'm not so good at. I forgot to touch base with my big sister on her birthday over the weekend... and there's another anniversary on the same day.

I've been doing this bloody blog for two years now. Which is approximately 23 months longer than I expected it to last.


Last year I gave you some stats ("1"). I'll try to do the same now.

  • I've now published 750 (this'll be the 751st) articles. I still have about a dozen in progress. The same ones as last year, funnily enough. The topics just don't have legs, I think.
  • And the word tally is now up around 600000 words. So in the second year I didn't write quite as much as the first year (350000), but spread over more articles (428 in the last 12 months vs 322 in the first year).
  • I've had another 3000 comments since the previous year's 2000. That's pretty cool. Thanks for the contributions everyone. Often the comments are more interesting than the articles, I find.
  • Google Analytics claims I've had 86000 visitors over the last year (up from 25k in the first year). So this thing is getting more popular. The average per day is 230-odd. It was around 120/day in year one. It's still not a huge amount of traffic, but I guess my potential audience is pretty small too.
  • The busiest day in the last 12 months was 5 March 2014, with 593 visitors. That was towards the end of the isValid() saga, with this article: "ColdFusion 11: Thank-you Carl, Mary-Jo, many other community members and indeed Rupesh", and a click-chasing one entitled "CFML is dying. Let's drop it off at Dignitas". Looking at the analytics, that was the bulk of it, plus I was writing a lot about new features in ColdFusion 11 around about then, which boosted things. That was also my biggest week ever, by quite a margin.
  • The most popular article last year was the one about me migrating from "ColdFusion Builder to Sublime Text 2". That's had 2200 visitors. The next most popular were as follows:
  • The most +1'ed article was "I am one step closer to being unshackled from ColdFusion". It's interesting that that was the one that people liked the most. It had 13 +1s. Most articles get none or maybe one, so that's quite a lot.
  • Last year I worked out which article had the most comments. I have no idea how I did that, and I can't be bothered working it out again. So erm... that'll remain a mystery.
I've blogged a lot about ColdFusion 11 during the year... what with it being in public beta and then being released. I've also compared its functionality to Railo's equivalents. I've shifted my primary dev platform at home to Railo now. I've done a lot of JavaScript over the last 12 months (I've spared you most of the detail), but haven't progressed in other languages as much as I'd like to. That's my mission for the next year.

I battered Adobe a lot about how they (don't) handle their bugs. I will continue to do this. They're long overdue for an updater to ColdFusion 10, for one thing; plus we should have had at least a coupla small updates to ColdFusion 11 by now.

The biggest shift in my coding practices in the last year has been down to reading Clean Code, and adopting a lot of its suggestions. My code is better for it. I've got my colleagues Chris and Brian to thank for this... both the encouragement to read the book, but also keeping at me about it. Sometimes to great irritation on my part. If you have not read that book: do so. Especially if you're either of the two members of our team who still haven't read it. Ahem.

Another thing I've been fascinated with this year gone is TestBox. I love it. I am looking forward to shifting off ColdFusion 9 at work so we can start converting our MXUnit styled tests to BDD ones. Brad and Luis are dudes.

I've bitched a lot about Stack Overflow, but contrary to what I threatened ("Not that it will really matter in the bigger scheme of things..."), I still answer questions there every day (if I can find questions I can answer, that is).

Railo continues to rock. As do Gert, Micha, Igal from Railo. They really have done brilliant work keeping CFML alive and interesting.

A bunch of people have motivated me to write this year... it's too difficult to pull out a list of the main miscreants, but Sean would be the top. And the list of my various muses (or adversaries!) is - as always - on the right hand side of the screen, over there.

Gavin deserves special mention, as he very kindly tried to raise money to get me across to CF.Objective() ("Shamelessful plug"), but we had to kill that plan just as it was getting started ("Do not sponsor me to go to CF.Objective()"). But happily Gert stumped up with a ticket at the last minute ("Well that was unexpected"), so I made it anyhow. I really am taken aback by you guys. Seriously.

And of course Mike from CFCamp paid for my entire conference last year too ("CFCamp 2013"). That was amazing. And I mean both Mike's generousity, and the conference itself. Go to it this year if you can: CFCamp.

Ray's done most of the work for ColdFusion UI the Right Way, but I've helped out a bit. I'm glad we got going with that project.

Thanks for your participation in this blog, everyone. If you weren't reading it or commenting on it, I'd've chucked it in. But you keep coming back. Cheers.

Oh and let's not forget: <cfclient> sucks arse. And I can tell that without using it, Dave Ferguson ;-)

--
Adam

Friday 22 November 2013

CFML: Slightly interesting (?) but mostly pointless exercise with inline function expressions

G'day:
I was watching Blow-up and Dead Man Down with one eye on the TV screen and one eye on the code screen last night (actually all I have is a laptop, so it was different halves of the same screen, but hey), and I came to be thinking about some Ruby, and wondered how it could work in CFML.

Yesterday one of my colleagues (Chris) said something curious: that he doesn't "approve" of the ternary operator. I think it's a fine construct if used with caution... the caution being "the resultant code must still be easy to read" (so the same as with any code, really). IE, this sort of thing is fine:

result = randRange(0,1) ? "heads" : "tails";
writeOutput(result);

This, however:

H = (
    C == 0 ? null :
        V == r ? (g - b) / C :
            V == g ? (b - r) / C + 2 :
                (r - g) / C + 4
);

Is a shooting offence. Even if one only considers the ternary operator usage, and ignores the poor variable-naming (I lifted this from Stack Overflow: "A somewhat painful triple-nested ternary operator").

But I like the notion of having an conditional statement which is an expression.

In Ruby, everything is an expression, so every statement "returns" a value. Even an if statement. One can do this:

result = if Random.new().rand(0..1) == 1
    "heads"
else
    "tails"
end
puts result

In this case the value "returned" from an if statement is the last expression from within whichever of the true or false block was executed. So result ends up containing one of "heads" or "tails".

I thought it'd be handy to have an equivalent construct in CFML, where one could have an if() function, which would work like this:

result = if (randRange(0,1)){
    return "heads";
}else{
    return "tails";
}
writeOutput(result);

However this doesn't follow normal function syntax as it requires two code blocks (one for true, one for false), not just the usual one. So perhaps not completely straight fwd for the Railo or Adobe bods to implement.

Then it occurred to me... it's actually very bloody easy to implement in CFML, using inline function expressions. Here's a proof of concept:

function _if(required boolean condition, required function _true, function _false){
    if (condition){
        return _true();
    } else if(structKeyExists(arguments, "_false")){
        return _false();
    }
}

This mimics if / if/else. It's very straight forward really: instead of having blocks, it just takes a function or two, and calls one of them based on the results of the condition.

And an example calling of this using inline function expressions demonstrates the code kinda mimics an if() block visually, but it has the benefit of returning a value:

result = _if(
    randRange(0,1),     // condition
    function(){         // true
        return "heads";
    },
    function(){         // false
        return "tails";
    }
);
writeOutput("#result#<br><hr>");

One good side effect of this approach - and it's probably more handy than the construct itself - is that because the true/false blocks are functions, any function-local variables within them are indeed local to the function block itself, and do not pollute the calling scope. This would help keeping the variables-scope uncluttered in larger tracts of code. Demonstration:

scope = "calling code";

_if(
    randRange(0,1),
    function(){
        var scope = "true block";
        writeDump(var=[{variables=variables.scope}, {local=scope}], label="Within true block");
    },
    function(){
        var scope = "false block";
        writeDump(var=[{variables=variables.scope}, {local=scope}], label="Within false block");
    }
);

writeDump(var=[scope], label="Back in calling code");

This outputs:

Within true block - array
1
Within true block - struct
VARIABLEScalling code
2
Within true block - struct
LOCALtrue block
Back in calling code - array
1calling code

See how the function-local scope variable a) didn't interfere with the calling-code's variable; b) is gone after the function exits.

This could be beneficial.

JavaScript has a concept of  self-executing anonymous functions, which are handy for much the same reason. I've raised this as an E/R for ColdFusion, but it's been deferred: 3346435.

Continuing on this tangent, I figured I could perhaps contrive a looping construct too: one that works like a for() loop, but returns a value. And it was easy enough, using exactly the same technique:

function loop(function before, function condition, function afterEach, function body){
    if (structKeyExists(arguments, "before")){
        before();
    }
    if (!structKeyExists(arguments, "condition")){
        condition = function(){
            return true;
        };
    }
    while (condition()){
        var result = body();
        afterEach();
    }
    return result;
}

The arguments here mimic how an indexed for() loop works:
  • before() is called once at the beginning of the process;
  • condition() is checked at the beginning of each iteration;
  • afterEach() is called after each iteration;
  • body() emulates the code block.
Indeed it's slightly better than a for() loop in that it allows more than one expression in each of the first three arguments, whereas the native version only permits one.


Friday 26 July 2013

Recognising the people who help me with this blog

G'day:
Adam Tuttle (that's twice today) was quipping last that I'd mentioned him twice on the blog on Weds, and I should try for three times y/day (which failed: just the one mention, sorry). Anyway, as a joke back I said I should tag my articles with the people who I mention - these are usually people who have helped me, or caused me to write the article - and whoever is at the top of the list is automatically on my "give them beer next time I see them" list.

And then I thought... well why not? People do help me out and inspire me to write, and I appreciate it. So I did go through all my back articles last night, and tagged them up with the people I have mentioned in them, and I will continue to do so. So there are people's names listed at the bottom of the article on the "tags" bit, and the tag cloud thing on the right hand side also lists a bunch of people amongst the other tags I've got. Now there's been a whole swag of people tagged up, and the tag listing became unhelpful with every tag displayed, so you don't get a mention on the right unless you've got 3 mentions (or are Chris who only had two mentions until now, but as he wrote my most popular article, I decided to list his anyhow. And now he's got his third mention anyway).

Sean's currently at the top of the leaderboard, and there's a fair gap back to the rest of the pack.

Anyway... cheers y'all for your help along the way.

--
Adam

Thursday 18 July 2013

1

G'day:
I'm a bit late with this as it happened a week or so ago, but I just noticed I've been prattling away on this blog for a year now.

Apropos of nothing, here's some mostly useless information about this blog.

I said in one of my earlier articles that I've learned more about ColdFusion since I started this blog than I had in the preceding few years. This continues to be the case, and I've learned a bunch of good stuff about Application.cfc, ColdFusion regexes, JSON (grumble), REST, interfaces (in general, as well as ColdFusion's inplementation of them), and various other odds 'n' sods. Even some web sockets stuff, whilst troubleshooting that security issue from a coupla weeks back. I've also used Railo a lot more, and had a look at Coldbox. Beyond ColdFusion I've also started dabbling with PHP and Ruby. It's been cool! I hope some of it was useful to you, or at least slightly interesting. Or killed some time whilst you tried to decipher what I was wittering on about.

To close, I'd like to say special thanks to a few people whose participation in this blog has been helpful, interesting or thought-provoking. In no particular order, and it's certainly not an exhaustive list:
  • Chris Kobrzak
  • Sean Corfield
  • Andrew Myers
  • Bruce Kirkpatrick
  • Brad Wood
  • Andrew Scott
  • Adam Tuttle
  • Ray Camden
  • Gavin Pickin
  • Jay Cunnington
  • Simon Baynes
  • Duncan Cumming
  • Brian Sadler
There's been a bunch of great input / correction / sanity-checking / bullshit-detection done by a heap of other people too.  Cheers to everyone who's participated here.

And now on to year 2...

--
Adam

Monday 21 January 2013

Railo website on Raspberry Pi with a public facing domain hosted at home

G'day:

As promised on Twitter last week, here's Chris's article on getting Railo running on Rasperry Pi.

Over to Chris...



So you are a lucky owner of a sweet Raspberry Pi, you have a typical broadband connection, some ColdFusion language skills and you would like to take advantage of all these things and roll out a little Web site hosted at home, independently from any hosting provider, and make it available to your family, friends and the rest of the world? That's exactly what I've done and I thought I'd share a step-by-step guide on how my stack has been set up so you can give it a try, amend it and/or improve it.


The guide is inspired by an excellent article by Glyn Jackson on running Railo on Raspberry Pi that I found very useful when I started this exciting journey. However, the set-up described below differs slightly as the current version of Raspbian does not allow to install the official Oracle Java JDK and for that reason I'm going to opt for OpenJDK instead. And also, we don't need to worry about the SSH configuration as it's enabled by default in more recent versions of Raspbian.
Another deviation from Glyn's config is using a wired Internet connection rather than WiFi.

Prerequisites

  1. Standard broadband connection with a dynamically allocated IP address
    If you are in the UK, it can be BT, Virgin or any other popular async broadband option (and if you are lucky enough to have an Internet connection with a static IP address, you might want to skip the section covering Dynamic DNS).
  2. A router configurable to forward traffic on port 80 to a machine on the local network
    I tested it with an Apple TimeCapsule and a BT HomeHub but other routers should provide that functionality as well.
  3. Raspberry Pi (Model B) with 512MB of RAM
    I haven't tested it on the 256 model but you might like to do it at your own risk.
  4. An SD card with the Raspian GNU/Linux distribution installed on it
    A step-by-step guide covering this topic can be found on the eLinux site. You will need direct or SSH access to the box with root permissions.

Setup summary

Possible alternatives
HardwareRasbperry Pi 512MB RAM
Operating SystemGNU/Linux Raspbian
JREOpenJDK 1.6Oracle Java provided you are running a soft-float ABI distro (e.g. Debian) instead of Raspbian
Web serverLighttpdNginx
Application serverTomcat 7Jetty, Resin etc.
CFML serverRailo 4 jarsEarlier version of Railo, Open BlueDragon (not confirmed). Adobe ColdFusion is unlikely to run on such limited hardware.
Internet domain providerDNS DynamicThere is a number of alternative free and commercial services

Power

One of the great things about Raspberry Pi is its low power consumption which means having it always on should not ruin your home budget. I'm no expert on the electricity stuff but I'm powering my Pi through a USB cable hooked to the Apple TimeCapsule which acts as our home router and is always on anyway so that means there are two devices plugged to one wall socket. Does this configuration mean a decreased power consumption? I honestly don't know but it's certainly nice to have one extra power socket available.
In my case, the Pi is connected to TimeCapsule with two cables as the wired Internet connection is also coming from it (see the picture below).