<?xml version="1.0" encoding="utf-8"?>
  <rss version="2.0"
    xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:wfw="http://wellformedweb.org/CommentAPI/"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
    xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
    xmlns:georss="http://www.georss.org/georss"
    xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
  >
    <channel>
      <title>Piccalilli - Advice topic archive</title>
      <link>https://piccalil.li/</link>
      <atom:link href="https://piccalil.li/category/advice.xml" rel="self" type="application/rss+xml" />
      <description>We are Piccalilli. A publication dedicated to providing high quality educational content to level up your front-end skills.</description>
      <language>en-GB</language>
      <copyright>Piccalilli - Advice topic archive 2026</copyright>
      <docs>https://www.rssboard.org/rss-specification</docs>
      <pubDate>Mon, 10 Aug 2026 04:09:38 GMT</pubDate>
      <lastBuildDate>Mon, 10 Aug 2026 04:09:38 GMT</lastBuildDate>

      
      <item>
        <title>A Front-end developer’s guide to the hybrid mobile app development landscape</title>
        <link>https://piccalil.li/blog/a-front-end-developers-guide-to-the-hybrid-mobile-app-development-landscape/?ref=advice-category-rss-feed</link>
        <dc:creator><![CDATA[Rachael Yomtoob]]></dc:creator>
        <pubDate>Thu, 04 Jun 2026 11:55:00 GMT</pubDate>
        <guid isPermaLink="true">https://piccalil.li/blog/a-front-end-developers-guide-to-the-hybrid-mobile-app-development-landscape/?ref=advice-category-rss-feed</guid>
        <description><![CDATA[<p>Just as with every aspect of my life, I find it hard to identify my software development skills. At my heart, I am a developer, though I spent way too much time as a high school senior fretting about whether or not I’d become an engineer. On paper, my job title has been product owner for almost the same amount of time as engineer/developer, but I was still writing code and reviewing PRs. Then comes the question of what kind of developer am I? Web developer? Mobile developer? Front-end? Full-stack? So many titles, but not a single one that fully encompasses my experience. I can tell you one thing that I’m not is a back-end developer 😆</p>
<p>All that said, for the purposes of this article, I’m a front-end web developer who has spent their 7 year career building a product for testing accessibility of mobile apps. I’d like to give you — a front-end web developer, who may not have mobile experience — a quick run-through to the mobile apps built with web technologies landscape.</p>
<h2>What is a hybrid mobile app?</h2>
<p>As a front-end web developer, we’re used to our HTML content being rendered in the browser whether it’s being generated by a framework like React or Vue, or being served from an HTML file.</p>
<p>The mobile app world is a quite different story where the rendered content doesn’t follow agreed upon and maintained guidance, like web standards. For example, Apple and Google completely govern their own native tech stacks for building iOS and Android apps respectively. Those tech stacks create elements on the screen called <code>Views</code>. Then there’s the 3rd party cross-platform frameworks such as React Native, .NET MAUI (previously Xamarin), Flutter. These all allow you to build both an Android and iOS app, and sometimes a web and/or desktop app, from a single code base, but they each do that process a bit differently to each other.</p>
<p>React Native and .NET MAUI generate <code>Views</code> that mimic or are very similar to native mobile <code>Views</code>. They are designed to use technologies familiar to React and .NET developers: TypeScript/JavaScript with CSS and C# with XAML. Flutter is in it’s own league because it uses Dart to build <code>Widgets</code> that are rendered by it’s own graphics engine, bypassing the concept of native <code>Views</code> entirely.</p>
<p>While all these frameworks are often referred to in discussions of hybrid mobile apps, I prefer to distinguish them as cross-platform or code-once frameworks and reserve hybrid to specifically describe the subset of apps which present a blend of web and mobile content.</p>
<p>We’ll define a hybrid mobile app as follows: “A mobile app which primarily features HTML content rendered in <code>WebViews</code> alongside some native mobile content or functionality”</p>
<p>A <code>WebView</code> is a native mobile <code>View</code> which acts as an embedded web browser component to render HTML content inside of it instead of native controls like sliders or buttons. The mobile browser apps such as Safari and Chrome utilize a <code>WebView</code> as the main component with the addition of peripherals like the URL bar and back button. That’s a route to web developers to feel <em>empowered</em> rather than hindered.</p>
<p>The cross-platform framework names I haven’t mentioned yet are by this definition, hybrid app development frameworks: Ionic, Capacitor, Cordova/PhoneGap. It’s a bit complicated to untangle what each framework is and does, so we’ll dive into that in the next section.</p>
<p></p>
<h2>Hybrid App Development Frameworks</h2>
<p>Let’s start by talking about Apache Cordova/Adobe PhoneGap, since it’s the original hybrid framework, created back in 2009. Here’s the overview statement on <a href="https://cordova.apache.org/docs/en/latest/guide/overview/index.html">the Cordova documentation site</a>:</p>
<blockquote>
<p>Apache Cordova is an open-source mobile development framework. It allows you to use standard web technologies - HTML5, CSS3, and JavaScript for cross-platform development. Applications execute within wrappers targeted to each platform, and rely on standards-compliant API bindings to access each device's capabilities such as sensors, data, network status, etc.</p>
</blockquote>
<p>There’s some history with the project being acquired by Adobe, including in an offering called PhoneGap, but that was discontinued in 2020. Cordova is still alive and actively maintained, but you may see references to PhoneGap while looking for hybrid app development topics.</p>
<p>Cordova isn’t a UI framework, but rather a runtime environment for your web app on a mobile device. This means you could take an existing web app that you built with your favorite front-end tools and package it up to render inside a <code>WebView</code> in both an iOS and Android app. Now there’s quite a lot of reasons why you wouldn’t want to to that, but let’s cover the other runtime frameworks first.</p>
<p>Capacitor is a newer option for a hybrid framework to ship your web content wrapped in a mobile app, developed in 2018 as a modern alternative to Cordova/PhoneGap. The intro on <a href="https://capacitorjs.com/docs">the Capacitor docs site</a> reads:</p>
<blockquote>
<p>Capacitor is a cross-platform native runtime that makes it easy to build performant mobile applications that run natively on iOS, Android, and more using modern web tooling. Representing the next evolution of Hybrid apps, Capacitor creates <strong>Web Native apps</strong>, providing a modern native container approach for teams who want to build web-first without sacrificing full access to native SDKs when they need it.</p>
</blockquote>
<p>What separates Capacitor from Cordova is that it’s built and maintained by the Ionic framework team. While the former are both native runtime frameworks, Ionic is actually a front-end UI framework for hybrid apps. Ionic can be used with both Cordova and Capacitor, but Capacitor is designed specifically to work in conjunction with Ionic. Here’s the introduction on <a href="https://ionicframework.com/docs">the Ionic docs site</a>:</p>
<blockquote>
<p>Ionic is an open source UI toolkit for building performant, high-quality mobile apps using web technologies — HTML, CSS, and JavaScript — with integrations for popular frameworks like <a href="https://ionicframework.com/docs/angular/overview">Angular</a>, <a href="https://ionicframework.com/docs/react/overview">React</a>, and <a href="https://ionicframework.com/docs/vue/overview">Vue</a>.</p>
</blockquote>
<p>Now we’re finally in the front-end developer’s domain! Before we dig into it too much, let’s go over some important design concepts for hybrid apps.</p>
<p></p>
<h2>Designing a Hybrid App</h2>
<p>Like I said earlier, you can use either Capacitor or Cordova, to wrap your existing web front-end into a <code>WebView</code> inside a mobile app, but there are some considerations to make since content built for the web is structured quite differently than content built for mobile.</p>
<p>For example, a common pattern in web apps is a single page with lot of content that can be scrolled to or jumped to with links/landmarks. Whereas, in a mobile app, content is often better presented in small chunks with navigation through a flow of multiple screens. Mobile app user experience is built around the fact that the content is displayed in a small viewport, but the web was originally built for desktop and adapted to suite mobile devices as their browser became more and more capable.</p>
<p>I’ve spoke with folks in the industry that claim most users can’t tell whether an app is presenting native content or a <code>WebView</code>, but I find that hard to believe. Maybe I’m biased because I know too much about both, but it says a lot if a user downloads your app instead of visiting your website since there’s a much higher barrier to entry. They likely took the extra effort to open the App Store or Play Store and remember or find their account password to install your app because they want a native mobile experience. One thing I can confidently say is that a screen reader user will definitely know the difference since it will literally announce <code>WebView</code> when they hit one, and the landmarks are different, like the fact that Android only has 1 level of heading compared to the 6 levels in HTML <code>&lt;h1&gt;-&lt;h6&gt;</code>.</p>
<p>So all that said, how do you build a stellar hybrid app user experience? By using the concepts of responsive and mobile-first web design of course!</p>
<p>Figma has <a href="https://www.figma.com/resource-library/mobile-first-design/#core-principles-of-the-mobile-first-design-process">a wonderful article</a> which covers the topic focusing on websites, but can be applied to hybrid apps as well:</p>
<blockquote>
<p>“Mobile-first website design flips the traditional Web development approach. Instead of starting with a desktop layout and scaling down, you begin with a mobile website design. This approach prioritizes smaller screens, slower Internet connections, and the needs of on-the-go users.”</p>
</blockquote>
<p>Another layer to mobile-first design is that Android and iOS each have a look and feel uniquely branded to Google and Apple. We’ve established that the web and mobile ecosystems are very different, but iOS and Android are almost just as different too. So you’re faced with some choices: design 2 experiences, pick iOS or Android and ship it to the other platform anyways, or roll your own that ideally caters to both. Trust me, I’ve seen it all, and my least favorite is an Android styled app shipped to iOS</p>
<p>While companies/brands love the idea of a consistent experience across platforms, users prefer your app to look behave like the rest on their device do. A lot of factors go into choosing a design pattern for an app such as target audience, development resource capacity, etc, so let’s set that aside and finally dig into building the bits</p>
<h2>Building a Hybrid app Front-end</h2>
<p>I want to bring us back to Ionic because <a href="https://ionicframework.com/docs/components">its UI component library</a> allowing front-end developers to build seamless experiences for both iOS and Android from a single codebase using technologies you know and love. It’s full of mobile-first components which render on iOS matching Apple’s aesthetics and on Android matching Material Design, Google’s open-source design system. These components are available in Angular, React, Vue, and plain ole JavaScript with beautiful interactive demos on the documentation site.</p>
<p>Let’s take a closer look at a Toggle component which is commonly used in the settings of a mobile app. In React, you import the <code>IonToggle</code> from Ionic’s library and use it just like you would any component for a web-first app.</p>
<pre><code>import React from 'react';
import { IonToggle } from '@ionic/react';

function Example() {
  return (
    &lt;&gt;
      &lt;IonToggle&gt;Default Toggle&lt;/IonToggle&gt;
      &lt;IonToggle checked={true}&gt;Checked Toggle&lt;/IonToggle&gt;
      &lt;IonToggle disabled={true}&gt;Disabled Toggle&lt;/IonToggle&gt;
      &lt;IonToggle checked={true} disabled={true}&gt;
        Disabled Checked Toggle
      &lt;/IonToggle&gt;
    &lt;/&gt;
  );
}
export default Example;
</code></pre>
<p>On iOS, you’ll get 4 toggles in Apple’s well known style.</p>
<p><img src="https://piccalil.b-cdn.net/images/blog/4-apple-toggle-elements.png" alt="4 iOS toggle elements in different states: default, checked, disabled and disabled checked" /></p>
<p>For Android, the recognisable material design elements are used.</p>
<p><img src="https://piccalil.b-cdn.net/images/blog/4-android-toggle-elements.png" alt="4 Android toggle elements in different states: default, checked, disabled and disabled checked" /></p>
<p>All of the Ionic components can be styled with CSS custom properties and standard CSS, so you can achieve that consistent experience across platforms by modifying the iOS and Android styles slightly or make them match exactly.</p>
<p></p>
<h2>Accessibility</h2>
<p>As digital accessibility advocate, I can’t write an article without touching on the topic. I think of accessibility in 2 realms: compliance and user experience.</p>
<p>The realm of compliance focuses on building digital content that adheres to the <a href="https://www.w3.org/TR/WCAG22/">Web Content Accessibility Guidelines (WCAG)</a>. These are the guidelines which legislature around the world reference, and large enterprises strive to meet. There isn’t a similar de facto standard for mobile app accessibility despite the immense difference in how content is rendered, but instead, there’s only adaptations and interpretations of WCAG for mobile.</p>
<p>On the other hand, Apple and Google put emphasis on accessibility through the user experience of the iOS and Android ecosystems. There’s <a href="https://developer.apple.com/design/human-interface-guidelines/accessibility">Apple’s Human Interface Guidelines with a foundations section dedicated to accessibility</a>, and <a href="https://developer.android.com/guide/topics/ui/accessibility">the Android Developer guide on accessibility.</a></p>
<p>There’s no straightforward way to make a perfectly accessible app today, but that’s ok! Just as with most things in life, it’s about finding the right balance. On the compliance side, that <code>WebView</code> inside a mobile app is rendering HTML, so WCAG criteria can be directly applied, so there’s certainly advantages for hybrid apps in that regard. However, accessibility compliance doesn’t always equate to a high quality user experience, which is where the advice from Apple and Google come into play.</p>
<h2>Wrapping up</h2>
<p>While the world of mobile apps can be intimidating to a front-end web developer, it’s certainly worth exploring, even to be aware of the landscape for if you find yourself in a project in the future.</p>
<p>With that in mind, I hope this article is a useful introduction and shows that you don’t have to step completely out of your comfort zone thanks to the concept of hybrid mobile apps, providing a very <em>familiar</em> experience. It makes them a useful jumping off point!</p>
        
        ]]></description>
        
      </item>
    
      <item>
        <title>Some advice on managing your design career upwards</title>
        <link>https://piccalil.li/blog/some-advice-on-managing-your-design-career-upwards/?ref=advice-category-rss-feed</link>
        <dc:creator><![CDATA[Ron Bronson]]></dc:creator>
        <pubDate>Thu, 22 Jan 2026 11:55:00 GMT</pubDate>
        <guid isPermaLink="true">https://piccalil.li/blog/some-advice-on-managing-your-design-career-upwards/?ref=advice-category-rss-feed</guid>
        <description><![CDATA[<p>Becoming a design manager is a trade that most people make it without naming what they're giving up, which is why so many end up unhappy on the other side.</p>
<p>I've gone from individual contributor to manager to director, and the most consistent mistake I see is people treating management as the "next rung" instead of a fundamentally different job. We treat someone's ability to manage others as a reflection of their worth, yet we rarely teach what management actually requires. That gap does real damage — both to the people who take the role for the wrong reasons and to the people who end up reporting to them.</p>
<p>When someone asks me whether they should become a manager, I ask if they want responsibility for outcomes you don't directly control, or are they looking for validation, stability, or a raise? Those are not the same thing. At <a href="https://donmoynihan.substack.com/p/requiem-for-18f">18F</a>, managers weren't paid more than individual contributors. That stripped away the usual incentives and made intent visible very quickly. The people who stepped into management because they cared about others' growth thrived or wanted to take the next path on their career progression. There are pros and cons to a relatively “flat” org structure like this, but I found it useful.</p>
<p>In one of my early jobs, I had a senior director who trusted me with leading an org-wide project. Not only was I put in charge, they invited me to leadership meetings and let me speak.  That experience shaped my career in ways I could not have anticipated at the time. Someone with positional authority chose to see me, pulled me into the conversation, and made my perspective matter. That's the job. Being seen often equates with being invited, and managers who understand this spend their energy opening doors, not guarding them can develop talent.</p>
<p>Deciding to give up everyday responsibility on design choices is not an easy one. I miss front-line delivery work and might choose it in my next role. There’s nothing like actually working on the problems in front of you, rather than just triaging or dealing with escalations. I’ve had front-end designers worry about losing their craft, and they're right to. You will write less code.</p>
<p>If your identity is tightly bound to being the person who solves the hardest technical problem, management will feel like erosion. The increasing number of “player-coach” roles that let designers keep designing while managing are the best of both worlds, but it takes a mindset to both focus on delivering artifacts while also coaching someone who may or may not be on your same project.</p>
<p></p>
<p>A few years ago, I took over coaching a new high school tennis team. Early into my tenure, I would notice the players looking at me for validation during crucial moments of the match. This didn’t happen with my old teams, but I realized what I needed to do. One of the things I emphasize through the pre-season and our practices is trust. Not just from me, but the entire coaching staff. I want the players to understand that they’ve been given the tools to make decisions out on the court. Sometimes, they’ll make the right ones. Other times, it won’t work, but by reminding them that they get to make the call because you’re the one seeing the ball is a lesson that transcends sports. As a director, I want my managers to instill this into their teams and same for individual contributors, because it’s crucial that people learn it for themselves. Few things are more rewarding than seeing someone grow into their craft and having a hand in that.</p>
<p>It's also worth saying plainly: you can grow without managing people. Leadership is not synonymous with line management. I've met outstanding principal designers who influence direction, mentor deeply, and carry real organizational weight without ever owning performance reviews. Some of my favorite designers are professionals I knew we could trust with almost any task in their toolbox; folks that delight clients and their colleagues alike. With senior designers and principals, my question is just ensuring they’re staying engaged and challenged by the work. Coaching and mentoring are non-managerial ways for them to contribute without having to “manage” someone.</p>
<p>On the flip side, I've watched senior designers become the glue — mentoring, stabilizing, unblocking — and then stall because none of that work was owned or legible. If you don't claim authority somewhere, the organization will take the value and flatten the role. This can be one of the ways that elevating into a leadership role can be a way to build yourself into a growth role in a company where you’ve spent a long time. It’s also where considering opportunities elsewhere are a chance to reframe how people see you; new jobs with a different title can give you a chance to reinvent yourself.</p>
<p>If you're considering management, be honest with yourself. If what energizes you is coaching, advocating, and shaping how work happens beyond your own hands, then management can be deeply rewarding. If what energizes you is making things and being close to the work, protect that instinct. The field needs senior practitioners just as much as it needs good managers.</p>
        
        ]]></description>
        
      </item>
    
      <item>
        <title>We made an email template to help convince your boss to pay for Mindful Design</title>
        <link>https://piccalil.li/blog/we-made-an-email-template-to-help-convince-your-boss-to-pay-for-mindful-design/?ref=advice-category-rss-feed</link>
        <dc:creator><![CDATA[Andy Bell]]></dc:creator>
        <pubDate>Wed, 26 Nov 2025 12:55:00 GMT</pubDate>
        <guid isPermaLink="true">https://piccalil.li/blog/we-made-an-email-template-to-help-convince-your-boss-to-pay-for-mindful-design/?ref=advice-category-rss-feed</guid>
        <description><![CDATA[<p>We recently launched <a href="https://piccalilli.link/md-launch-email-your-boss">Mindful Design</a>, and plenty of people have mentioned that they don’t know how to approach their boss to ask them to pay for it. Here’s an email template for you to help with that.</p>

<p>Dear {'{Boss}'},</p>
<p>I have found a <a href="https://piccalilli.link/md-launch-email-your-boss">new design course called Mindful Design</a> that I believe will completely transform our ability to produce design that actually works well for our users/customers. The course doesn't teach hacks and deceptive patterns, but instead teaches us how the human brain actually works, so our design skills will evolve to work <em>with</em> people, rather than against them. I think that will benefit us all in the long term.</p>
<p>I also think the course will be useful for our front-end developers because the instructor, <a href="https://piccalil.li/mindful-design#bio">Scott Riley</a>, covers practical design skills from scratch. Our developers are not designers, but having a broader understanding of practical design <em>and</em> how the human brain works will improve their skillset and output a lot. It’ll also help them work more effectively and efficiently with our designers, who themselves, will always benefit from re-learning the fundamentals too.</p>
<p>The course has nearly 20 hours of video content and around 15-30 hours of practical exercises. I thought doing those exercises as a team will be an efficient way for us all to skill up at the same time. The course is written off the back of a really successful book, also called Mindful Design, which has helped countless teams already, including the BBC, Stanford, GitLab and Zeroheight.</p>
<p>If you would like to look over all the course curriculum you can find it <a href="https://piccalil.li/mindful-design/lessons">here</a>. Certificates are also available upon completion of the course should we want them, along with LinkedIn certifications.</p>
<p>I am asking that we allocate some of our training budget for this course if possible. <a href="https://piccalil.li/company-licences?course=Mindful%20Design#enroll">Bulk discounts are available</a>, should we want the team to go through this together.</p>
<p>Thanks!</p>
<p>{'{Your Name}'}</p>

<p>If you are a boss reading this, investing in your staff’s training is really valuable in both improving your company’s output, but also making your staff feel rightly valued, supported and invested in. It’s something I don’t even hesitate to do for the staff that work here. Staff training spend is also tax-deductible and often incentivised in various countries.</p>
<p>If you have any questions about bulk licences or <em>anything</em> related to <a href="https://piccalilli.link/md-launch-email-your-boss">Mindful Design</a>, we’re ready to help at <code>support@piccalil.li</code>.</p>
<p><a href="https://piccalilli.link/md-launch-email-your-boss">Check out Mindful Design</a></p>
        
        ]]></description>
        
      </item>
    
      <item>
        <title>Programming principles for self taught front-end developers</title>
        <link>https://piccalil.li/blog/programming-principles-for-self-taught-front-end-developers/?ref=advice-category-rss-feed</link>
        <dc:creator><![CDATA[Kilian Valkhof]]></dc:creator>
        <pubDate>Tue, 11 Nov 2025 11:11:00 GMT</pubDate>
        <guid isPermaLink="true">https://piccalil.li/blog/programming-principles-for-self-taught-front-end-developers/?ref=advice-category-rss-feed</guid>
        <description><![CDATA[<p>Like many front-end developers, I don’t have a formal computer science background. I rolled into this discipline as a designer wanting more control over the end product and though I did get a bachelors of ICT degree, the actual studies were, ahem, quite light in terms of “fundamental computer science”. This means all I know about capital-s Software Development, I learned as I went from various sources. If that’s you too, this article hopefully saves you a few years.</p>
<p>After 20+ years, the things that have the most effect on my day-to-day aren’t that I learned how to model my OOP systems using UML or know what a Monad is. Instead, it’s a bunch of (sometimes pithy) statements that fall under the umbrella of “programming principles”.</p>
<p>Now, there are many, many programming principles out there. Some are more like “laws” that describe how systems and people behave (like Hofstadter’s law: <em>It always takes longer than you expect, even when you take into account Hofstadter’s law</em>.) and while those are useful in broader contexts, I don’t find them that actionable when I want to write “good code”.</p>
<p>In this article, I go over the rules-of-thumb that help me write better code <em>as I’m writing code</em>. They don’t require me to write out my entire system before they’re useful, they just help me make better decisions as I go.</p>
<h2>From pithy statements to actual useful habits</h2>
<p>When you’re just starting out, at some point someone is going to point at your code and say “Premature optimisation is the root of all evil”. That sounds super serious, but also kind of odd.</p>
<p>Optimisation is something that’s good while “premature” usually isn’t. The big problem here is that you’ve now been told that what you’re doing is evil, but you don’t actually know what to do next. Avoiding premature optimisation is a good programming principle, but it doesn’t actually help you write better code.</p>
<p>A helpful senior developer might help you out there and explain <em>You Aren’t Gonna Need It</em> (YAGNI). This is another good programming principle that warns you against writing code that you anticipate needing in the future, but don’t need now. The reason you’re not going to need it is that between not needing it now and the planned future where you would need it, the plans are likely to change in such a way that you actually won’t need it after all. It’s better then to write things “just in time”, when you actually need them.</p>
<p>However, you’ll also be asked to follow the <em>Don’t Repeat Yourself</em> (DRY) principle. Don’t write code that does the same thing in multiple places, because that’s hard to maintain. If you listen to this, all you’d ever do is consolidate code that does the same thing into a single function or module, and call that from multiple places.</p>
<p>All of these acronyms are generally good advice. If you’re building out some functionality, it makes sense to anticipate the future at least somewhat, right? It makes sense that if you need that logic in multiple (future) situations, to optimise or refactor that already. That way you can make sure the current code takes that into account, and you don’t have to write it twice.</p>
<p>YAGNI and premature optimisation are usually brought up because rather than writing the code for the functionality you need <em>now</em>, you start writing code for the <em>general system</em> that offers the functionality you need now, but also the functionality you might need in the future. It means that you end up writing a lot more code, adding a lot more complexity and taking much longer than your senior co-workers.</p>
<p>These principles don’t actually help you as you write code. You could try leaving out random parts that you think you need later, but it would be much nicer to have a principle that helps you know what to leave out.</p>
<p>Enter the “rule of three” — the actually actionable, pragmatic principle that elegantly combines how you should be thinking about YAGNI, DRY and premature optimisation.</p>
<p>The rule of three states that you should only refactor (or optimise) code once you’ve written the same code three times. The first time you write the code, you just write it. It does <em>the thing</em> and only <em>the thing</em>. The second time you see that you need the same code again, you …literally copy-and-paste it and make the few changed you need. Then when you have to do that a third time, only <em>then</em> do you look at the now three implementations you have and generalise them into a single implementation that can handle all three cases.</p>
<p>The concept here is that, once you’ve written that code three times, you have an understanding of what general functionality you actually need, and what parts can be simplified and optimised. After three implementations you know what “level of abstraction” you need, and you can make sure that the generalised implementation actually works for all three cases. I “apply” this principle all the time because it’s so easy (I can count to three!) and it helps me avoid over-engineering right as I’m about to.</p>
<p>When you read up on programming principles, it’s easy to find Laws and Rules that sound very serious, but that require a lot of context to actually apply. I hope that from the example above you can see how getting from the general “premature optimisation is the root of all evil” to the specific “rule of three” has a much bigger impact on your day-to-day coding, and the quality of the code you write.</p>
<h2>Writing the right thing</h2>
<p>Lets now zoom in to that first implementation. It can be very tempting to optimise the code right from the start, making sure each line is fast and efficient. Often times though, the fast and efficient code is not the most readable code.</p>
<p>When it comes to writing code, we don’t actually spend that much time <em>writing</em>. Instead, we spend time <em>reading</em> the code we just wrote, or that already exists and reasoning about it to decide what to write next. So the easier it is to read and reason about the code, the faster we can write the right code. Code that’s fast and optimized is great, but if it’s hard to read and reason about, it will slow us down in the long run.</p>
<p>We want it all though: we want to write correct code fast and we want to write code that <em>is</em> fast. So how do we go about that? How do we choose?</p>
<p>Here, I like to apply another principle: “Make it work, make it right, make it fast”, which is attributed to Kent Beck, the inventor of <em>Extreme Programming</em>.</p>
<p>At any point during your coding you can look at your code and ask yourself: <em>does it work</em>? If the answer is no, then you focus on making the code work. You don’t care about anything else. Just make it work. If it works: great!</p>
<p>But things that work aren’t always doing the right thing, so next you ask: is is right? As long as your code isn’t right (it doesn’t behave the way you want to, it makes tests fail, it doesn’t accept the input you give it), you focus on making sure that it works right. Only then, when your code works and your code is right, do you ask: is it fast? If it’s not fast enough, you can now focus on making it fast.</p>
<p>This helps you prioritise your efforts. It’s a waste of time optimising code that doesn’t work yet, or that does the wrong thing. You’ll have to rewrite it anyway and then the optimisation is gone too. If your code doesn’t even work yet, there’s no need to worry about whether or not the broken code is right. It’s broken so you need to make it work before you can do anything useful.</p>
<p>What makes this principle so useful is that you can apply it at any time simply by looking at (the behaviour of) your code. You don’t need to plan anything out. You can just ask yourself these three questions, in order, and focus on the one that matters right now. You can forget everything else until it’s relevant.</p>
<p><em>If</em> you squint, you realise that this is actually the same principle as the rule of three, just applied to a different aspect of programming. Both help you focus on the task you have right now, and avoid getting distracted by other concerns that aren’t relevant yet.</p>
<p></p>
<h2>The crappy first version</h2>
<p>There’s a bunch of principles that help you get into the mindset of writing that first implementation. Principles in this vein tell you to <a href="https://ntietz.com/blog/throw-away-your-first-draft/">throw away your first implementation</a>, or to build <a href="https://dannorth.net/blog/best-simple-system-for-now/">the best simple system for now</a> and, actually, “make it work” in the rule of three is this exact same idea.</p>
<p>There’s a more high-brow version of this too called <em>Gall’s Law</em>, which states that “a complex system that works is invariably found to have evolved from a simple system that worked.”</p>
<p>The idea here is that if you try to account for all things from the start, the thing you end up with doesn’t actually work. An example of this is every “full rewrite” ever that ended up worse than the original and took significantly longer than planned. (this, of course, also has a name: <a href="https://en.wikipedia.org/wiki/Second-system_effect">Second-system effect</a>.)</p>
<p>Reading all of that, you might be reminded of <em>Keep It Simple, Stupid</em> (KISS). The problem with KISS though is that if you’re building something to help people complete a task, some complexity might be unavoidable and then, KISS has no answers for you. Some things aren’t simple. <em>Gall’s Law</em>, on the other hand, at least tells you that the complex <em>can</em> exist if you’re honest about starting simple and iterating towards your goal.</p>
<p>Still, that’s not very actionable <em>as you’re writing code, s</em>o lets see if we can find some principles that do help you write better code <em>as you’re writing code</em>.</p>
<h3>Idempotency</h3>
<p>As much as possible, the functions I write are <em>idempotent</em>. That’s a big word isn’t it? All it really means is that a function always does the same thing when given the same arguments. That doesn’t sound groundbreaking, but it actually has pretty big implications for how easy it is to reason about your code.</p>
<p>If you have a function that is idempotent, you can call it as many times with the same argument and it will always return the same result. For example, getting the length of a string is idempotent. No matter how many times you call <code>"hello".length</code>, it will always return <code>5</code>. If you know the function is idempotent, you don’t have to worry it secretly returns a new string or read a variable from elsewhere in your code. Same arguments in, same result out.</p>
<div><h2>FYI</h2>
<p>There is a subtle difference between idempotent and pure functions, which isn’t particularly relevant to this part but if you really want to know: pure functions are guaranteed to not have side effects, meaning they don’t access or modify any global data, nor do they change their arguments in-place.</p>
</div>
<p>A function that is idempotent can still have side effects as long as those are also idempotent: changing global state or a database entry can be idempotent as long as calling the function more than once always results in the same value being set.</p>
<p>When that’s not the case, calling a function twice (due to a user double-clicking, or a servers retry-logic on a flaky connection) might change the resulting value. That makes reasoning about your code much harder. If you find you need a side-effect, you can split that off into its own function and then make <em>that</em> idempotent. Rather than one larger function, you have two smaller functions that each do one thing.</p>
<p>You can treat idempotent functions like black boxes that let you “forget” the implementation details while you reason about your larger system. It’s like a brain shortcut that makes it easier to reason at a higher level. The function always does the same thing, so you can collapse it into a single step in your mind.</p>
<h3>Single responsibility principle</h3>
<p>Related to idempotency is the <em>Single Responsibility Principle</em>. This principle states that a function (or module, or class) should have “only one reason to change.”</p>
<p>In practice, this means that there should be one function that takes care of one aspect of your system. A nice example here is using an <em>Object-Relational Mapping</em> (ORM) to handle all your database access. The ORM module is responsible for talking to the database and the rest of your code should have <em>no idea</em> how that works. If you ever need to change how you talk to the database, you need to update your ORM and no other part of your code.</p>
<p>Again, this lets you collapse parts of the system as you reason about it. You don’t need to know how it constructs SQL queries. It’s not the responsibility of the code you’re working on right now. You can just treat an ORM like a black box that does database access for you.</p>
<p>You also see the Single Responsibility Principle described as “a function/module/class should only have one reason to exist.” If that single reason disappears, you should be able to remove that function/module/class entirely. If you switch to a different database and need a new ORM for example, the old one should be completely removable.</p>
<p>What often happens though, is that your ORM grows in functionality: it doesn’t just fetch data from the database, it also mangles that into a specific format that the rest of your code expects. Now, if you want to switch databases, you also need to update all the code that depends on that specific data format. Your ORM has multiple reasons to change, and that makes it harder to reason about.</p>
<p>Instead, you should have one module that only handles getting data from the DB, and another module that only handles data formatting. Now each module has a single responsibility, and you can change (or delete!) one without affecting the other: that’s the single responsibility principle in action.</p>
<p>A small trick to check for single responsibility is to describe what a function/module/class does in a single sentence. If you find yourself saying “<em>and</em>”, then it probably has multiple responsibilities and should be split up.</p>
<h3>One level of abstraction</h3>
<p>Related to the single responsibility principle is the idea that a function shouldn’t just do one thing, but also only operate at one level of abstraction. The phrase, “level of abstraction” is in itself quite an abstract concept, if you pardon me the overloading of the term. What it means is that when you read through the code in a function, all the operations should be at the same level of detail.</p>
<p>For example, consider this function:</p>
<pre><code>async function processUsers() {
  const users = await database.fetchAllUsers();

  users.forEach((user) =&gt; {
    if (user.isActive) {
      sendEmail(user.email, "Hello active user!");
    }
  });
}
</code></pre>
<p>In this function, we have three levels of abstraction:</p>
<ol>
<li>Fetching data from the database (<code>database.fetchAllUsers()</code>).</li>
<li>Loop over all the users and filter them to only the active ones (<code>if (user.isActive)</code>).</li>
<li>Performing an action based on that data (<code>sendEmail(...)</code>).</li>
</ol>
<p>Not only do you have to use a lot of “and” to describe this function — it connects to the database to get users <em>and</em> filters them <em>and</em> sends emails only to the filtered users — but you also have to think about three different levels of detail when reasoning about this function: the database, active users and email sending. In real-world code, this might additionally have a bunch more <code>await</code>, validation and error handling.</p>
<p>As you read the function, the thing you’re focused on keeps shifting, making it harder to follow along. For example, first the function is about getting all users, then it’s about filtering them, then it’s about sending emails to those filtered users only.</p>
<p>Some things you can look out for that indicate multiple levels of abstraction:</p>
<ul>
<li>Multiple “and” when describing what the function does.</li>
<li>Multiple loops or iterations over data.</li>
<li>Mixing “low-level” operations (like database access) with <a href="https://en.wikipedia.org/wiki/Business_logic">business logic</a>.</li>
</ul>
<p>If you split this up, you can have three functions that each operating at a single level of abstraction:</p>
<pre><code>async function getActiveUsers() {
  const users = await database.fetchAllUsers();
  return users.filter((user) =&gt; user.isActive);
}

function sendEmailsToUsers(users) {
  users.forEach((user) =&gt; {
    sendEmail(user.email, "Hello active user!");
  });
}

function processUsers() {
  const activeUsers = getActiveUsers();
  sendEmailsToUsers(activeUsers);
}
</code></pre>
<p>The <code>getActiveUsers</code> function only deals with fetching and filtering users to those that are active, the <code>sendEmailsToUsers</code> function only deals with sending emails, and the<code>processUsers</code> function gets all the active users and then emails all of them. Each function is easier to understand because it only deals with one level of abstraction, and you can reason about each part separately.</p>
<p>Notice how in the refactored version, <code>sendEmailsToUsers</code> doesn’t care where the users come from or what their state is. It just sends emails to the users it has been given. Each function has a single responsibility and operates at a single level of abstraction.</p>
<p></p>
<h2>Are they all the same thing?</h2>
<p>At this point, you might have noticed that a lot of these principles are related, and that’s because, to butcher a classic:</p>
<blockquote>
<p>All good code is alike; each bad code is bad in its own way.</p>
<p>— Tolstoy (if he was a software engineer)</p>
</blockquote>
<p>Good code is easy to reason about and things are easy to reason about when it’s clear what each part does. It’s also clear how the parts relate to each other, so all these principles highlight different aspects of writing code that’s easy to reason about.</p>
<p>On the flip side, it can be hard to figure out why some code is bad. Is it because it has multiple responsibilities? Is it optimised but incorrect? Does it take you on a tour of multiple levels of abstraction as you read it line-by-line? Does it do extra things that you aren’t sure what for? All of these things make bad code so hard to work with.</p>
<p>It’s much easier to end up with good code by (dogmatically) sticking to the principles above than it is to have bad code and make it good again.</p>
<p>Next time you’re writing a new function, I hope you catch yourself thinking about these principles, that you stop yourself from optimising code that doesn’t work yet, that you make sure each function only does one thing and that you keep yourself from designing complex systems before you have a simple system that works. Good luck!</p>
<h2>Bibliography and further reading</h2>
<p>Like I said, I learned all this stuff on the fly. Here are some of the resources that helped me along the way:</p>
<ul>
<li><a href="https://martinfowler.com/books/refactoring.html">Refactoring by Martin Fowler</a>. This classic book has a JavaScript edition and though a lot of the code has a distinct Java flavour, the principles are universal.</li>
<li><a href="https://www.youtube.com/watch?v=IcgmSRJHu_8">Making impossible states impossible</a> by Richard Feldman. A great talk about modelling data structures to make reasoning about your code easier. Though the focus is on data structures and less about business logic like this article, I apply rules from this talk on a nearly daily basis.</li>
<li><a href="https://wiki.c2.com/?MakeItWorkMakeItRightMakeItFast">Make It Work Make It Right Make It Fast</a> on the C2 wiki, attributing the quote to Kent Beck.</li>
<li><a href="https://medium.com/@nsbaspinar/software-design-principles-single-level-of-abstraction-3017adbbd703">Software Design Principles: Single Level of Abstraction</a></li>
<li><a href="https://hacker-laws.com/">hacker-laws.com</a> is a collection of programming principles, laws and rules.</li>
</ul>
        
        ]]></description>
        
      </item>
    
      <item>
        <title>We made an email template to help convince your boss to pay for JavaScript for Everyone</title>
        <link>https://piccalil.li/blog/we-made-an-email-template-to-help-convince-your-boss-to-pay-for-javascript-for-everyone/?ref=advice-category-rss-feed</link>
        <dc:creator><![CDATA[Andy Bell]]></dc:creator>
        <pubDate>Wed, 15 Oct 2025 12:55:00 GMT</pubDate>
        <guid isPermaLink="true">https://piccalil.li/blog/we-made-an-email-template-to-help-convince-your-boss-to-pay-for-javascript-for-everyone/?ref=advice-category-rss-feed</guid>
        <description><![CDATA[<p>We recently launched <a href="https://piccalil.li/javascript-for-everyone">JavaScript for Everyone</a>, and a lot of people have mentioned that they don’t know how to approach their boss to ask them to pay for it. Here’s an email template for you to help with that.</p>

<p>Dear {<code>{Boss}</code>},</p>
<p>I have found a JavaScript course that I believe will elevate our team’s knowledge of how the language <em>really</em> works, which in turn, will improve the quality of the JavaScript code we produce, day-to-day. I also think a deeper knowledge of the language will reduce our technical debt levels and also reduce bugs.</p>
<p>The course takes around 15-30 hours to complete, based on an average reading speed and it will also be a useful reference guide for us in the long term too.</p>
<p><a href="https://piccalil.li/javascript-for-everyone">JavaScript for Everyone</a> was written by <a href="https://piccalil.li/javascript-for-everyone#bio">Mat Marquis</a> who has written industry leading courses and books already. He was also part of the jQuery team, a member of the W3C Responsive Issues Community Group and an editor of the HTML specification. In short, he knows his stuff and his material is incredibly trustworthy with all of that experience.</p>
<p>If you would like to look over all the lessons you can <a href="https://piccalil.li/javascript-for-everyone/lessons">find them here</a>. Certificates are also available upon completion of the course should we want them, along with LinkedIn certifications.</p>
<p>I am asking that we allocate some of our training budget for this course and <a href="https://piccalil.li/company-licences?course=JavaScript%20for%20Everyone#enroll">bulk discounts are available</a> should we want the team to go through this together.</p>
<p>Thanks!</p>
<p>{<code>{Your Name}</code>}</p>

<p>If you are a boss reading this, investing in your staff’s training is really valuable in both improving your company’s output, but also making your staff feel rightly valued, supported and invested in. It’s something I don’t even hesitate to do for the staff that work here. Staff training spend is also tax-deductible and often incentivised in various countries.</p>
<p>If you have any questions about bulk licences or <em>anything</em> related to <a href="https://piccalil.li/javascript-for-everyone">JavaScript for Everyone</a>, we’re ready to help at <code>support@piccalil.li</code>.</p>
        
        ]]></description>
        
      </item>
    
    </channel>
  </rss>
