Tuesday, May 28, 2013

Web Performance Optimization, double blink of an eye

So last time I had managed to refactor my code and make it more structured by introducing a test framework. All was good, but something bad also happened.

My site (figment engine) got slow - this was not the fault of the testing framework, or the better structure of my code, it was because I took my eye of the ball.

Performance tends to fall away on any project as soon as you stop tracking it, a bit like test coverage or trousers without a belt. Unless there is a big ugly graph its easy for it to go the way of the dodo.

Earlier the site was delivery in about ~300ms (not quite the blink of an eye!), but after reviewing my progress yesterday - disaster! it was up to 700ms, this is an eternity in computing time - and much tooooo long, I was trying to target 100ms so this is going the wrong way!

So, what did I do? I was using a CDN, and my cache headers looked good. So I fell back on my personal performance mantra - the fastest way to do something is to not do it. So in WPO this means avoiding making requests - the following:

1. Convert my background image into a data URI, using an online tool this means the CSS changes from:
    background:transparent url(../pictures/crt.png) top left repeat;
to
    background:transparent url(data:image/png;base64,[lots of chars]) top left repeat;
this saves an additional request at the cost of always downloading the image data.

2. Inline my CSS, using M4 I can use a simple "include(assets/styles/main.css)" in the HTML to bring the CSS into the index.html. This saves another request, again at the cost of always downloading the CSS

3. (can you guess?) Inline my JavaScript, using M4 I can use a simple "include(assets/scripts/main.js)" in the HTML to bring the JavaScript into the index.html. This saves another request, again at the cost of always downloading the JavaScript.

The impact of these three tiny changes?


Document Complete Fully Loaded

Load Time First Byte Start Render Speed Index Time Requests Bytes In Time Requests Bytes In
First View 0.205s 0.135s 0.214s 200 0.205s 1 7 KB 0.258s 2 8 KB
Repeat View 0.062s 0.000s 0.050s 100 0.062s 0 0 KB 0.062s 0 0 KB

Yep, that's right - 200ms down from 700ms - and repeat views in a crazy 62ms!. Hitting refresh on this site I can't see the redraw!

The only fly in the ointment is that this test is running from the NL vs IE as the IE load tester is too busy. So this could invalidate my results if the NL test location is next to the CDN edge location in NL.

Probably the largest improvement here is caused by making less requests, and the overhead is acceptable as my site is a single page and the HTML/CSS/JS moves in lock-step.

I'm pretty happy with this gain, there are a few things I could do:
  • compress the content with gzip
  • minify the CSS/JS
  • put in place an async loader, which would give the same performance, but allow caching of seperate JS and CSS.
I'll probably leave performance alone for a few sprints, and focus on features - but I will keep an eye on the document complete time..

Monday, May 27, 2013

Technical debt paid down, and code better for it

Writing code without unit tests is not a fun place to be, so I've bitten the bullet and paid of the technical debt that was building. I've opted for QUnit as I've used it before and does not suck in other dependencies.


As I've written my tests I've rewritten the code base, which has driven out a better structure for the code in terms of Classes and separation of responsibility across the code.

To make the test harness as close to the live code as possible I used M4 to create a build time include. This allows me to reuse the same HTML across for the test harness, and hopefully avoid any differences in code base.

Although putting in a test harness and unit tests has not delivered any additional functionality, the code is in a much better place to accept changes. The weak point with the tests is user interactions, I expect I will have to face into this as well, though my preference would be to abstract any UI stuff out of the main code base (though it will still need testing!)

The other looming problem is performance, with the initial document complete time going from ~300ms to ~700ms. However I believe that the work I did with M4 could deliver some massive gains here, but that's for next time!




Document Complete Fully Loaded

Load Time First Byte Start Render Speed Index DOM Elements Time Requests Bytes In Time Requests Bytes In
First View 0.692s 0.243s 0.525s 560 33 0.692s 5 9 KB 0.700s 5 10 KB
Repeat View 0.262s 0.000s 0.289s 300 33 0.262s 0 0 KB 0.262s 0 0 KB

Sunday, May 26, 2013

Drawing in the browser: goodbye Applets, ActiveX objects, Flash, Silverlight. Hello canvas!

The latest set of changes for the Figment Engine revolved around making the interface resemble a terminal/console. Mainly accomplished by using a transparent png which is over-layed on the text interface. In order to make the text selectable I've actually under-layed the effect.


I've also added a graphical element (canvas), and used it to draw a simple "x" on a command being done. This was easy, and reminds me of the evolution in drawing in a browser: from Applets, ActiveX objects, Flash, Silverlight to finally the canvas object. The fact it works on my phone as well is such a leap forward - no more opaque object formats or run-times needed (phew!)


Sunday, May 12, 2013

Not quite the blink of an eye: 300ms vs 100ms

One of my key architectural considerations is how to make Figment Engine as fast as possible - really my goal is 100ms (the blink of an eye). Now of course this is a stretch target, its incredibly difficult to obtain and even more so for mobile users. At the moment its about 300ms and takes advantage of a CDN for everything.

The current design keeps the number of requests very low, and ultimately the assets of the page are quite small. I've avoided graphics of any sort so far (except favicon.ico).

I will need to compress files, especially the JavaScript as it grows and think about inlining some of the core CSS. I will also need to look at lazy loading, to avoid the first render being held up by downloads of assets that are not needed for that render.




Document Complete Fully Loaded

Load Time First Byte Start Render Speed Index Time Requests Bytes In Time Requests Bytes In
First View 0.342s 0.184s 0.299s 300 0.342s 4 6 KB 0.484s 4 7 KB
Repeat View 0.321s 0.000s 0.189s 200 0.321s 3 1 KB 0.321s 3 1 KB

Saturday, May 11, 2013

More code, but technical debt is building

So having fun adding the ability to cope with multiple commands in my command line interface - and since I know this is an early spike to get it moving I can do things that make the code functional, but also pretty ugly.

There's a few things already need fixing (some would argue I should have done them before doing anything, but I find it becomes a barrier if I try too early):
  • put some TDD in place, theres only ~80 odd lines of code so its still easy to do
  • make the code more structured (in JS land that means more objects)
  • separate the UI code from the logic code - so how to add a new command entry vs how to render it in HTML
One approach I like is not having lots of HTML element creation code, and a neat way round this is to clone an existing node - it probably should be a UI pattern in JavaScript. So in the example of a command line interface, where each new entry is very similar - rather than having lots of code to recreate the same structure each time: you can simply clone the first node at load time - and then clone that each time to add the same type of HTML item (with children). This also abstracts the HTML structure away from the code, so its easier to evolve the structure and appearance separate from the code. This approach can be generalized for most interfaces with multiple items that are the same (so notes, entities etc) - with the prototype UI object either being the first blank item, or hidden.

So next is probably a bit of refactoring for TDD - and I guess that means I need to find a good TDD library (and good for me means very simple and no dependencies on JQuery etc)

Friday, May 10, 2013

Writing code beats watching TV

So I've started to pull together some ideas, concepts and architectures - all of which I've pushed back hard on to just start building an MVP, trying hard to focus on something that does rather than something that is..

Amazingly I still managed to spend too long thinking of domain names, without a line of code written - I guess this is the curse of new ideas, spending too much time trying to find a unique name and (critically) domain name that reflects your idea - rather than working on the idea itself. Given a MVP approach this is pretty dumb, as its unlikely that what you envisage will be the final product anyway..

Each evening this week I've written some client-side portions, be it structure (html: 30 lines), style (css: 54 lines) and some behaviour (javascript: 43 lines) - all without any server side code. I like this approach as I can focus on the user experience (what it does for you), rather than how it does it. Of course soon I will need some server help to give me the system I want, but I'm happy to follow this route for now.

One of the slightly weird things about doing this has been looking at the TV and seeing that it offers little interest compared to writing code - its more interesting to create than consume, but still it surprises me.

I'm also super happy about the expressiveness of the modern platform, 127 lines of codes gives me a bare-bones CLI - of course the JavaScript needs refactoring, but its a start ;-)

finally I put the code into git, I kind of wish I did this from the first day - but I guess I was being lazy. now whats on TV?

Thursday, January 3, 2013

Xenon website

One thing I'm adopting from the start is to release as often as possible, even if its not even MVP.

So the first step is to get a base website up. http://xenon.figmentengine.com/ is the holding location, to make this work I've done a few things:
  • Used Git for source control (with GitHub)
  • Vim for editing
  • S3 for static site hosting
  • DYN for DNS (as figmentengine.com nameservers are DYN)
  • Used http://www.favicon.cc/ to create a favicon (to stop 404 errors)
Disclosure: I work for Amazon Web Services, this blog however is personal and does not reflect my employer's views. I will be using AWS services as I know them well (and used them before working at AWS).

Generally I'm planning to build most of the code myself, rather than relying on libraries etc - this will change as I need to focus on the core concepts.

I will also be keeping track of the page performance, so the base website benchmarks at
  • Load: 0.7s, TTFB: 0.29s, Start Render: 0.57s, Doc Complete: 0.7s, Fully Loaded: 0.7s
Next steps will be to put in place a CDN (CloudFront) to reduce global latency, and switch to Route 53 for DNS hosting. These two changes will also enable a slightly different approach to building websites, a mainly static website which is enriched with dynamic content.

Tuesday, January 1, 2013

Project code name 'xenon'

As with all my personal projects this one starts life with a name from the periodic table - this stops me spending too much time coming up with a name when I should be focused on the core idea.

However, my approach this time differs from my usual route, in that its much more undefined - I don't have a specific product in mind, or a defined end goal. It will however bring together a number of threads I've been thinking about for a number of years.

So watch this space for xenon featuring emergence, AI, visualization and an alternative computational model.

btw I do have a cool name for xenon, but I want to validate it matches what I actually build. My design is blank so far, so I don't want to create an artificial constraint.

Friday, April 27, 2012

TMUX on Amazon Linux (EC2)

Installing TMUX 1.6 on Amazon Linux: a fix if you get
cmd-load-buffer.o cmd-load-buffer.c
cmd-load-buffer.c: In function ‘cmd_load_buffer_exec’:
cmd-load-buffer.c:93: warning: implicit declaration of function ‘bufferevent_enable’
cmd-load-buffer.c: In function ‘cmd_load_buffer_callback’:
cmd-load-buffer.c:170: warning: implicit declaration of function ‘EVBUFFER_LENGTH’
cmd-load-buffer.c:170: error: dereferencing pointer to incomplete type
cmd-load-buffer.c:175: warning: implicit declaration of function ‘bufferevent_read’
cmd-load-buffer.c:183: warning: implicit declaration of function ‘evbuffer_add_printf’
cmd-load-buffer.c:184: error: dereferencing pointer to incomplete type
make: *** [cmd-load-buffer.o] Error 1 

Friday, December 23, 2011

Installing weighttp on AWS/EC2: ev library not found

when installing weighttp on AWS EC2 using the Amazon Linux AMI you might get errors such as:
  • "ev library not found." when running ./waf configure or
  • libev.so.4 not being found
This series of steps fixed it for me: