Jamie Balfour

Welcome to my personal website.

Find out more about me, my personal projects, reviews, courses and much more here.

Jamie Balfour'sPersonal blog

I'm currently working on a new website design for release in 2027 or maybe earlier. The current website design has been in place since 2017, but it is similar to the 2013 design. 

I never wanted a full-page website because my website serves so many purposes, and it's not just about that. However, I have considered the idea of having a personal website and a less personal one, or using subdomains for each. Alas, none of this has happened, and here I am contemplating a complete redesign. 

It has never been the case that I couldn't build a more modern look, but more that I wanted to keep my website the way it was. I'm not trying to sell something, but rather just provide something. If you look at some of the sites I have created for clients, you'd see that I do care a lot about form, not just function.

But my own website might even have this design in ten years' time, who knows - I have tried to change to a new design before, but always gone back to this design due to my love for the traditional design.

In the last few weeks I have been focusing on improving DragonDocs and DragonSlides interoperability. To that end, one of the things I wanted to do was reduce the number of file reads and writes, which have always been a risk for bottlenecking. As a result of the constant back-and-forth nature of reading JSON data for the API, the file reads are wasteful. Instead, I've decided to use APCu.

APCu allows me to store the JSON data in RAM rather than on the SSD storage. SSDs are fast, but RAM is considerably faster. There is a noticable improvement to the system as a result of this update too. 

It's sad that I have to move from Disqus after moving back to it only a few years ago, but Disqus decided to force ads onto the free tier when a website becomes busy enough. Because I'm now actively getting 6,000 to 8,000 visits a day, Disqus now force ads on to my website, which I think is totally unacceptable and not part of the original model of this website. As a result, I'm building my own comment system again. 

Please continue to use Disqus in the mean time.

Over the last few days, I have been working hard to update a range of products and services across my website. This list outlines the updates:

  • ZPE ZULE updater (the system used to distribute updates for ZPE) has been fixed and improved
  • ZPE 1.12.2 fixes the updater system for the new (faster update system)
  • DASH 2.0 updater has also been fixed on both the server and product
  • The online YASS runtime has been fixed
  • The system status service is now more streamlined

ZPE 1.12.2 will be released in the next few days to address the updater issue. It will require a manual download to update it.

This day in 2018 was the most significant in the history of my website.

The plan was formulated in late 2017 to refurbish my website performance in a huge way.

The first step was to replace DragonScript 3 with a much faster version called DragonScript IV. DragonScript IV allowed my website to handle up to 6 times more requests simultaneously (up to around 1 million requests).

The second step was inline optimisation and caching. My caching system is substantial across my website and relies on several different technologies, such as cron jobs used to clear and freshen caches, automated scripts to generate cached data and my analytics system to determine what needs to be cached. The inline optimisation feature is similar to the caching system on my website, and it's what ensures that all data transferred is compressed before it is sent. If you take a look at my gallery on my website, you'll see that all photos are watermarked. The watermarking is preprocessed and cached and then reread when it is needed. 

The third and final part of this was a bit more manual and required me to optimise other images and content across my website. 

The result was that my website went from loading in 100 milliseconds to around 10 milliseconds. 

balf.io is a new domain I aim to use as a nexus or portal to content on my website. For example, docs.balf.io is used to host documents from my website on a separate domain, and the main domain, balf.io, is a redirect site to make redirects easier and it uses the same URL redirect system as found on my website. 

In fact, the codebase for balf.io is entirely the same as my website. So the slide viewer on it uses DragonSlides and the document system on it is my DragonDocs. 

Some users of my website will notice that there has been a minor update to my website, bringing the version number up to version 4.3. 

The update to version 4.3 brings a new font, the Oswald font, mainly being used for titles. It also fixes an issue that hasn't really been addressed on the web with text with background clipping when the text reaches the next line - it does this by splitting the text by spaces into inline spans with a 'glowing' background. Please have a look at my title to see what I mean. 

This is the first change in a long time, probably some 4 years as Quicksand has been used almost everywhere. For fans of Quicksand like me, please do not fret, it's not going anywhere! 

Next font size, I'm taking the font size back down to 16px instead of 17px. I had this like this for a good few years but in recent years I moved away from the agreed standard size of 16px up to 17px. 

Some of these new changes actually also affect the slides hosted on my website as well. 

A few improvements have been made over the last few weeks in DragonScript as well. This should make the website smoother than before.

Otherwise, the rest of the website remains the same.

I've wanted to do this for a long time - a dedicated server! 

For the last five years, I've been running Jambour and all hosted websites using a VPS (virtual private server) with Digital Ocean - an absolutely marvellous company. Well, not any more! As of yesterday, most of my websites have been moved to my own dedicated server, sitting there in my office. 

There are massive benefits to this.

Firstly, cost. It's actually much cheaper for me to run a dedicated server in my house than to rent a virtual part of a server. Our prices were going up so much that we started off paying £7 a month for our virtual private server in 2018 and by the end of 2022, we were paying over £26.

Second, upgradability is much easier, we can provision a second system quickly which can run an updated operating system and be spinning up in less than a second of downtime.

Thirdly, security. Unlike using Digital Ocean, the only way to connect to the server is from within my house, there is absolutely no other way to do this.

Fourthly, performance is much higher. A dedicated system can have whatever performance you want. We've got a 12-core system as opposed to a 4-virtual core system. 

Fifthly, storage space. We have a whopping 256GB and 2TB of additional space available as opposed to 50GB. 

Finally, ownership. I now physically own the server and can shut it down or turn it on whenever I need to. 

I first introduced my tutorials back in 2012 when I began refurbishing my website. Since then they have become incredibly popular (I use a page visit counting algorithm that I have developed and I have noticed a huge spike in visitors to my reviews and tutorials over the last few months, with an average of around 500 visitors a day).

However, it struck me that in reality, my tutorials are not so much 'tutorials' but free online courses. I say this because when I look at say, my CSS tutorial, it doesn't focus on doing things in CSS like websites such as CSS Tricks does, but instead it focuses on giving a solid platform to build upon. For example, it teaches some of the core features like backgrounds and border-radii, but not more advanced things like the clearfix model or how to add gradient borders as I have been doing on my website.

From today on, these tutorials are now rebranded as my Courses and they will continue to be free, as with many of the resources I provide.

In the last few hours, I have been working on improving the information architecture and the URLs for my tutorials. For the last six or seven years the way the URLs to my tutorials have looked is like this:

/courses/web/css/1/2/

Now, with a bit of work, I've written a much more beautiful system, and that makes the URLs look like this:

/courses/web/css/using_css/

The new system uses URL rewrites alongside a clever automated (cron) generated JSON in which all of the titles are given friendly names:

JSON
[{
  "page_name": "What this tutorial is",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/1/1",
  "area": "1",
  "page": "1",
  "title": "what_this_tutorial_is",
  "friendly_path": "web/css/what_this_tutorial_is"
}, {
  "page_name": "What CSS is",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/2/1",
  "area": "2",
  "page": "1",
  "title": "what_css_is",
  "friendly_path": "web/css/what_css_is"
}, {
  "page_name": "Using CSS",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/2/2",
  "area": "2",
  "page": "2",
  "title": "using_css",
  "friendly_path": "web/css/using_css"
}, {
  "page_name": "Why CSS is used",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/2/3",
  "area": "2",
  "page": "3",
  "title": "why_css_is_used",
  "friendly_path": "web/css/why_css_is_used"
}, {
  "page_name": "Classes, IDs and tag selection",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/2/4",
  "area": "2",
  "page": "4",
  "title": "classes_ids_and_tag_selection",
  "friendly_path": "web/css/classes_ids_and_tag_selection"
}, {
  "page_name": "Display, positioning, floating and visibility",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/3/1",
  "area": "3",
  "page": "1",
  "title": "display_positioning_floating_and_visibility",
  "friendly_path": "web/css/display_positioning_floating_and_visibility"
}, {
  "page_name": "Width, height, padding, margins and overflow",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/3/2",
  "area": "3",
  "page": "2",
  "title": "width_height_padding_margins_and_overflow",
  "friendly_path": "web/css/width_height_padding_margins_and_overflow"
}, {
  "page_name": "Borders, box shadows, border radius and box sizing",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/3/3",
  "area": "3",
  "page": "3",
  "title": "borders_box_shadows_border_radius_and_box_sizing",
  "friendly_path": "web/css/borders_box_shadows_border_radius_and_box_sizing"
}, {
  "page_name": "Color, backgrounds, opacity and gradients",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/3/4",
  "area": "3",
  "page": "4",
  "title": "color_backgrounds_opacity_and_gradients",
  "friendly_path": "web/css/color_backgrounds_opacity_and_gradients"
}, {
  "page_name": "Font families, sizes, weights, variants, styles and alignment",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/3/5",
  "area": "3",
  "page": "5",
  "title": "font_families_sizes_weights_variants_styles_and_alignment",
  "friendly_path": "web/css/font_families_sizes_weights_variants_styles_and_alignment"
}, {
  "page_name": "Descendant selector",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/4/1",
  "area": "4",
  "page": "1",
  "title": "descendant_selector",
  "friendly_path": "web/css/descendant_selector"
}, {
  "page_name": "Child selector",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/4/2",
  "area": "4",
  "page": "2",
  "title": "child_selector",
  "friendly_path": "web/css/child_selector"
}, {
  "page_name": "Adjacenct sibling selector",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/4/3",
  "area": "4",
  "page": "3",
  "title": "adjacenct_sibling_selector",
  "friendly_path": "web/css/adjacenct_sibling_selector"
}, {
  "page_name": "General sibling selector",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/4/4",
  "area": "4",
  "page": "4",
  "title": "general_sibling_selector",
  "friendly_path": "web/css/general_sibling_selector"
}, {
  "page_name": "Universal selector",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/4/5",
  "area": "4",
  "page": "5",
  "title": "universal_selector",
  "friendly_path": "web/css/universal_selector"
}, {
  "page_name": "Attribute selector",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/4/6",
  "area": "4",
  "page": "6",
  "title": "attribute_selector",
  "friendly_path": "web/css/attribute_selector"
}, {
  "page_name": "An introduction to pseudo-selectors",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/5/1",
  "area": "5",
  "page": "1",
  "title": "an_introduction_to_pseudo-selectors",
  "friendly_path": "web/css/an_introduction_to_pseudo-selectors"
}, {
  "page_name": "Advanced CSS pseudo selectors",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/5/2",
  "area": "5",
  "page": "2",
  "title": "advanced_css_pseudo_selectors",
  "friendly_path": "web/css/advanced_css_pseudo_selectors"
}, {
  "page_name": "Shorthand CSS",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/6/1",
  "area": "6",
  "page": "1",
  "title": "shorthand_css",
  "friendly_path": "web/css/shorthand_css"
}, {
  "page_name": "Precedence and specificity",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/6/2",
  "area": "6",
  "page": "2",
  "title": "precedence_and_specificity",
  "friendly_path": "web/css/precedence_and_specificity"
}, {
  "page_name": "CSS rules",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/6/3",
  "area": "6",
  "page": "3",
  "title": "css_rules",
  "friendly_path": "web/css/css_rules"
}, {
  "page_name": "Optimising CSS delivery",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/6/4",
  "area": "6",
  "page": "4",
  "title": "optimising_css_delivery",
  "friendly_path": "web/css/optimising_css_delivery"
}, {
  "page_name": "Cross platform and browser compatibility",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/6/5",
  "area": "6",
  "page": "5",
  "title": "cross_platform_and_browser_compatibility",
  "friendly_path": "web/css/cross_platform_and_browser_compatibility"
}, {
  "page_name": "Server-side generated CSS",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/6/6",
  "area": "6",
  "page": "6",
  "title": "server-side_generated_css",
  "friendly_path": "web/css/server-side_generated_css"
}, {
  "page_name": "CSS and Sass",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/6/7",
  "area": "6",
  "page": "7",
  "title": "css_and_sass",
  "friendly_path": "web/css/css_and_sass"
}, {
  "page_name": "An introduction to responsive web design",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/7/1",
  "area": "7",
  "page": "1",
  "title": "an_introduction_to_responsive_web_design",
  "friendly_path": "web/css/an_introduction_to_responsive_web_design"
}, {
  "page_name": "Tablet and smartphone friendly CSS",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/7/2",
  "area": "7",
  "page": "2",
  "title": "tablet_and_smartphone_friendly_css",
  "friendly_path": "web/css/tablet_and_smartphone_friendly_css"
}, {
  "page_name": "CSS transform",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/8/1",
  "area": "8",
  "page": "1",
  "title": "css_transform",
  "friendly_path": "web/css/css_transform"
}, {
  "page_name": "CSS transitions",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/8/2",
  "area": "8",
  "page": "2",
  "title": "css_transitions",
  "friendly_path": "web/css/css_transitions"
}, {
  "page_name": "CSS counters",
  "category": "web",
  "category_name": "Web",
  "topic": "css",
  "topic_name": "CSS",
  "route": "/courses/web/css/8/3",
  "area": "8",
  "page": "3",
  "title": "css_counters",
  "friendly_path": "web/css/css_counters"
}]

On the front end, the page is found via its friendly_path value. To keep the order correct, the pages are not given a key. Although it would make it slightly faster to give them this key, it would mean that the order isn't correct any longer.

Changes to title names will actually break the system and any changes made will need to be followed by a running of the automated script (which happens every evening anyway).

I'm still testing this feature out, so if you find any bugs, let me know. 

Powered by DASH 2.0