<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Paul Anthony</title>
        <link>undefined</link>
        <description>Your blog description</description>
        <lastBuildDate>Thu, 26 Mar 2026 16:24:40 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Paul Anthony</title>
            <url>undefined/favicon.ico</url>
            <link>undefined</link>
        </image>
        <copyright>All rights reserved 2026</copyright>
        <item>
            <title><![CDATA[23 Opinionated Big Little Details]]></title>
            <link>undefined/articles/attention-to-detail</link>
            <guid>undefined/articles/attention-to-detail</guid>
            <pubDate>Wed, 11 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[The small details are what makes good go to great when building web applications.]]></description>
            <content:encoded><![CDATA[<p>Things that make a little big difference to user experience when building web applications.</p>
<ol>
<li>When a user gets their password wrong, and are using email to sign in, send an email with either a one time login URL, or a link to your forgot password flow.</li>
<li>If you ask for verification codes and the length is fixed, auto submit the form when the last one is entered. e.g. See <a href="https://www.codedaily.io/tutorials/Create-a-Segmented-Auto-Moving-SMS-Code-Verification-Input-in-React">Stripe SMS codes component</a></li>
<li>If you perform a password reset, and the user has verified their password twice - allow them to login from this screen, rather than redirecting to the login to ask them to fill details in again.</li>
<li>Show a caps lock warning on password fields</li>
<li>During signup, if you ask for an email first, perform a gravatar lookup to showcase their avatar and potentially fill in firstname / lastname. Other APIs are also applicable here to lower friction to signup.</li>
<li>Auto-focus the first input field on forms.</li>
<li>Display password rules before users receive validation errors, preferably with a live strength indicator.</li>
<li>On long forms, preserve  entered form data even if the session expires.</li>
<li>Allow users to toggle visibility of entered passwords and sensitive fields.</li>
<li>After errors, return focus to the first invalid field, and on mobile, auto scroll to it.</li>
<li>Trim accidental whitespace from email inputs.</li>
<li>Use appropriate keyboard types on mobile for specific fields (email, numeric code).</li>
<li>Allow swipe to close menus on mobile, using touch down events etc. rather than just tapping hamburgers.</li>
<li>Handle slow networks gracefully, and provide online / offline indication. Retry on failed requests.</li>
<li>If you email a user, ensure they know which inbox to check, many people have multiple inboxes.</li>
<li>Preserve filters and sorts. Users spend time configuring views. Respect them on next visit.</li>
<li>If you ask for country of birth. Use the users current browser settings to either appropriately find the most likely country, or at least start the dropdown close to it.</li>
<li>Long dropdowns, for the love of all things holy. Make them searchable</li>
<li>Provide feedback with 100-300ms.</li>
<li>Use verbs on buttons. If I see another button with &#x27;Submit&#x27; on it, I might scream.</li>
<li>Empty states should be educational. No reports? Create one now.</li>
<li>Modals are a design smell. Too many modals feel claustrophobic and interrupt flow.</li>
<li>Undo is often better than &#x27;Are you sure?&#x27;</li>
</ol>]]></content:encoded>
            <author>paul@webdistortion.com (Paul Anthony)</author>
        </item>
        <item>
            <title><![CDATA[Using WeasyPrint with AWS Lambdas and Python]]></title>
            <link>undefined/articles/weasyprint-with-aws-lambda</link>
            <guid>undefined/articles/weasyprint-with-aws-lambda</guid>
            <pubDate>Tue, 19 Aug 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Aws Lambda setup for Weasyprint]]></description>
            <content:encoded><![CDATA[<p>I&#x27;ve recently found quite a bit of joy with WeasyPrint. A Python package which produces top quality PDF documents simply by using HTML and CSS. My particular setup had WeasyPrint deployed in an AWS Lambda, where we took a previous stored JSON result, transformed it using Jinga into an HTML template, and finally stored the output on S3. But you don&#x27;t want to hear about that right? Lets get to the juicy details of getting it up and running on AWS.</p>
<p>First things first:</p>
<p>The lambda layer - WeasyPrint is BIG - I hit size limits with deployment, so having a separate layer built helped keep the size down.</p>
<p>The following repo <a href="https://github.com/kotify/cloud-print-utils/tree/master/weasyprint">Cloud Print Utils</a> was a useful resource in building the lambda layer out. This was a key part of the puzzle. Once you&#x27;ve output your lambda layer zip file, the rest is just hooking it up to serverless for deployment.</p>
<p>Once the lambda layer was built out I referenced like below inside serverless.yml - a layer builder was created in Github actions which pushed the artifact up.</p>
<pre><code>configValidationMode: warn // serverless deployment complains without this
provider:
  name: aws
  runtime: python3.12 // WeasyPrint needs 3.12
  timeout: 30
  tracing:
    lambda: true


functions:
  generatePdf:
    handler: handler.generate_pdf
    layers:
      - { Ref: WeasyPrintLambdaLayer }

layers:
  weasyPrint:
    name: lambda-weasyprint-layer
    description: WeasyPrint and its dependencies
    package:
      artifact: layers/weasyprint.zip
</code></pre>
<p>The lambda itself was relatively simple. The crux of it was this method. Return the PDF as bytes so it can be written to S3 via an S3Client. Weasyprint does the heavy lifting here.</p>
<pre><code> def generate_pdf(self, html_content: str, css_path: str) -&gt; bytes:
        try:
            css = CSS(filename=css_path)
            html = HTML(string=html_content, base_url=self.static_dir)
            return html.write_pdf(stylesheets=[css])
        except Exception as e:
            raise
</code></pre>]]></content:encoded>
            <author>paul@webdistortion.com (Paul Anthony)</author>
        </item>
        <item>
            <title><![CDATA[Irish Grid To Lat Long in Python]]></title>
            <link>undefined/articles/irish-grid-references-in-python</link>
            <guid>undefined/articles/irish-grid-references-in-python</guid>
            <pubDate>Sun, 07 Jan 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Converting Irish Grid references to WSG84 in Python. Made easy.]]></description>
            <content:encoded><![CDATA[<p>Recently I came across some datasets within the Open Data portal in Northern Ireland that required some manipulation of the data into something... a bit more usable.</p>
<p>The end goal was to map every single street light in NI, courtesy of this tweet from Wesley Johnston of NI road blog fame: <a href="https://twitter.com/niroads/status/1742885280569274471">https://twitter.com/niroads/status/1742885280569274471</a></p>
<p>Currently most of the datasets that you see listed will come with an Irish Grid reference system, which uses Eastings and Northings.</p>
<p>This is a different system to that in use elsewere in the UK, which requires some conversion. I initially had assumed that <a href="https://webapps.bgs.ac.uk/data/webservices/convertForm.cfm">this webservice</a> might do the job, but alas - no dice. The final Python code to take the dataset and perform the conversion is shown below.</p>
<p>Hopefully its of use to some of your poor souls currently having to wrangle the local Government Open Data datasets into something that you can plot on a Google or OpenStreetMap map.</p>
<p>Of note here, is the pyproj package, which takes the work out. The rest is reading the csv, and writing it back out.</p>
<p><a href="https://epsg.io/29903">https://epsg.io/29903</a> Irish Grid</p>
<p><a href="https://epsg.io/4326">https://epsg.io/4326</a> to WSG84</p>
<pre><code>import pyproj
import csv

def ingrs_to_latlng(easting, northing):
    crs_irish = pyproj.Proj(init=&quot;EPSG:29903&quot;)
    crs_wgs84 = pyproj.Proj(init=&quot;EPSG:4326&quot;)
    lng, lat = pyproj.transform(crs_irish, crs_wgs84, easting, northing)
    return lat, lng

def process_csv_file(input_file_path, output_file_path):
    with open(input_file_path, mode=&#x27;r&#x27;) as infile, open(output_file_path, mode=&#x27;w&#x27;, newline=&#x27;&#x27;) as outfile:
        csv_reader = csv.DictReader(infile)
        fieldnames = csv_reader.fieldnames + [&#x27;LATITUDE&#x27;, &#x27;LONGITUDE&#x27;]
        csv_writer = csv.DictWriter(outfile, fieldnames=fieldnames)

        csv_writer.writeheader()
        for row in csv_reader:
            easting = float(row[&#x27;EASTING&#x27;])
            northing = float(row[&#x27;NORTHING&#x27;])
            lat, lng = ingrs_to_latlng(easting, northing)
            row[&#x27;LATITUDE&#x27;] = lat
            row[&#x27;LONGITUDE&#x27;] = lng
            csv_writer.writerow(row)

# Replace these with your actual file paths
input_file_path = &#x27;your_input_file.csv&#x27;
output_file_path = &#x27;your_output_file.csv&#x27;

process_csv_file(input_file_path, output_file_path)
</code></pre>]]></content:encoded>
            <author>paul@webdistortion.com (Paul Anthony)</author>
        </item>
        <item>
            <title><![CDATA[The great AI API reckoning is only a matter of time.]]></title>
            <link>undefined/articles/the-ai-api-reckoning-is-coming</link>
            <guid>undefined/articles/the-ai-api-reckoning-is-coming</guid>
            <pubDate>Sat, 17 Jun 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Using AI APIs for your app? Probably not that smart a move for the future.]]></description>
            <content:encoded><![CDATA[<p>Using third party APIs is a fun way to add additional features and complexity to software. Although there are obvious benefits, strategically for any business this path almost always has inherent platform risks. Pretty much any developer worth their salt has experienced a rug pull or price increase from a third party that either renders their application useless or, at the very least, requiring something of a rewrite to re-enable that missing function.</p>
<p><a href="https://www.wired.co.uk/article/twitter-data-api-prices-out-nearly-everyone">The recent changes at Twitter</a> related to their API pricing is one such example, with Reddit very closely following suit - (<a href="https://512pixels.net/2023/06/two-peas-in-a-pod/">apparently inspired by Musk</a>). Both of these platforms right now have Network effects that mean they no longer need to provide comprehensive APIs to third parties. The data that the rest of us willingly provide for free is valuable, so why make it easy for others to grab that data and build on top of their service?</p>
<p>At their infancy APIs provide growth vehicles for many online businesses. Tweetdeck for example was born out of api provision for twitter, which was <a href="https://techcrunch.com/2011/05/23/twitter-buys-tweetdeck-for-40-million/">later acquired</a>. A metric ton of other apps across the web have historically integrated with the generous offerings via their API. However not every app which provides a new interface to a service meets a similar fate.</p>
<p>Many of you will have read this week that the stand alone client app Apollo for Reddit did not share such a <a href="https://www.reddit.com/r/apolloapp/comments/144f6xm/apollo_will_close_down_on_june_30th_reddits/">fairy tale acquisition ending</a>.</p>
<p>The developer APIs for Facebook prior to the Cambridge Analytica scandal were extensive and designed to do also provide additional growth for the service and many developers optimistically built applications on top of all these public apis, <a href="https://techcrunch.com/2018/07/02/facebook-rolls-out-more-api-restrictions-and-shutdowns/">before they got canned</a>.</p>
<p>Fundamentally, if an API is free or low cost, developers need to remember that they are often just a marketing tool to help reach the market.</p>
<p>Since the dawn of time this trend has been apparent. Business provides a shiny API, developers get a hard-on and build on top or it. Tons of applications using that api in turn help introduce a new audience to the app. Company turns API off, keeps the audience.</p>
<p>Which takes us neatly to ChatGPT and OpenAI. Can we guess what their strategy looks like at the moment?</p>
<p>And here we all are, expecting those most deliciously simple APIs to exist until the end of time. Now maybe I&#x27;m wrong, maybe I&#x27;m old and jaded, but given the <a href="https://twitter.com/tomgoldsteincs/status/1600196981955100694">API is a loss leader currently given the cost</a>, at the very least the pricing cog of pain at some point in the future is going to need turned. At its worst, it goes away completely having sucked the river of data dry in the process.</p>
<p>From their perspective the API is not only going to be a brand building exercise to reach the mass market but also one designed to ingest additional information and improve the underlying model. How many businesses are going to end up providing the keys to their Kingdom off the back of that? As the saying goes fool me once..</p>
<p>Thankfully many open source AI frameworks are out there providing alternatives and competition, which is undoubtedly helping at least for now to keep OpenAI on their toes, but for those blindly building on their platform without looking at the road ahead the great AI API reckoning is only a matter of time.</p>]]></content:encoded>
            <author>paul@webdistortion.com (Paul Anthony)</author>
        </item>
        <item>
            <title><![CDATA[Its time to stop building addictive experiences]]></title>
            <link>undefined/articles/its-time-to-stop-building-addictive-experiences</link>
            <guid>undefined/articles/its-time-to-stop-building-addictive-experiences</guid>
            <pubDate>Sun, 29 Jan 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[The race to keep us on screen 24/7 makes it harder to disconnect, increasing stress, anxiety, and reducing sleep. Its just not healthy.]]></description>
            <content:encoded><![CDATA[<p><a href="https://www.axios.com/2017/12/15/sean-parker-facebook-was-designed-to-exploit-human-vulnerability-1513306782">Speaking at an event in 2017</a> Sean Parker warned about the unknown societal consequences of widespread social media use, saying he had become “something of a conscientious objector” against social platforms.</p>
<blockquote>
<p>“The thought process that went into building these applications, Facebook being the first of them, … was all about: ‘How do we consume as much of your time and conscious attention as possible?’”</p>
<p>And that means that we need to sort of give you a little dopamine hit every once in a while, because someone liked or commented on a photo or a post or whatever. And that’s going to get you to contribute more content, and that’s going to get you … more likes and comments.”</p>
<p>It’s a social-validation feedback loop … exactly the kind of thing that a hacker like myself would come up with, because you’re exploiting a vulnerability in human psychology. The inventors, creators — it’s me, it’s Mark [Zuckerberg], it’s Kevin Systrom on Instagram, it’s all of these people — understood this consciously. And we did it anyway.”</p>
</blockquote>
<p>The proliferation of ‘retention’, ‘engagement’ and ‘time spent in product’ as valid business metrics are not in any way helping us to provide better experiences. Tying ourselves to these Pavlovian metrics is sailing digital products in the wrong direction and **its obvious that what is best at capturing our attention isn’t best for our well-being. &#x27;Happiness&#x27; and ‘Task Success’ may be harder to measure, but are infinitely more powerful metrics in building successful brands than engagement.</p>
<p>The race to keep us on screen 24/7 makes it harder to disconnect, increasing stress, anxiety, and reducing sleep. Our children are caught in an endless cycle of checking their phones incase they miss out. We are replacing relationships with ‘like streaks’. YouTube and Netflix autoplay the next algorithmically crafted video, even if it eats into our sleep. That’s not even beginning to go down the rabbit hole of what is going on with algorithmic content creation. From James Bridle’s article <a href="/@jamesbridle/something-is-wrong-on-the-internet-c39c471271d2">earlier this month that caught significant attention.</a></p>
<p>On Youtube: <strong><em>Disturbing Peppa Pig videos, which tend towards extreme violence and fear, with</em></strong> <a href="https://www.youtube.com/watch?v=f70ymlTt8ek"><strong><em>Peppa eating her father</em></strong></a> <strong><em>or</em></strong> <a href="https://www.youtube.com/watch?v=owm0ZgAVEWU"><strong><em>drinking bleach</em></strong></a><strong><em>, are, it turns out very widespread.</em></strong></p>
<p>In fact these sorts of engagement metrics are downright dangerous when abused and the Silicon valley giants have no interest in changing their approach. Algorithmic timelines designed to keep us glued to our devices have us smacked to the eyeballs on content consumption in a zero sum game of attention- whether it is healthy or not. Not only that, but these algorithms are also significantly impacting society.</p>
<p>How many of your have turned off notifications on the various social products that you use to sleep better, to concentrate, to stop you from picking up your phone whilst driving? Twitter’s notification timeline is a great example of how desperate these apps are for your ‘engagement’. The following is a quick list of the scenarios Twitter use when they send a notification:</p>
<ol>
<li>When someone you follow tweets after a while.</li>
<li>When someone you have engaged with frequently tweets something</li>
<li>When someone you follow retweets someone else.</li>
<li>When someone likes a tweet you were mentioned in</li>
<li>When two or more of your followers follow someone else</li>
<li>When someone retweets you</li>
<li>When someone likes something you tweeted</li>
<li>When someone @replies you</li>
<li>When someone follows you</li>
<li>When there is new ‘Highlight tweets’ of people you follow</li>
</ol>
<p>Facebook&#x27;s list of notification settings also speaks volumes. When a product is sending notifications for external activity that <strong>you are aren’t responsible for in any way</strong> it is a pretty good indicator of a dark pattern in UX design.
As gatekeepers during product development it is our responsibility to think deeply about the experiences we create and to consider whether they are positively impacting on our end users lives.</p>
<p>Anyone building digital products today should be taking a responsible stance towards building potentially addictive experiences. We need products built on true value, and genuine success of customers, not low barrier behavioural growth hacks that are damaging at best.</p>]]></content:encoded>
            <author>paul@webdistortion.com (Paul Anthony)</author>
        </item>
        <item>
            <title><![CDATA[Using Modernizr with Next.JS]]></title>
            <link>undefined/articles/using-modernizr-with-nextjs</link>
            <guid>undefined/articles/using-modernizr-with-nextjs</guid>
            <pubDate>Mon, 23 Jan 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Trying to get some feature detects in your Next.JS project?]]></description>
            <content:encoded><![CDATA[<p>So you need some Modernizr feature detects huh? I was struggling to figure this out specifically for a Next.JS project recently, and the following is how I solved it.</p>
<p>First of all, install Modernizr.</p>
<p>Either with yarn or npm.</p>
<p><code>npm i modernizr</code></p>
<p>Next step is install the NextJS plugin from: <a href="https://github.com/scottydev/next-plugin-modernizr">https://github.com/scottydev/next-plugin-modernizr</a></p>
<p>Add the plugin to your Next.JS config like so:</p>
<pre class="language-c"><code class="language-c"><span class="token keyword">const</span> withModernizr <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token char">&#x27;next-plugin-modernizr&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token function">withModernizr</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
reactStrictMode<span class="token operator">:</span> true<span class="token punctuation">,</span>
eslint<span class="token operator">:</span> <span class="token punctuation">{</span>
ignoreDuringBuilds<span class="token operator">:</span> true<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Add your Modernizrrc file like so:</p>
<pre class="language-c"><code class="language-c">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span>
<span class="token string">&quot;options&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token string">&quot;addTest&quot;</span><span class="token punctuation">,</span>
<span class="token string">&quot;setClasses&quot;</span><span class="token punctuation">,</span>
<span class="token string">&quot;prefixes&quot;</span><span class="token punctuation">,</span>
<span class="token string">&quot;domPrefixes&quot;</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string">&quot;feature-detects&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token string">&quot;svg&quot;</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span>
<span class="token punctuation">}</span>
</code></pre>
<p>In your _app.js dynamically load Modernizr on the fly:</p>
<pre class="language-c"><code class="language-c">function <span class="token function">MyApp</span><span class="token punctuation">(</span><span class="token punctuation">{</span> Component<span class="token punctuation">,</span> pageProps <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
<span class="token function">import</span><span class="token punctuation">(</span><span class="token char">&#x27;modernizr&#x27;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
export <span class="token keyword">default</span> MyApp<span class="token punctuation">;</span>
</code></pre>
<p>Boom. That should be all you need.</p>]]></content:encoded>
            <author>paul@webdistortion.com (Paul Anthony)</author>
        </item>
        <item>
            <title><![CDATA[Music for coding]]></title>
            <link>undefined/articles/focus-playlists-for-coding</link>
            <guid>undefined/articles/focus-playlists-for-coding</guid>
            <pubDate>Sun, 22 Jan 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Whilst some prefer total silence to concentrate, personally I find particular soundtracks work better when trying to get into ‘the Zone’ when writing code.]]></description>
            <content:encoded><![CDATA[<p>Whilst some prefer total silence to concentrate, personally I find particular soundtracks work better when trying to get into ‘the Zone’ when writing code. Thankfully, the web provides plenty of playlists freely for Spotify and other radio station alternatives to make getting up and going and back at it that bit easier. I’ve grabbed them here as links for safe keeping, the developers among you may find them useful.</p>
<p>Ambient Background Sounds
Sometimes ambient background sounds help to block things out and help you concentrate even better than complete silence. The below are a couple of options.</p>
<p>URL: <a href="http://www.rainymood.com">http://www.rainymood.com</a></p>
<p>Rainy mood does what it says on the tin, and is a loop of a rainy day / thunderstorm. It’s more of a white noise type soundtrack than it is anything else, but if you prefer simply listening to background sounds over music, its a pretty good place to start.</p>
<p>Perhaps the Sound of a Tropical Beach is more your thing? This Loop on YouTube is perfect for imagining desert island bliss.</p>
<p>URL: <a href="http://www.simplynoise.com">http://www.simplynoise.com</a></p>
<p>Simply Noise is a free online white noise generator, although there are some paid for tracks in there as well; (with a honesty payment policy so you can pay whatever you want) you will however need Flash player to hear them, at least on the website initially.</p>
<p>If you want to go down the slightly more involved root, Boodler is an open source soundscape tool that lets you mash together your own creation. Python geeks eat your heart out.</p>
<p>URL: <a href="http://brain.fm">http://brain.fm</a></p>
<p>One of my absolute favs online - brain.fm is a commercial service, with tracks that can very quickly put me into thinking mode. I&#x27;m a paid customer, and there&#x27;s not only Focus playlists, but also ones for Relaxation and Sleep.</p>
<p>Spotify PlayLists
Here are few Spotify playlists I’ve found on sharemyplaylists.com (a site solely dedicated to Spotify playlists) and have kept around:</p>
<p><a href="https://play.spotify.com/user/kyleballard/playlist/2GI6wbTjS4M4QHN8PbsIr0?play=true&amp;utm_source=open.spotify.com&amp;utm_medium=open">Coding Music – Uptempo Electronica, Tycho, The Crystal Method</a></p>
<p>A soundtrack for coding – Mixture of Electronica, Moby, Massive Attack</p>
<p>Deep Focus – Much more chilled, includes Explosions in the Sky, Six Parts Seven, Shoegaze and Post Rock instrumentals</p>
<p>Coding / Programming / Hacking Slashing – Kosheen, Massive Attack, Phantogram, Thievery Corporation</p>
<p>Post Rock Coding – 65 Days of Static, And So I watch you from Afar, Metavari</p>
<p>Instrumental tracks for Coding – Includes some of the brilliant Trent Raznor Score from the Social Network, (you know, if you fancy pretending you are Zuck for an evening)</p>
<p>Other / Misc.
Some other links I found on my travels if you can’t quite manage to find exactly what gets you in the swing.</p>
<p><a href="http://whitenoisemp3s.com/sounds-like/rain">http://whitenoisemp3s.com/sounds-like/rain</a></p>
<p><a href="http://musicforprogramming.net">http://musicforprogramming.net</a></p>
<p><a href="http://djbolivia.blogspot.co.uk/2011/04/music-to-code-by-volumes-1-3.html">http://djbolivia.blogspot.co.uk/2011/04/music-to-code-by-volumes-1-3.html</a></p>]]></content:encoded>
            <author>paul@webdistortion.com (Paul Anthony)</author>
        </item>
        <item>
            <title><![CDATA[An approach to better quality performant front end code]]></title>
            <link>undefined/articles/better-performing-code</link>
            <guid>undefined/articles/better-performing-code</guid>
            <pubDate>Sat, 21 Jan 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[If you are building a website of any decent size and with high traffic, there are a lot of things to consider when writing high quality frontend code.]]></description>
            <content:encoded><![CDATA[<p>If you are building a website of any decent size and with high traffic, there are a lot of things to consider when writing high quality frontend code for high traffic sites at scale. There’s a ton of things to consider for the rapidly evolving frontend stack before publishing a new a project, and my own practices have changed massively and improved throughout the years, so I thought I’d share some of the detail of my own approach. The following techniques, gotchas and dos and don’t are what I personally consider to be some of the best practice I’m using that delivers not only a better user experience, but more performant frontend code overall.</p>
<h1>Use semantic HTML elements.</h1>
<p>HTML5 brought with it many new elements that are designed to be more meaningful. For example</p>
<p><code>&lt;nav&gt; &lt;section&gt; &lt;article&gt; &lt;footer&gt;</code></p>
<p>and <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element">others</a> are now much more appropriate to use to give semantic meaning to your page than using <code>&lt;div&gt;</code> tags everywhere. These not only provide search engine robots with better understanding of your page architecture, but also make your code much more readable. In order to be backwardly compatible with IE 8, you’ll need to polyfill with <a href="https://github.com/aFarkas/html5shiv">HTML5 shiv</a>. Yes, IE8. Because not every market has the latest and greatest browser and if you are building on high traffic websites you have to worry about that. 1% of 1,000,000 visitors, is 10,000 people you are potentially missing out on. Yes, it may be 2018, but those browsers are out there and good frontend code progressively enhances and caters for older browsers when it makes sense to do so.</p>
<h1>Pick a CSS Framework.</h1>
<p>Modular CSS provides you with a way to reuse blocks of HTML and CSS, so before you get started pick a modular framework convention like <a href="http://getbem.com/">BEM</a>, <a href="https://github.com/stubbornella/oocss/wiki">OOCSS</a> or <a href="https://smacss.com/">SMACSS.</a> If you are building a site with more than a handful of pages, it doesn’t take long for CSS to become unmaintainable so sensible naming conventions and modularity are a must. Frameworks enforce those conventions that make you think deeper about the code you write.</p>
<h1>Write CSS with reuse in mind.</h1>
<p>Deeply nested overqualified selectors are also a code smell, not only do they suck for browser performance, (as the browser has to do several fetches over the DOM) but they add additional bytes to your load time and limit reusability. The best practise advise for your class selectors is to aim for two selectors deep at most.</p>
<h1><code>.widget section table tr td h1.widget-title { padding: 10px 20px; font-weight: bold; font-size: 2rem; }.widget .widget-title { padding: 10px 20px; font-weight: bold; font-size: 2rem; } </code>
Use a Module Loader</h1>
<p>Large applications often need to load core javascript, then additional page specific javascript for particular pages. My approach for this is typically to use RequireJS <a href="https://github.com/requirejs/example-multipage/tree/master/www/js/app">multipage</a>, although I’ve worked recently on a project that uses a <a href="https://www.viget.com/articles/extending-paul-irishs-comprehensive-dom-ready-execution/">modified version of Paul Irish’s code which is also pretty elegant.</a> The key here is, don’t load JS you don’t need for large applications until you need it, and load it on demand.</p>
<h1>Use Modular JS / AMD.</h1>
<p>Using Asynchronous module definitions (AMD for short) — provide a great way to write reusable javascript code. Once you are using RequireJS, it makes sense to go down the AMD route. Why AMD? AMD implementations allow developers to define dependencies that <em>must</em> load before a module is executed, so wave goodbye to function undefined errors that can result from Javascript executing in a more linear fashion. AMD implementations also load smaller JavaScript files, and then only when they are needed. Good reading <a href="https://addyosmani.com/writing-modular-js/">over here.</a> and here on the official requireJS site. I prefer this approach rather than CommonJS, for many of the reasons <a href="http://blog.millermedeiros.com/amd-is-better-for-the-web-than-commonjs-modules/">detailed here</a>. Essentially in my opinion AMD has much more flexibility on the lazy loading and dependency management front.</p>
<h1>Minify CSS / JS to trim the fat.</h1>
<p>JS and CSS should be optimised before being deployed to production, so setting your project up for that right from the get go with deploy scripts and well battle tested devops is a good way to ensure that the code you deploy is as trimmed of fat as possible. There are a few options for doing this on the server side. For Java, there’s <a href="https://github.com/wro4j/wro4j">WRO4J</a>, <a href="https://j-a-w-r.github.io/">JawR</a> <a href="http://www.julienlecomte.net/blog/2007/09/16/">YUI + Ant</a>. PHP you can use the <a href="https://developers.google.com/speed/pagespeed/module/">PageSpeed module</a> from Google. This is available on Apache and NGINX.</p>
<p>Lots of developers these days are jumping on Webpack as the defacto standard in frontend bundling and optimisation. However, with great power, comes great responsibility, it’s easy to end up bundling all your dependent modules into one file and spitting out a 1MB+ file even with production switches, particularly if you don’t know what you are doing with <a href="https://webpack.js.org/guides/code-splitting/">code splitting</a>. Webpack configuration is something of an art to get right, so if you are using it to do your compression of your code for production you need to be careful what options you employ, and work out if a module loader with post deploy compression will better suit your needs than a module bundler. Veera Sundar has a <a href="https://veerasundar.com/blog/2018/02/webpack-code-splitting-example/">nice hello world post</a> that is easy to follow on how to use Webpack with code splitting that explains the process and how to get your configuration right.</p>
<h1>Make it Validate.</h1>
<p>There was a time in Internet land when everyone and their dog explained the merits of HTML validation. Browsers today do a pretty good job of understanding badly formed HTML and for the record, it’s of <a href="https://www.youtube.com/watch?v=2XlKn6I9rSc">no benefit for SEO</a>. However there is something about valid HTML code that pleases me. It indicates that you are dedicated to your craft, attention to detail focused, and care about the multitude of browsers that may be chewing over your HTML. After all, if your HTML is valid, then there’s little excuse for an existing decent browser making a mess of your page, and you’ve also future proofed your application. It also makes your code that bit easier to maintain, and picks up any potential bugs that you might have unwittingly introduced.</p>
<h1>Only use JQuery when necessary.</h1>
<p>Less is more, particularly when loading sites on mobile 3G / 4G connections so getting rid of Javascript that isn’t necessary is an important frontend task. Whilst jQuery is well recognised and provides a useful layer over native javascript, it’s not needed on every project. See if you can get rid of it altogether on greenfield projects and swap in native JS instead.</p>
<h1>Don’t rely on JS to fix CSS problems.</h1>
<p>There’s often instances where you can solve frontend problems more efficiently with just CSS, for example, <a href="http://brm.io/jquery-match-height/">equal heights</a> can be solved with <a href="http://www.lottejackson.com/learning/an-equal-height-grid-using-flexbox">Flexbox</a>. Slide menus for navigation, again, <a href="https://codepen.io/marclloyd77/pen/gtypB">don’t necessarily need javascript</a> and can be performant into the bargain. Need a <a href="https://speckyboy.com/open-source-carousel-sliders-css/">slideshow</a>? Don’t automatically reach for the Javascript. Although some of these techniques rely on modern browsers, you can always bring your JS in afterwards to support the older browsers and move the execution and loading of those scripts out of the modern browser pipeline.</p>
<h1>Defer JS Loading when possible.</h1>
<p>By default JavaScript blocks DOM construction and thus delays the time it takes for your browser to first render. Scripts which are not critical to how your page displays on first render should be made asynchronous or deferred until after the first render. How do you do that? A bit like this:</p>
<p><code>&lt;script src=&quot;bundle.js&quot; async&gt;&lt;/script&gt;</code></p>
<p>Previously to move JS out of the critical rendering path in older browsers, we all used to script inject. However, that is no longer <a href="https://www.igvita.com/2014/05/20/script-injected-async-scripts-considered-harmful/">considered best practice</a>. Moving your JS loading to the footer, adding an ASYNC attribute to your JS should be sufficient to letting the page get on with its thing prior to your JS executing.</p>
<h1>Provide a Jank Free Experience.</h1>
<p>According to the site <a href="http://jankfree.org/">dedicated to getting rid of it</a>, jank is any stuttering, juddering or just plain halting that users see when a site or app isn’t keeping up with the refresh rate. Jank is the result of frames taking too long for a browser to make, and it negatively impacts your users and how they experience your site or app. It’s important that as front end developers we understand the causes, how to diagnose and how to resolve Jank issues when they occur to make the web as silky smooth as possible. 9 times out of 10, when I’ve experienced Janky behaviour, it’s typically been to do with direct binding to window scroll events without debouncing, inefficient fixed position CSS or non hardware accelerated CSS animations. Anyway, understanding how to diagnose this is something of an artform in itself, with much of the Chrome Developer tools providing lots of ‘under the hood’ diagnostics to assist with it. Some additional reading. [<a href="https://addyosmani.com/blog/making-a-site-jank-free/">1</a>] [<a href="https://calendar.perfplanet.com/">2</a>] [<a href="https://aerotwist.com/">3</a>]</p>
<h1>Use CSS Sprites to cut requests.</h1>
<p>Performance is important and every byte you can save downloading resources is money well spent, not only because of the bandwidth saving, but the overall performance of the site for end users. Sprites are a great way to cut down on HTTP requests, and speed up your site. All of the icons and smaller images on your site should be added to a single sprite, and then background positioning used with CSS to show the image. If you aren’t already familiar with it, the following CSS illustrates how that typically looks.</p>
<p><code>.icon{ background:url(sprite.svg); width:22px; height:22px; display:inline-block; } .no-svg .icon{ background:url(sprite.png); /\*fallback for rubbish browsers\*/ }.icon .twitter{background-position:0 0; } .icon .facebook{background-position:-22px 0;} .icon .pinterest{background-position:-45px 0;} .icon .linkedin{background-position:-67px 0;}</code></p>
<p>One resource I’m a big fan of which complements this technique is <a href="http://www.spritecow.com/">SpriteCow</a>, which does all the hard work of working out the position of your sprites and spits out some CSS for you.</p>
<h1>Use SVGs for scalable graphics.</h1>
<p><a href="https://modernizr.com/">Modernizr</a> is a thing of beauty, and I use it on pretty much every build. This allows me to serve SVG’s to browsers that support it, along with PNG’s to browsers that don’t. It’s also a great way to work out if you’ve got flexbox support or not. If you aren’t already aware (and you should be) Modernizr is a feature detect library that provides additional classes on the HTML element of your page that gives you the flexibility to do this. A bit like this:</p>
<p><code>&lt;html class=&quot;js no-inlinesvg video&quot; /&gt;</code></p>
<p>That means you can write CSS code like the below. One sprite is served to the browser that supports SVG, and another for those older browsers that will only show a PNG.</p>
<p><code>.myclass { background-image:url(&#x27;images/sprite.svg&#x27;); } .no-inlinesvg .myclass { background-image:url(&#x27;images/sprite.png&#x27;); }</code></p>
<h1>Provide double density PNGs for retina displays</h1>
<p>Double Density devices are becoming more and more widespread now, so often your PNGs are often going to look a bit ropey and pixelated on those devices. You should be serving an image twice the size, and detecting the high density devices with a media query and serving that.</p>
<p><code>/\* for high resolution display \*/ @media only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2) { .image { background: url(/path/to/my/highreslogo.png) no-repeat; background-size: 200px 400px; } }</code></p>
<h1>Use REM or EM for sizing.</h1>
<p>Great sites don’t dictate the font size for their viewers. Set a base font % on the HTML element in your CSS, then use REM units to set your typography to the correct size. If your design breaks when zoomed in the browser, then there’s px units used somewhere and the scaling won’t play nicely. Pixel density is one of the last things you can rely on with various user devices, so em-based units of measurement put the user back in control of legibility.</p>
<h1>Don’t use Icon Fonts</h1>
<p>Sorry all you fans of Font Awesome, but I’m not a fan. Required reading. <a href="http://technotes.iangreenleaf.com/posts/font-awesome-not-awesome.html">Part 1</a>. Required reading. <a href="https://cloudfour.com/thinks/seriously-dont-use-icon-fonts/">Part 2.</a> Oh and this:</p>
<ul>
<li>Font rendering is very inconsistent across platforms, so your icons can look pretty shit.</li>
<li>The overhead of download a ton of icon resources to use one or two icons makes no sense.</li>
<li>SVG support is sufficiently widespread, so the original rationale for using font icons no longer applies.</li>
</ul>
<p>Don’t use them, Icon Fonts are performance cancer. Consider embedding whatever icons you need in SVG sprites as mentioned earlier.</p>
<h1>Progressively Load Web Fonts.</h1>
<p>We’ve come a long way from <a href="https://en.wikipedia.org/wiki/Scalable_Inman_Flash_Replacement">SIFR</a>. Web Fonts now provide us with all kinds of of typographic joy, but they aren’t cheap from a performance perspective. Zach Leatherman is something of a web font pornstar and his <a href="https://www.zachleat.com/web/comprehensive-webfonts/">article on font loading strategies</a> is a must read for every front end developer. In fact, go <a href="https://www.zachleat.com/web/">read his entire blog</a> on how you should be approaching font loading whilst remaining performant. Ebay also recently open sourced their <a href="https://www.ebayinc.com/stories/blogs/tech/ebays-font-loading-strategy/">font loading strategy</a> and the linked article is also a good resource on how to improve performance.</p>]]></content:encoded>
            <author>paul@webdistortion.com (Paul Anthony)</author>
        </item>
        <item>
            <title><![CDATA[Can we all please stop using Medium now?]]></title>
            <link>undefined/articles/can-we-all-stop-using-medium</link>
            <guid>undefined/articles/can-we-all-stop-using-medium</guid>
            <pubDate>Sat, 21 Jan 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Medium is cancer. A trojan horse. It’s Facebook. But for blogging.]]></description>
            <content:encoded><![CDATA[<p>Medium is cancer. A trojan horse. It’s Facebook. But for blogging. A walled garden behind which all your favourite content lives, and yet you are forced to login via their shitty UI, or worse still pay for access.</p>
<p>When did reading stuff on the web become pay to play?</p>
<p>I’ll tell you when. When we all got greedy looking for the attention our blogs used to get until social media came along. Or when we got greedy looking for coinage off the onetruecontentsource™. If you enjoy reading on the web chances are you’ve been forced to login to Medium at some point in the last week.</p>
<p>Have any of you noticed the dark UI patterns. I bet you did. I’m guessing you noticed smart programmers / designers / internet celebs tweeting about how shit it is. Maybe someone you respect continually pointed out their accessibility failures. Maybe you nodded your head in agreement. Maybe you even retweeted it. Go you.</p>
<p>Just so we are clear. Medium takes your content, rolls it up into a pretty SEO friendly package for themselves and sells it. Oh, and turns us all into seals waiting for someone to throw us a fish in the process. If you are lucky, you might even get a cut. You know. Like the sort of cut artists get on Spotify. Profit share I think the cool kids call it.</p>
<p>So why is everyone still publishing on it? For what? More eyeballs? More attention? More reach?</p>
<p>Balls to that. If only one of you read this I’ll be happy. At least I own my own platform and I’m not being controlled by some monolithic publishing giant that can do whatever they want and sell whatever advertising they please ON YOUR HARD WORK.</p>
<p>Please. It’s 2019. Learn to market yourself and your content. Quit being lazy waiting for Medium to do it for you. OWN YOUR PLATFORM.</p>
<p>Oh, and don’t get me started on the mini publications that we all jump for fucking joy over being published on. How’s about no. How’s about we starting taking responsibility for the absolute decimation of the traditional web.</p>
<p>You know. That old internet that used to be open and free.</p>]]></content:encoded>
            <author>paul@webdistortion.com (Paul Anthony)</author>
        </item>
    </channel>
</rss>