<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: John Aitchison</title>
    <description>The latest articles on DEV Community by John Aitchison (@johnai).</description>
    <link>https://dev.to/johnai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2899595%2F6f27351a-8a4e-418e-84bc-db91cd875817.png</url>
      <title>DEV Community: John Aitchison</title>
      <link>https://dev.to/johnai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/johnai"/>
    <language>en</language>
    <item>
      <title>Use Browser Fingerprinting to Give Valuable Free Trials</title>
      <dc:creator>John Aitchison</dc:creator>
      <pubDate>Fri, 28 Feb 2025 02:20:03 +0000</pubDate>
      <link>https://dev.to/johnai/use-browser-fingerprinting-to-give-valuable-free-trials-40f6</link>
      <guid>https://dev.to/johnai/use-browser-fingerprinting-to-give-valuable-free-trials-40f6</guid>
      <description>&lt;p&gt;In my company’s opportunity discovery process (a fancy industry term for “what delights our users, what do they want us to build?”), we learned that providing users with a completely free trial was essential. At LanguageConvo, we taught foreign languages online; our niche was 1-on-1 and small group classes in a custom-built online classroom with teachers located in native-speaking countries.&lt;/p&gt;

&lt;p&gt;Potential customers were initially very skeptical:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is learning in an online environment effective?&lt;/li&gt;
&lt;li&gt;Are these international teachers good at teaching?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is for most people, and our teachers were fantastic; if we could get users into a free trial lesson with one of our teachers, conversion rates were high. The problem: fraud, people signing up multiple times for multiple free trial lessons.&lt;/p&gt;

&lt;h3&gt;
  
  
  What &lt;em&gt;is&lt;/em&gt; browser fingerprinting?
&lt;/h3&gt;

&lt;p&gt;Browser fingerprinting isn’t well known in the web dev world, which I don’t find surprising; it’s not something you’ll commonly use in everyday web or mobile application development. Browser fingerprinting is the process of capturing information about users from the data their browser exposes and using that data as a unique signature to identify users. You’ll gather information from browser APIs and HTTP requests: IP address, user agent, time zone, browser permissions, and much more. The list is incredibly extensive.&lt;/p&gt;

&lt;p&gt;Get on the Google, search “browser fingerprint test” and take a look at the first few results. I think you’ll be surprised at the amount of data your browser exposes!&lt;/p&gt;

&lt;p&gt;💡 Obviously GDPR and other laws come into play in a big way, so make sure you’re following applicable laws. &lt;/p&gt;

&lt;h3&gt;
  
  
  How accurate is it?
&lt;/h3&gt;

&lt;p&gt;Incredibly accurate, even against black hat actors who know what they’re doing. As you’ll see in online fingerprinting tools, the amount of data browsers expose is surprising. You can use adblockers, VPNs, etc., and you will still expose enough data to uniquely identify yourself. Browsers expose the list of installed fonts on your system for goodness sake! If you take just that one single data point, a list of installed fonts, and hash it, you can be fairly accurate at identifying users. And that’s just one small touch point in the fingerprinting world.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://Fingerprint.com" rel="noopener noreferrer"&gt;Fingerprint.com&lt;/a&gt; claims a 99.5% accuracy rate, and I don’t doubt that number.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation
&lt;/h3&gt;

&lt;p&gt;This is a build vs. buy decision, and I usually lean toward buy in these scenarios. &lt;a href="http://Fingerprint.com" rel="noopener noreferrer"&gt;Fingerprint.com&lt;/a&gt; is one of a few off-the-shelf solutions available, the only one I’ve personally used in production. It’s easy to implement, accurate, and affordable for most use cases.&lt;/p&gt;

&lt;p&gt;That said, it depends on the value to your organization. You can build basic fingerprinting solutions yourself; in a scenario where you want to allow newly signed-up users to take advantage of a free trial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use browser APIs to record as much data about each user as possible (again, make sure you’re clearly informing them that you’re doing this)&lt;/li&gt;
&lt;li&gt;Store that data in your database&lt;/li&gt;
&lt;li&gt;Each time a user requests or begins a free trial, have a back-end process parse through the data of previous free trial users and look for matches&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's easier said than done. Users with basic skills can use a VPN or adblocker so their fingerprints won’t match &lt;em&gt;exactly&lt;/em&gt;. Your back-end can attempt to create a likelihood score, a percentage chance that the user starting this free trial matches another user who did so previously. Doing that well isn’t easy, especially as browsers continually update, changing what data is available via their APIs. I recommend looking at off-the-shelf solutions, and only if they aren’t affordable for your use case, explore the possibility of building your own implementation.&lt;/p&gt;

&lt;p&gt;With a well-implemented fingerprinting solution, you can confidently provide free trials to users while minimizing fraud!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Commenting Code: Describe Why, Not What</title>
      <dc:creator>John Aitchison</dc:creator>
      <pubDate>Fri, 28 Feb 2025 01:39:22 +0000</pubDate>
      <link>https://dev.to/johnai/commenting-code-describe-why-not-what-47km</link>
      <guid>https://dev.to/johnai/commenting-code-describe-why-not-what-47km</guid>
      <description>&lt;p&gt;I love well-comment code and am a little perplexed by engineers who live by the “comment as little as possible” mantra. Maybe I’ve just written a lot of bad code, and comments have helped tremendously when I look back to refactor it!&lt;/p&gt;

&lt;p&gt;What defines &lt;em&gt;well-commented&lt;/em&gt; code, though? In my experience, the key is to describe &lt;em&gt;why&lt;/em&gt; you did what you did rather than &lt;em&gt;what&lt;/em&gt; you did.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s Compare
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;displayTheComponent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A what comment for this might be: “if x is 0, display the component”&lt;/p&gt;

&lt;p&gt;A why comment for this might be: “if the user hasn’t ever made a purchase, we’ll show them a special UI component explaining some benefits of purchasing”&lt;/p&gt;

&lt;p&gt;Obviously, this is a contrived example but hopefully it explains the concept. The first what comment is completely useless to anyone with more than a week of engineering experience; we can look at the code and tell &lt;em&gt;what&lt;/em&gt; it’s doing. The why comment is better. If we return to this code two years from now and wonder, “Why did we do this?” we’ll know!&lt;/p&gt;

&lt;p&gt;Next time you’re reviewing a PR, just meandering through old code, or when you’re refactoring unfamiliar code, pay attention to your thought process. I think you’ll notice that you often ask yourself, “Why are we doing this here?”&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Sometimes Useful in Complex Scenarios
&lt;/h3&gt;

&lt;p&gt;What comments can be useful from time to time. Particularly when code gets complex, some what comments sprinkled here and there may be helpful. I like using code-foldable regions to keep complex code organized, and I often write &lt;em&gt;what&lt;/em&gt; comments in those regions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;  &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;endregion&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;  &lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;endregion&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;[ Avoiding files and especially functions that get larger than a few hundred lines is often the best approach to keeping code simple, but sometimes complexity is unavoidable ]&lt;/p&gt;

&lt;p&gt;I’d love to hear your take on commenting code. There are so many different styles and opinions that it’s still an open debate in my mind what works best in a team scenario!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Use an Image CDN to Dramatically Speed Up App Load Times</title>
      <dc:creator>John Aitchison</dc:creator>
      <pubDate>Fri, 28 Feb 2025 01:10:48 +0000</pubDate>
      <link>https://dev.to/johnai/use-an-image-cdn-to-dramatically-speed-up-app-load-times-4cfo</link>
      <guid>https://dev.to/johnai/use-an-image-cdn-to-dramatically-speed-up-app-load-times-4cfo</guid>
      <description>&lt;p&gt;I’ve seen quite a few questions about building image-heavy web and mobile applications. Although there doesn’t seem to be much familiarity with Image CDNs, they’re a great option to explore if your goal is to build fast, reliable image hosting in your application! &lt;/p&gt;

&lt;h3&gt;
  
  
  What &lt;em&gt;is&lt;/em&gt; an Image CDN, and why might you want to use one?
&lt;/h3&gt;

&lt;p&gt;I’ll assume if you’re reading this article, you have a background in engineering and are already somewhat familiar with at least the concept of CDNs. Image CDNs are exactly what they sound like: CDNs specially designed for hosting images.&lt;/p&gt;

&lt;p&gt;Unlike many file types, delivering images to end-users in browser and app contexts can be highly optimized. An image CDN automates that optimization. Like most CDNs, you’ll upload your images to an &lt;em&gt;origin&lt;/em&gt; (AWS S3 is a common choice, but most support any S3-compatible origin). The CDN sits on top of that origin, automatically serving image files in compressed, optimized formats.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Short Trip With a Browser Loading a Webpage
&lt;/h3&gt;

&lt;p&gt;When users visit a page in your web application that includes an image, their browser must make an HTTP request for the actual image file. Meaning that in order for the user’s browser to &lt;em&gt;display&lt;/em&gt; the image, it first must &lt;em&gt;download&lt;/em&gt; that image. The larger the image file size and the further away (geographically) that image is hosted from your user, the slower the download occurs, which in turn directly affects the user’s experience loading your webpage.&lt;/p&gt;

&lt;p&gt;If we can host the image geographically very close to the user and compress the image to a small file size, the user will experience a really fast page load time!&lt;/p&gt;

&lt;h3&gt;
  
  
  What Optimizations Image CDNs Make
&lt;/h3&gt;

&lt;p&gt;Like typical CDNs, a good Image CDN will have many global edge locations, so files are close to your users. On top of that, we get into the really good stuff:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compression of your original image file&lt;/li&gt;
&lt;li&gt;Conversion of your original image file type into highly compressed formats

&lt;ul&gt;
&lt;li&gt;WebP and AVIF are two highly compressed file formats. Head to Google Images, click on a thumbnail to open a somewhat larger preview and right-click to download. As of this writing, Google will serve this image file to you as WebP, with a typical file size of around 25 KB!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Automatic detection of user’s browser and automatic detection of the actual display size of the image, allowing the CDN to intelligently determine which file format and quality/file size to serve the user!&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The end result is pretty magical. Let’s say your users upload original images in the 5 MB range. These original, very large, high-quality images get stored in your S3-compatible origin. When they or other users view this image in your app, say as a thumbnail in an image gallery, your Image CDN serves each image as a tiny 10 KB thumbnail version! When a user clicks to view a larger version of that image in a lightbox, your Image CDN servers a larger, higher quality 30 KB version. All automatically, without you doing anything other than the initial CDN setup. You can use the CDN’s API to manually override optimizations, allowing users to download the original high-quality image version or to force the CDN to always serve a specific file type, size, or quality.&lt;/p&gt;

&lt;p&gt;If you plan to include more than a few images in your application, consider using an Image CDN to speed up your users’ browsing experience!&lt;/p&gt;

</description>
      <category>ui</category>
      <category>ux</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Marketing Automation: Implement a Single Source of Truth</title>
      <dc:creator>John Aitchison</dc:creator>
      <pubDate>Thu, 27 Feb 2025 23:42:41 +0000</pubDate>
      <link>https://dev.to/johnai/marketing-automation-implement-a-single-source-of-truth-194a</link>
      <guid>https://dev.to/johnai/marketing-automation-implement-a-single-source-of-truth-194a</guid>
      <description>&lt;p&gt;Marketing automation is a powerful tool for engaging users, converting prospects, and reducing churn. Over the past 5 years, I think we’ve experienced a seismic shift in architecture and tooling in this space that, for companies that have stayed at the forefront of these technologies, has enabled massive improvements in how we advertise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recent History
&lt;/h3&gt;

&lt;p&gt;Just a few years ago, organizations wanting to implement marketing automation reliably and at scale had a limited set of what I’ll call black box options. CDPs like Segment led the way. Their premise was simple: dump data into the CDP, then use the CDP to enable customer interactions in external tools.&lt;/p&gt;

&lt;p&gt;I used Segment in production for many years to engage both our B2C and B2B customers. In all honesty, it worked pretty well. The problem was that your customer data was stuck in a black box, one to which you had very little access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Warehouse / Lakehouse: Single Source of Truth
&lt;/h3&gt;

&lt;p&gt;Enter the modern data warehouse. As Snowflake, BigQuery, Databricks, etc. started to gain in popularity, an idea arose: if all of our customer data is in our data warehouse, shouldn’t &lt;em&gt;the warehouse&lt;/em&gt; be the single source of truth for customer data?&lt;/p&gt;

&lt;p&gt;The answer seems to be a resounding yes.&lt;/p&gt;

&lt;p&gt;My team was one of the early users of Hightouch; we were stuck in Segment’s black box, but most of our customer data was already in BigQuery. Hightouch started with the simple premise that #1, your data is in your data warehouse #2, we’ll help you pipe that data to the tools your marketing team uses. We set up on their generous free tier and, in no time, had some custom Facebook audiences set up to automatically update every 24 hours. We were already using dbt to build custom data on our users within our data warehouse; Hightouch made it easy to activate that data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reverse ETL
&lt;/h3&gt;

&lt;p&gt;What Hightouch built became known as Reverse ETL. “Reverse” refers to the fact that instead of piping data from a database into a data warehouse, we’re piping data &lt;em&gt;out&lt;/em&gt; of our warehouse into external tools. Think Facebook Audiences, Google Ads, Intercom, etc.&lt;/p&gt;

&lt;p&gt;With the advent of Hightouch and Reverse ETL, you can now combine, slice, and dice data however you see fit within your data warehouse and then use that data in hundreds of marketing (and other) tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Quick Simplification
&lt;/h3&gt;

&lt;p&gt;If this article hasn’t made much sense to you, if you’re not very familiar with data warehouses or marketing automation in general, let me give you a quick real-world overview of how you might actually implement some of this in your organization.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You’ve got data about your users in a database of some kind. You’ve also got data from users taking actions within your app (e.g. clicking around, opening their shopping cart, visiting a Subscribe page, etc.) and even data from users taking actions in customer service tools like chat applications.&lt;/li&gt;
&lt;li&gt;Send that data to a data &lt;em&gt;warehouse;&lt;/em&gt; this is what you’ll see referred to as ELT or ETL. I love Airbyte for simple, straightforward EL. You can think of warehouses as relational databases (PostgreSQL, MySQL, etc.) that are optimized for analytical rather than transactional workloads.

&lt;ul&gt;
&lt;li&gt;If you’ve got a lot of unstructured data, you may want to consider data &lt;em&gt;lakehouse&lt;/em&gt; options.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Now that you have lots of data about your users in one place, transform that data to make it useful. For example, calculate the customer lifetime value and the last date each of your users made a purchase. I’m a big fan of dbt for transformations in the warehouse, but there are other options.&lt;/li&gt;

&lt;li&gt;Finally, activate that data and make it useful. We could, for example, create two Custom Facebook Audiences: one for users who have purchased relatively recently and one for users who have higher than a $100 CLV but haven’t purchased in the last six months. Here’s where Hightouch’s Reverse ETL comes into play: it will pull the data from your data warehouse at regular intervals and update the Facebook audiences accordingly.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;And voila, you have powerful marketing automation following best practices!&lt;/p&gt;

</description>
      <category>dataengineering</category>
      <category>marketing</category>
    </item>
    <item>
      <title>Logging, For Goodness Sake!</title>
      <dc:creator>John Aitchison</dc:creator>
      <pubDate>Thu, 27 Feb 2025 22:43:24 +0000</pubDate>
      <link>https://dev.to/johnai/logging-for-goodness-sake-1j7d</link>
      <guid>https://dev.to/johnai/logging-for-goodness-sake-1j7d</guid>
      <description>&lt;p&gt;This is going to be a brief article primarily aimed at junior developers: when you’re building applications in the wild, things can and will go wrong in production. Whether accidental bugs, API downtime that’s out of your control, or outdated developer docs that lead you astray, you’ll build software that doesn’t work perfectly 100% of the time. Like death and taxes, there’s no getting around it.&lt;/p&gt;

&lt;p&gt;The key is &lt;em&gt;building so that you’re notified when things go wrong&lt;/em&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  Beyond Error Logging
&lt;/h3&gt;

&lt;p&gt;Even as a junior engineer, you’re probably familiar with &lt;em&gt;error&lt;/em&gt; logging. Popular tools like Sentry make logging errors a mostly painless process; in fact, for most front and back-end tech stacks, there are options available for automatically logging errors. Database administrators and microservices architects often have a tougher problem, but error logging is usually not an impossible proposition.&lt;/p&gt;

&lt;p&gt;What often gets missed by junior engineers is logging &lt;em&gt;unexpected situations&lt;/em&gt; that don’t necessarily cause an error to be thrown. A good example is making an API call. Here’s some production TypeScript from an app I lead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;onCompleted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SubscriptionStartResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;stuSubsCreateportalurl&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;portalUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setStripePortalUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stuSubsCreateportalurl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;portalUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;Sentry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;captureException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unexpected successful response, GetStripePortalUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;extra&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// more code to handle this situation in the UI/UX&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;onCompleted&lt;/code&gt; indicates that we’ve gotten a successful (200) response from our API. In the &lt;code&gt;if&lt;/code&gt; case, we got what we expected: a Stripe URL that will allow our users to view their subscription details. That’s the &lt;em&gt;only&lt;/em&gt; successful response we ever expect to receive. If we get a 200 and &lt;code&gt;res.stuSubsCreateportalurl.portalUrl&lt;/code&gt; does not exist, something has gone quite wrong in our back-end. So we use our logging tool, Sentry, to log this situation.&lt;/p&gt;

&lt;p&gt;Something unexpected has occurred in our application, but we’ll know about it!&lt;/p&gt;

&lt;p&gt;(Note: I’ve simplified the code a bit; our error checking was slightly more complicated in practice than the code above shows)&lt;/p&gt;

&lt;h3&gt;
  
  
  Try / Catch Can Be Dangerous
&lt;/h3&gt;

&lt;p&gt;In many languages, try/catch is powerful. It allows your application to continue after what otherwise would have been a fatal runtime error. That said, it’s dangerous. If you wrap code in a try/catch, most logging tools &lt;em&gt;won’t&lt;/em&gt; automatically log errors that occur within the try.&lt;/p&gt;

&lt;p&gt;You often &lt;em&gt;want&lt;/em&gt; to be notified if errors occur in the try, even though you don’t want your program to stop execution. To do so, you’ve got to remember to log errors in the catch. Engineers forgetting this principle have led to some pretty insidious bugs throughout my career. No logging and the occasional user complaint “It doesn’t work!” is a recipe for a nightmare.&lt;/p&gt;

&lt;p&gt;So, use your logging tool to log errors in the catch unless you really &lt;em&gt;really&lt;/em&gt; know you don’t want to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// some code that can throw&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// log the error!&lt;/span&gt;
  &lt;span class="nx"&gt;Sentry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;captureException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Include Important Data
&lt;/h3&gt;

&lt;p&gt;As a final note, I’ll add that when unexpected things happen in your app, having data that might help you determine what went wrong can be extremely helpful. Most logging tools allow you to include extra data in your log message. Think like a senior engineer — stop and consider what can go wrong, how it can go wrong, and what data will be helpful when debugging:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;Sentry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;captureException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// the error object&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="c1"&gt;// here we get to include extra data that might be helpful when debugging&lt;/span&gt;
    &lt;span class="na"&gt;extra&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="na"&gt;thing1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;someData1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;thing2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;someData2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>webdev</category>
      <category>programming</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Unified Data Analytics via a Semantic Layer</title>
      <dc:creator>John Aitchison</dc:creator>
      <pubDate>Thu, 27 Feb 2025 22:03:09 +0000</pubDate>
      <link>https://dev.to/johnai/unified-data-analytics-via-a-semantic-layer-gam</link>
      <guid>https://dev.to/johnai/unified-data-analytics-via-a-semantic-layer-gam</guid>
      <description>&lt;p&gt;One of the most important principles in software engineering, in my opinion, is single source of truth. It applies up and down the chain, from databases to React front ends to data engineering and analytics. The Semantic Layer is a relatively new concept (outside of very large organizations that were able to create their own custom solutions) that allows us to apply the single source of truth construct to data analytics: define your data objects in one centralized place and reuse them everywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Simple Example
&lt;/h3&gt;

&lt;p&gt;I’m not quite happy with that definition above; it’s a little convoluted for my taste, so let’s look at a simple example. Business leaders in your organization probably want some sort of dashboard where they can see how many active subscribers your service currently has. We might build a database table &lt;code&gt;subscribers&lt;/code&gt; something like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;customer_id&lt;/th&gt;
&lt;th&gt;subscribed&lt;/th&gt;
&lt;th&gt;trialing&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;uuid1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uuid2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uuid3&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If &lt;code&gt;subscribed = 1&lt;/code&gt; and &lt;code&gt;trialing = 0&lt;/code&gt; , the user is actively subscribed, and we want to show them in our dashboard’s total count of subscribers. The query is simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;subscribers&lt;/span&gt;
&lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;subscribed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;trialing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As your organization grows, you’ll inevitably create multiple dashboards, ad hoc analyses, Jupyter notebooks, and even end up using multiple data analytics tools. &lt;/p&gt;

&lt;p&gt;What happens when someone who’s less familiar with your database forgets the &lt;code&gt;and trialing = 0&lt;/code&gt; bit? Now they’re looking at, and potentially making important business decisions based on an incorrectly high number.&lt;/p&gt;

&lt;p&gt;Potentially worse, consider the very real possibility of making some change in the future that requires an update to the definition of “is subscribed.” Maybe you add a new column &lt;code&gt;provided_free&lt;/code&gt; that indicates subscriptions that are provided to users for free as part of marketing initiatives. You now have a major, major headache: you’ll need to find &lt;em&gt;every&lt;/em&gt; usage of this query in &lt;em&gt;every&lt;/em&gt; analytics tool, notebook, and analysis, and carefully update each one to include &lt;code&gt;and provided_free = 0&lt;/code&gt;. Yikes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Single Source of Truth to the Rescue
&lt;/h3&gt;

&lt;p&gt;A Semantic Layer allows you to centralize the “users subscribed” definition in one single, easy-to-update place. dbt’s Semantic Layer, formerly a separate project named MetricFlow, is the only tool I’ve personally used in production, but there are a number of options on the market today. I don’t want to get bogged down in code as each Semantic Layer tool is different, but in dbt we’d do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dimensions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;is_subscribed&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;True&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;each&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;paying&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;subscriber,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;false&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;otherwise'&lt;/span&gt;
    &lt;span class="na"&gt;expr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;case when subscribed = 1 and trialing = 0 then &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="s"&gt; else &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="s"&gt; end&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;categorical&lt;/span&gt;

&lt;span class="na"&gt;measures&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;all_customers&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;The&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;distinct&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;count&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;paying&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;customers&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;by&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;account&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;creation&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;date'&lt;/span&gt;
    &lt;span class="na"&gt;agg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;count_distinct&lt;/span&gt;
    &lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;Dimension('is_subscribed')&lt;/span&gt;&lt;span class="pi"&gt;}}&lt;/span&gt; &lt;span class="s"&gt;is &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;agg_time_dimension&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;created_at&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;dbt’s Semantic Layer capabilities take this code and make it queryable in your analytics tools. Instead of the raw &lt;code&gt;select count(*)&lt;/code&gt; SQL, we query the Semantic Layer &lt;code&gt;all_customers&lt;/code&gt; measure. &lt;/p&gt;

&lt;p&gt;In the future when our back-end engineers add the &lt;code&gt;provided_free&lt;/code&gt; field, they’ll ping us in analytics: “bad news, we need to update &lt;em&gt;every&lt;/em&gt; count of subscribers everywhere to include &lt;code&gt;provided_free = 0&lt;/code&gt;"  Rather than a week or more of a nightmare digging through all of our analytics tools, we can simply head into &lt;code&gt;dbt&lt;/code&gt; and update the &lt;code&gt;is_subscribed&lt;/code&gt; dimension!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;case when subscribed = 1 and trialing = 0 and provided_free = 0 then &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="s"&gt; else &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="s"&gt; end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>analytics</category>
      <category>dataengineering</category>
    </item>
    <item>
      <title>Build vs. Buy — Focus on Customer Value</title>
      <dc:creator>John Aitchison</dc:creator>
      <pubDate>Thu, 27 Feb 2025 21:18:19 +0000</pubDate>
      <link>https://dev.to/johnai/build-vs-buy-focus-on-customer-value-knk</link>
      <guid>https://dev.to/johnai/build-vs-buy-focus-on-customer-value-knk</guid>
      <description>&lt;p&gt;Software applications that customers want to use typically involve more than one feature. A social network’s primary value to consumers is (ideally) connecting people via technology; they’ll probably need a solid file uploader and CDN. Your favorite calendar app’s primary value is likely its ability to organize events in your life; they’ll probably need a database that’s fast, ACID compliant, and highly available.&lt;/p&gt;

&lt;p&gt;As engineers and product people, we love building things. That’s our job! When you have the option to &lt;em&gt;buy&lt;/em&gt; something like a file uploader and associated CDN or build your own, you should take a step back and compare the value each option will bring to your customers.&lt;/p&gt;

&lt;h3&gt;
  
  
  What primary value do you bring your customers, and what are your comparative advantages?
&lt;/h3&gt;

&lt;p&gt;If you’re building the next great social network, what would be a more valuable way to spend your engineering resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 month building a custom file uploader that works on desktop and mobile devices, has great test coverage, and is well documented in your component library&lt;/li&gt;
&lt;li&gt;1 week implementing an already existing open-source file uploader component/library that’s used by hundreds of thousands of other companies who can collectively find and quickly fix bugs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Likely the latter, allowing you 3 extra weeks to build something else your customers highly value (and save you maintenance time down the road via the power of the collective open-source community finding and fixing bugs). If, instead of a social network, your team is building the next great CDN, a custom file uploader that you could then provide to your customers as a free added feature might be decisive. Building your own custom file uploader might be extremely valuable to your users, and it’s likely that your engineering team has extensive domain knowledge.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: On-Demand Video
&lt;/h3&gt;

&lt;p&gt;At my language education company, our primary value to customers was 1-on-1 and small group classes with a real teacher (in an online classroom we created ourselves). Eventually, we decided to build on-demand video as a free feature for our customers: teachers would upload short, TikTok-style educational videos that students could watch 24/7. In our customer interviews, students were really excited about this as a way they could improve their language skills outside of lessons with their teacher.&lt;/p&gt;

&lt;p&gt;We had some big decisions to make, but one of the most important was whether to build our own video infrastructure or use an off-the-shelf solution.&lt;/p&gt;

&lt;p&gt;While we had expertise in live video chat, streaming on-demand video is a different beast. Encoding, global edge hosting, providing video streams at lower or higher qualities based on the end-user’s device and connection speed…if you want to provide low-latency, high-quality streaming video, you’re stepping into a complex technical challenge!&lt;/p&gt;

&lt;p&gt;Fortunately, we found that Mux has solved this problem really well. They provide an uploader, player, and all the complex back-end required to ingest video and allow users to play it back anywhere in the world on any device. The calculus was easy: paying Mux $0.00096 per streaming minute plus a minimal fee for storage was by far the best option for our team.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgn3kcw2ayzbxym54nrk4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgn3kcw2ayzbxym54nrk4.png" alt="Image description" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  It’s Not Always Cut and Dried
&lt;/h3&gt;

&lt;p&gt;The build vs. buy decision isn’t always as simple as our Mux example. You may discover that nobody has solved your technical challenge efficiently yet, or you may discover that the cost is prohibitive (looking at you, Data Catalogs…someone needs to disrupt that space!).&lt;/p&gt;

&lt;p&gt;Regardless of the situation, the important step is ensuring you take the time to compare and contrast the value to your customers of a custom-built solution vs. an off-the-shelf solution.&lt;/p&gt;

</description>
      <category>agile</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Software Engineering: Slow is Smooth, Smooth is Fast</title>
      <dc:creator>John Aitchison</dc:creator>
      <pubDate>Thu, 27 Feb 2025 20:29:30 +0000</pubDate>
      <link>https://dev.to/johnai/software-engineering-slow-is-smooth-smooth-is-fast-4gl1</link>
      <guid>https://dev.to/johnai/software-engineering-slow-is-smooth-smooth-is-fast-4gl1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;If I had an hour to solve a problem, I’d spend 55 minutes thinking about the problem and 5 minutes thinking about solutions.&lt;/p&gt;

&lt;p&gt;Albert Einstein&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’ve had the opportunity to mentor quite a few junior software engineers, and by far the #1 piece of advice I give is simple: &lt;em&gt;slow down, spend more time thinking than writing code&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I first heard “slow is smooth, smooth is fast” on the baseball field; I wanted to play shortstop, and I look up to players like Javier Baez who make fielding a ground ball look like ballet. If you’re not a baseball fan, think of any movement-based activity — dancing, gymnastics, or even crochet — and picture someone great at that activity. The one thing they all have in common is their movements are incredibly &lt;em&gt;smooth.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In my experience, the same principle applies to technical fields: you’ll build better solutions to complex problems if you spend more time thinking than you do building. Go slow to move fast.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stop Coding, Start Engineering
&lt;/h3&gt;

&lt;p&gt;Fortunately, I quickly realized I wasn’t destined for baseball greatness. As I started my education and then career in aerospace engineering, I learned the value of deep thinking early on. One of my professors highlighted this in a lecture, and it has stuck with me ever since: the best people in technical fields typically develop the best problem-solving skills coupled with field-specific knowledge and the ability to work in a team. Solving complex technical problems in elegant, reliable ways requires deep thinking. And the more brains you have working on a problem, the better solutions you’ll develop.&lt;/p&gt;

&lt;p&gt;In the software world, I think of this as coding vs. engineering. &lt;/p&gt;

&lt;p&gt;Coders are folks capable of writing code. You can give them a task, that inevitable TODO list app, and they’ll get it built. Think back to your first Hello World program: you were a coder.&lt;/p&gt;

&lt;p&gt;Engineers are problem solvers. They can take an ill-structured problem (one without one clear “correct” solution) and develop an elegant solution through a combination of personal problem-solving ability and teamwork. &lt;/p&gt;

&lt;h3&gt;
  
  
  Spend More Time Thinking Than Coding
&lt;/h3&gt;

&lt;p&gt;One simple key to developing engineering skills is to spend more time thinking than you do coding. Slow down! When given something to work on, even if you’re told &lt;em&gt;exactly&lt;/em&gt; what and how to build a particular feature, take the time to step back and think. Brainstorm as many ways as possible to solve the problem. Ideally, loop in a teammate and get their ideas.&lt;/p&gt;

&lt;p&gt;Unfortunately, even though Agile and Scrum principles dictate that the team themselves are best capable of determining &lt;em&gt;how&lt;/em&gt; to get work done, many organizations still practice a top-down, dictatorial style of engineering.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Build projects around motivated individuals. Give them the environment and support they need, and trust them to get the job done.&lt;/p&gt;

&lt;p&gt;Agile Principle #5&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For most organizations, this is shortsighted. Do you want to create a team of people capable of taking direct orders from that one brilliant engineering lead (who is going to retire or move on at some point), or do you want to create a systemic approach and team capable of working together to solve complex problems for your customers?&lt;/p&gt;

&lt;h3&gt;
  
  
  Draw, Diagram
&lt;/h3&gt;

&lt;p&gt;Humans learn incredibly well in a spatial context, so take time to draw things out. I recommend using a tool like Miro to diagram complex problems (it’s also great for things like customer journey mapping, basic wireframing, etc.).&lt;/p&gt;

&lt;p&gt;System architecture is one of the best use cases for diagramming, but even if you’re building a new front-end feature that has some complexity, give it a try.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3utp0lp8bzsm9yzhafha.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3utp0lp8bzsm9yzhafha.jpg" alt="Image description" width="800" height="849"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[ Side note: ByteByteGo is a great way to learn the basics of a wide variety of software system architecture ]&lt;/p&gt;

&lt;p&gt;Imagine trying to explain, in writing, what the diagram above depicts. It’s possible, and often even a requirement, to do so, but a picture is worth a thousand words as they say. Our brains process visual representations differently than textual representations. A diagram gives you a 10,000-foot view of your problem at a glance.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Real World Has Deadlines
&lt;/h3&gt;

&lt;p&gt;We all have deadlines, and we’re not trying to discover the laws of nature like Einstein was. We’re building software and competing in a marketplace. If you’re at an established company building highly technical B2B software, you’ll probably be given more leeway to spend time thinking than you would at a B2C sales-driven startup.&lt;/p&gt;

&lt;p&gt;Regardless, use the time available to you to do more thinking upfront. I think you’ll not only discover that you write better software but also do so faster than you’ve done in the past.&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>programming</category>
    </item>
    <item>
      <title>Localization Opportunities in SaaS</title>
      <dc:creator>John Aitchison</dc:creator>
      <pubDate>Thu, 27 Feb 2025 18:06:46 +0000</pubDate>
      <link>https://dev.to/johnai/localization-opportunities-in-saas-2gpf</link>
      <guid>https://dev.to/johnai/localization-opportunities-in-saas-2gpf</guid>
      <description>&lt;p&gt;There are over 8 billion people on our planet, and roughly 1.5 billion of them speak English — approximately 19%. Of those 1.5 billion, less than 400 million are native English speakers. &lt;/p&gt;

&lt;p&gt;That means there’s a theoretical maximum 500% increase in your total addressable market (20% of the market speaks English, 20% → 100% is a 5x increase) simply by localizing your application. The actual increase will, of course, be something lower than that theoretical maximum — not everyone everywhere who speaks every language is a potential user of your service — but I do think it’s a good point of reference for those of us in the English-centric world to begin understanding the magnitude of the opportunity.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the Data Says
&lt;/h3&gt;

&lt;p&gt;Theory is fun, but what does real-world data tell us? Unfortunately, high-quality data, as I would define it, is scant. &lt;a href="https://csa-research.com/" rel="noopener noreferrer"&gt;CSA Research&lt;/a&gt; is one of few independent organizations focused on actionable globalization research. Some of their findings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;75% of potential customers will immediately look elsewhere if content is not in their language&lt;/li&gt;
&lt;li&gt;40% of consumers flatly refuse to purchase in any language other than their native language&lt;/li&gt;
&lt;li&gt;Some of their research shows that each dollar spent on localization enables 5.8 times as much revenue as would that same spending on English. Meaning that rather than advertise more to English customers, create more English content, etc., if that money were spent on localizing existing content/advertising you would see a 5.8x better return.

&lt;ul&gt;
&lt;li&gt;I read more deeply into their research backing this specific claim, and it’s very theoretical, to say the least. While I do think it has enough merit to mention here, I would take it with a large grain of “every industry/product/service/market is different” salt.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  How can we validate?
&lt;/h3&gt;

&lt;p&gt;Before diving headfirst into localizing all of our content everywhere in all of our web and mobile applications, marketing sites,  branding, and content marketing channels, validating the potential value of this opportunity on a smaller scale is a great starting point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customer Interviews&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Continually interviewing customers is a best practice in general, and before embarking on localization can be a great way to get some initial data. What can be especially valuable is finding potential customers who are from non-English speaking countries and did &lt;em&gt;not&lt;/em&gt; end up using your software. Hopefully, you already have some data collection in place that allows you to determine users’ approximate location and, with a bit of data wrangling, generate a list of those users who did not end up as paying customers. Interview them with an eye toward localization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Marketing Site&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Localizing your marketing site is, in most cases, going to be &lt;em&gt;much&lt;/em&gt; easier, faster, and cost-effective than localizing your applications. If you happen to have built your marketing site using a tool like Webflow or Framer, a small team can localize your site in multiple languages in a week or two. If your marketing site is built and maintained by your engineering team, it’s certainly a more involved project, but it is much smaller in scale than localizing applications. &lt;/p&gt;

&lt;p&gt;Remember to measure what matters. Ideally, you’ll be able to compare conversion rates of non-English visitors before and after localization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Essential in the B2C World
&lt;/h3&gt;

&lt;p&gt;If your software is primarily targeted toward individual consumers, I would suggest that localization is &lt;em&gt;almost&lt;/em&gt; essential. Recall that 6.5 billion people, 80% of the world’s population, don’t understand English. You’re likely missing a huge opportunity there if you don’t localize. Discovery and validation due diligence is certainly warranted, but if your app is only available in English it’s an opportunity I would prioritize researching.&lt;/p&gt;

&lt;h3&gt;
  
  
  B2B: Test and Validate
&lt;/h3&gt;

&lt;p&gt;English is undoubtedly the de facto language in the B2B SaaS world. Companies around the world expect to use software tools in English, even in cases where many of their employees don’t speak the language. I would suggest interviewing and small-scale tests to validate whether internationalization is currently a top-priority opportunity your company should pursue, keeping in mind that this opportunity is only going to grow over time as internet access and incomes around the world increase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tools and Strategies for Application Localization
&lt;/h3&gt;

&lt;p&gt;I want to briefly touch on an overarching strategy for localizing your software applications, one I’ve used in production. Fortunately, over the past decade there have been some incredible advances that make it &lt;em&gt;much&lt;/em&gt; easier and cost-effective to localize. Let’s consider an example company that has both a React web and React Native mobile application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React/React Native Localization Frameworks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You’ll first need a localization framework for your applications. The general idea is that your framework will help you extract all of the strings in your application to some centralized store, from which you can translate each string.&lt;/p&gt;

&lt;p&gt;As of 2025, my personal recommendation is Lingui, but take a look at react-i18next and react-intl. Lingui takes a different approach, which I think makes localization for your engineering team much smoother; rather than a JSON string approach, you use React components and hooks. It’s a clever approach that has many benefits over legacy solutions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Translation Management System (TMS)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Second, you’ll need a way to actually translate each string that your framework extracted.&lt;/p&gt;

&lt;p&gt;Small teams and open-source projects may choose to do this manually, but a translation management system makes doing this much more scalable. In a nutshell, as strings are added to your application (or original language strings are modified), you’ll git push those strings to a TMS. Within the TMS, you can choose between a combination of machine learning, AI, and real translators to translate each string. When the translation is finished, you git pull those translations back into your project.&lt;/p&gt;

&lt;p&gt;A good 10,000-foot view is that your app itself is the source of truth for your strings in the original language (probably English, if you’re reading this article), and the TMS is the source of truth for the translated strings.&lt;/p&gt;

&lt;h3&gt;
  
  
  International Markets Will Continue to Grow
&lt;/h3&gt;

&lt;p&gt;Internet access and incomes around the world continue to grow. As developing countries climb the economic ladder, more and more consumers and companies within those countries will become potential users of your products. Will you be ready to onboard them?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1lgbmmd1h8dcw3ihe6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1lgbmmd1h8dcw3ihe6g.png" alt="Image description" width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>saas</category>
      <category>webdev</category>
      <category>marketing</category>
    </item>
    <item>
      <title>React + Relay + Hasura GraphQL: a Stack Made in Typescript Heaven</title>
      <dc:creator>John Aitchison</dc:creator>
      <pubDate>Thu, 27 Feb 2025 00:38:49 +0000</pubDate>
      <link>https://dev.to/johnai/react-relay-hasura-graphql-a-stack-made-in-typescript-heaven-3egk</link>
      <guid>https://dev.to/johnai/react-relay-hasura-graphql-a-stack-made-in-typescript-heaven-3egk</guid>
      <description>&lt;p&gt;Tech stacks are a dime a dozen: everybody has one, and we all think ours is the best! The fact is there are &lt;em&gt;many&lt;/em&gt; great tech stacks out there, there’s no right answer when selecting one, and the one your team chose isn’t necessarily any better or worse than the one your top competitor chose.&lt;/p&gt;

&lt;p&gt;That said, for our team of TypeScript engineers we found this stack helped us build more than 2x faster (yes, we measured) and we all enjoyed it very much, so I wanted to mention it somewhere!&lt;/p&gt;

&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Engineers can theoretically work on both the front and back-end; they only need to know one language: TypeScript!&lt;/li&gt;
&lt;li&gt;Type safety from your data store to the front-end&lt;/li&gt;
&lt;li&gt;The awesome benefits of GraphQL without the headaches of creating a server from scratch

&lt;ul&gt;
&lt;li&gt;Note: if you’ve tried GraphQL before, loved the FE benefits but hated the BE complexity, don’t stop reading yet. Hasura takes away 95% of that difficulty.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Relay is very opinionated and allows even junior engineers to build a solid, performant FE&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Relay has a steeper learning curve than many front-end data management options&lt;/li&gt;
&lt;li&gt;Hasura is a paid product&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  React + Relay
&lt;/h3&gt;

&lt;p&gt;You may know that Facebook built React, but did you know they also built a front-end GraphQL client called Relay (&lt;a href="https://relay.dev/" rel="noopener noreferrer"&gt;relay.dev&lt;/a&gt;)? In fact, if you install the Relay Chrome extension and open your Facebook account, you’ll get a cool view of your own data/state management within the app!&lt;/p&gt;

&lt;p&gt;You’re probably familiar with React so I won’t dive into it much here, but I do want to talk a bit about Relay.&lt;/p&gt;

&lt;p&gt;Relay is a GraphQL client, similar to Apollo client, but does far more than just help you query data. If you’ve used Redux, a frontend library for centralized state management, that’s the closest analogy I’m aware of.&lt;/p&gt;

&lt;p&gt;And Relay is fantastic. I’ve used it in multiple production apps and can’t recommend it highly enough. It’s opinionated, which some engineers don’t like. The benefit being that as long as you don’t completely botch its implementation, you’ll end up with a React app that is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performant&lt;/li&gt;
&lt;li&gt;Data consistent (”you have 2 unread messages” will display “2” correctly everywhere throughout your app, rather than displaying 3 in one place, 2 in another, 4 in another)&lt;/li&gt;
&lt;li&gt;Easy to maintain&lt;/li&gt;
&lt;li&gt;Declarative components + their data requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a nutshell, it makes building a component-based React app easy. When adding a component to your app, you’ll simply create a data &lt;code&gt;fragment&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="err"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;StoryFragment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;graphql`&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;fragment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StoryFragment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Story&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;thumbnail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;`;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This fragment should &lt;em&gt;only&lt;/em&gt; include the data that &lt;em&gt;this&lt;/em&gt; specific component needs. In this example, we’re creating a newsfeed component that will display multiple stories (and each story has a title, a summary, and a thumbnail image).&lt;/p&gt;

&lt;p&gt;Within that component, you guessed it, you use that fragment! The major benefit here is that your component &lt;em&gt;declaratively&lt;/em&gt; defined &lt;em&gt;only&lt;/em&gt; the data it needed.&lt;/p&gt;

&lt;p&gt;Well, we usually have multiple components on a page, right? Right. When a user loads a route in your app, you’ll typically create one single GraphQL query — one single call API call to the network — to get &lt;em&gt;all&lt;/em&gt; of the data the components on the page need. Let’s imagine that on the Home page, we’re going to display stories and a few of the user’s settings. We might create a UserSettingsFragment fragment for the component that will be displaying the user’s settings.&lt;/p&gt;

&lt;p&gt;Then, when writing our query for this page, we &lt;em&gt;spread&lt;/em&gt; these fragments into the query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="err"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;HomepageQuery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;graphql`&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HomepageQuery&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="n"&gt;StoryFragment&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="n"&gt;UserSettingsFragment&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;`;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There’s a lot of magic under the hood. For example, if you’ve already gotten all the data this query requires (via the user having previously loaded this route or even via the user having loaded other routes that, combined, queried all of the data we need here) no network call will be made. Relay will see that it already has all of the data needed and have React display the Home page immediately without suspending. Voila, you’ve got a data-consistent, performant app!&lt;/p&gt;

&lt;p&gt;That’s the 10,000-foot view. You’ll want to dig more deeply into Relay to learn more of its benefits and drawbacks, but from experience I can say that once you’re past the learning curve it’s a great way to build a well-organized, performant, easy-to-maintain React application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hasura GraphQL
&lt;/h3&gt;

&lt;p&gt;I’ve talked to quite a few engineers about GraphQL, and a common viewpoint is that it’s too complicated to implement. Digging further, what they mean is that creating the back-end server is complicated; using GraphQL on the front-end is typically a smooth and enjoyable process.&lt;/p&gt;

&lt;p&gt;That’s where tools like Hasura come in. There are other options, but I’ve only personally used Hasura in production. I don’t work for them, and I wasn’t a big fan of their dramatically reduced open-source support a few years ago, but overall, it’s an amazing tool to build a GraphQL back-end.&lt;/p&gt;

&lt;p&gt;Like Relay, I’d classify it as a declarative way to build. Instead of manually creating GraphQL resolvers, you can simply define what data from your data store should be accessible from a GraphQL API endpoint (they also offer a REST endpoint which can be helpful particularly if you want to update your application to GraphQL piece by piece). There’s RBAC built in: create a &lt;code&gt;user&lt;/code&gt; role, an &lt;code&gt;admin&lt;/code&gt; role, etc. and separately define what data each should have access to.&lt;/p&gt;

&lt;p&gt;With Hasura v3, you can quickly have a globally edge-distributed, autoscaling, extremely performant GraphQL API up and running. If you’re a large organization, Apollo Federation, a unified data graph across your various data sources, is built in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;p&gt;For learning material, I don’t necessarily like to recommend for-profit companies pushing their own products, but Hasura’s talks on YouTube are pretty informative if not a bit hyperbolic:&lt;/p&gt;

&lt;p&gt;“GraphQL without Relay is not worth it”&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/peI3NCsdbB0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Yes, the title is clickbait, but they do a fairly good job of arguing why this tech stack might be a good option for your team.&lt;/p&gt;

&lt;p&gt;Best of luck, give it a try in a personal project and let me know how it goes!&lt;/p&gt;

</description>
      <category>react</category>
      <category>graphql</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Iterate Frequently on Your Marketing Site, Grow with CRO</title>
      <dc:creator>John Aitchison</dc:creator>
      <pubDate>Wed, 26 Feb 2025 23:34:10 +0000</pubDate>
      <link>https://dev.to/johnai/iterate-frequently-on-your-marketing-site-grow-with-cro-3kfh</link>
      <guid>https://dev.to/johnai/iterate-frequently-on-your-marketing-site-grow-with-cro-3kfh</guid>
      <description>&lt;p&gt;In the age of product-led growth, the importance of organizations’ marketing sites seems to have somewhat diminished. As a “product person” with an engineering background, I’m fully behind the product-led growth philosophy. That said, in my chats with leaders at many organizations, it seems to me that an important opportunity is often missed: improving the conversion rate of your marketing site.&lt;/p&gt;

&lt;p&gt;I propose that someone on your team, typically marketing, sales, or product (or a combination thereof), be responsible for iteratively improving your marketing site. And by &lt;em&gt;improving,&lt;/em&gt; I don’t mean &lt;em&gt;beautifying;&lt;/em&gt; beauty is in the eye of the beholder, and it’s not something that adds value to our organization*.* I mean improving the percentage of visitors who sign up/purchase/reach whatever goal is most important to your team.&lt;/p&gt;

&lt;h3&gt;
  
  
  CRO: Conversion Rate Optimization
&lt;/h3&gt;

&lt;p&gt;First, a quick definition: conversion rate can be broadly defined as the percentage of visitors or users who reach a given goal. For your marketing site, this is often “the percentage of visitors who sign up,” “the percentage of visitors who purchase from our store,” or “the percentage of users who schedule a sales call.”&lt;/p&gt;

&lt;p&gt;Conversion rate &lt;em&gt;optimization&lt;/em&gt; is simply the practice of making changes, ideally iteratively and in a quasi-scientific fashion, in an attempt to improve conversion rates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Beauty Doesn’t Matter. Conversion Does.
&lt;/h3&gt;

&lt;p&gt;I’ve worked with quite a few website designers over the years, and I can only recall &lt;em&gt;one&lt;/em&gt; in all of those interactions who brought this concept to the table from the get-go: it doesn’t matter one bit how beautiful your website is. The &lt;em&gt;only&lt;/em&gt; thing that matters is conversion rate.&lt;/p&gt;

&lt;p&gt;Do beautiful websites convert? Sometimes, but it’s certainly not a guarantee.&lt;/p&gt;

&lt;p&gt;The best example of this concept, in my opinion, is Amazon. Few would consider Amazon to be a beautiful website even now, and those of us who were around during their early heyday know it hasn’t ever been. What Amazon is great at, obviously, is conversion. They make it easy to find what you’re looking for. They make it easy to purchase once you’ve found what you’re looking for. They make it easy to trust that you’ll receive what you purchased in a timely manner. That’s all that matters; that’s the value your marketing site brings to your organization.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzaay0757it4ayx2yui8k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzaay0757it4ayx2yui8k.png" alt="Image description" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Small Increases, Like in Investing, Equal Large Long-Term Gains
&lt;/h3&gt;

&lt;p&gt;You’re probably familiar with the power of compound interest over time. The same concept applies to conversion rates.&lt;/p&gt;

&lt;p&gt;I’ll stray from my familiar world of B2B SaaS and take the example of a typical Shopify seller. If we set an audacious, seemingly unattainable goal of &lt;em&gt;doubling&lt;/em&gt; our conversion rate, all we need to do is increase the conversion rate of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ads by 19%&lt;/li&gt;
&lt;li&gt;Landing page by 19%&lt;/li&gt;
&lt;li&gt;Shopping cart by 19%&lt;/li&gt;
&lt;li&gt;Checkout by 19%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why 19% and not 25%? Because each improvement &lt;em&gt;compounds&lt;/em&gt; over time.&lt;/p&gt;

&lt;p&gt;Now, consider your organization. If you went to your CEO tomorrow and said, “I feel fairly confident I can increase our conversion rate by 5% in 6 months and more than 10% within a year,” what would they say? How valuable would that be to your organization?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkd7q2qrp75ejgufzambj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkd7q2qrp75ejgufzambj.jpg" alt="Image description" width="800" height="632"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Statistics 101: Make Big Changes, Avoid Meek Tweaking
&lt;/h3&gt;

&lt;p&gt;One of the most common mistakes teams make when broaching the CRO world with their marketing site is making small changes: changing the primary color of your buttons, increasing the border radius of elements…meek tweaks.&lt;/p&gt;

&lt;p&gt;Smaller tweaks &lt;em&gt;might&lt;/em&gt; give you statistically significant results if you get on the order of hundreds of thousands of monthly visitors. If you aren’t familiar with statistical significance, look into online A/B testing calculators and read about why you need fairly large numbers of visitors &lt;em&gt;or&lt;/em&gt; fairly large changes in results to really be able to know with some certainty that the change you made improved your conversion rate.&lt;/p&gt;

&lt;p&gt;In the B2B world or smaller B2C companies, you may not get enough visitors for small changes to make a measurable difference. Therefore, you’ll need to focus on making significant changes to your marketing site. Remove or add pages. Add simple, single-input email signup forms on every page. Radically change or even entirely remove your signup form. I’ll get into some more ideas below, but the point is you’ll usually need to make significant changes if you want to see significant results.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Bit More Statistics
&lt;/h3&gt;

&lt;p&gt;I don’t want this to turn into a statistics deep dive, but I do want to touch on the basics of the concepts you should know. Let’s consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Poll #1 asks 10 people who they’re going to vote for in the next presidential election&lt;/li&gt;
&lt;li&gt;Poll #2 asks 10000 people who they’re going to vote for in the next presidential election&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which poll is more likely to correctly predict the outcome of the next presidential election? Poll #2, because it’s closer to a &lt;em&gt;representative sample&lt;/em&gt; of the population.&lt;/p&gt;

&lt;p&gt;Now apply this to our website:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scenario #1: 10 people visit your website, and 5 convert. You make and deploy a change. Another 10 people visit your website, and 6 convert.&lt;/li&gt;
&lt;li&gt;Scenario #2: 10000 people visit your website, and 500 convert. You make and deploy a change. Another 10000 people visit your website, and 600 convert.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In which scenario can you be more confident that the change made a &lt;em&gt;real&lt;/em&gt; improvement? Scenario #2, clearly. Put the above numbers into an online A/B testing calculator, and you’ll see that you can be more confident in scenario 2.&lt;/p&gt;

&lt;p&gt;So, larger numbers of visitors help us be more confident in our results, but what about larger changes in results?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scenario #1: 10000 people visit our website, and 500 convert. You make and deploy a change. Another 10000 people visit our website, and 510 convert.&lt;/li&gt;
&lt;li&gt;Scenario #2: 1000 people visit our website, and 500 convert. You make and deploy a change. Another 1000 people visit our website, and 700 convert.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which scenario would you be more confident in? Clearly we can be more confident that the change we made in scenario #2. The improvement we saw in #1 could very easily be down to luck, whereas the improvement we saw in #2 is less likely to due to luck.&lt;/p&gt;

&lt;h3&gt;
  
  
  Act Like Scientists &amp;amp; Statisticians, But Remember  We’re Not
&lt;/h3&gt;

&lt;p&gt;While statistically significant results are ideal, we’re not attempting to flesh out the laws of nature. Use your team’s knowledge of your company, industry, and customers to help determine whether a change you made had a positive impact. If, after deploying a chang,e you find that our A/B testing statistics tell us “there’s a 72% chance the change you made had a statistically significant impact,” you have two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Let more customers view your change (meaning, wait longer before making another change)&lt;/li&gt;
&lt;li&gt;Stop your test and make a best guess at whether the change was positive or not&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I’d argue that it’s likely more valuable to keep iterating, keep making changes than to continue running your test for a longer period of time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Some General Tactics
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Iterate Frequently / Agilely&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The most powerful tactic I’d recommend is setting up a process, a system your team follows that forces you to make regular changes. The power of experimentation is greatest if you frequently experiment. Making a major change to your marketing site once every year or two won’t be very impactful, even if the changes you make do increase conversion rates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use a Website Builder&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’m not sure why engineers sometimes resist this idea, but consider using a website builder (Webflow, Framer, etc.) for your marketing site.&lt;/p&gt;

&lt;p&gt;There are a ton of benefits when compared to having engineers build your marketing site in something like NextJS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Non-technical team members can fully plan and implement changes&lt;/li&gt;
&lt;li&gt;Changes are typically faster and easier to implement&lt;/li&gt;
&lt;li&gt;Localization and other valuable features are baked in&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Think Big&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Remember that we need to try making significant, major changes. If you’ve got a cluttered, 20-page marketing site, what if you pared it down to 3 pages? Instead of a sign-up &lt;em&gt;page&lt;/em&gt;, what if it was a modal that would pop up on the page the user is currently viewing? What if you &lt;em&gt;entirely removed&lt;/em&gt; your sign-up form and instead directly forwarded new users into an account? Try live video chat customer support. Think big.&lt;/p&gt;

&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;p&gt;Booking.com is famous for their experimentation, they’ve given a number of great talks you can find on YouTube. Other companies have written about their culture of experimentation, although Booking seems to talk a lot about their marketing site specifically.&lt;/p&gt;

&lt;p&gt;I’ve just scratched the surface of this topic. If it has piqued your interest, I highly recommend “Making Websites Win” (Blanks, Jesson). It’s full of digestible, real-world examples layered on top of overarching theory that’ll have you on your way to increased conversion rates in no time!&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>website</category>
    </item>
    <item>
      <title>Why Your Organization Should Consider Low-Code for Internal Tooling</title>
      <dc:creator>John Aitchison</dc:creator>
      <pubDate>Wed, 26 Feb 2025 20:46:52 +0000</pubDate>
      <link>https://dev.to/johnai/why-your-organization-should-consider-low-code-for-internal-tooling-50bk</link>
      <guid>https://dev.to/johnai/why-your-organization-should-consider-low-code-for-internal-tooling-50bk</guid>
      <description>&lt;p&gt;Most companies larger than sole proprietorships need some form of internal tooling, and as your company grows, this need for tooling typically grows as well. Often you’ll find that the tooling you need already exists: QuickBooks for accounting, Salesforce for CRM, etc.&lt;br&gt;
If an existing tool in the marketplace meets your needs, it’s often a good idea to use those tools rather than build your own. You’ll usually save time and money using an off-the-shelf solution, allowing you to focus on activities that bring the most value to your customers (should you spend 6 months building a custom CRM, or would that time and money be more valuable to your customers if you build that feature X which large numbers of potential customers need?).&lt;br&gt;
At some point, though, you may determine the value that a custom tool could add is high enough that you decide to explore options for building one; it’s during that exploration process you should take a hard look at low-code options!&lt;/p&gt;

&lt;h3&gt;
  
  
  What do we mean by “low-code internal tools”?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Low-Code = app “builders” that typically allow you to create custom web or mobile applications using a combination of already-built components and code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Internal Tool = a tool used by your team rather than your customers&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Retool is one of the market leaders in this space. Take a gander at their marketing site for some examples and customer stories. I’d also recommend looking at their developer docs, particularly the components section, and asking yourself how much engineering time it would take your team to simply build out a similar component library. In a nutshell, low-code tools allow you to drag and drop components, wire those components up with code, and click a button to publish your app to your team.&lt;/p&gt;

&lt;p&gt;The quintessential example is a custom CRM — imagine that rather than being constrained by existing CRM design/feature sets, you were able to build the &lt;em&gt;perfect&lt;/em&gt; solution for your team’s specific needs. That said, a CRM is not a great example; in my opinion, there are so many existing CRM solutions out there that I think it’s very likely you can find an existing tool that works well for your team. A better example might be the software that DoorDash uses to help manage its delivery drivers. That’s a very custom use case, one for which it’s unlikely existing software would work very well. They realized this and used Retool to build their custom internal software.&lt;/p&gt;

&lt;p&gt;Here’s a screenshot to give you a little better idea. The app is being built in the center of the page (the area with the gray background). We can see some &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; elements for search/filtering, a table, and some cards that probably contain data. The bottom and right-side panels are what engineers building the app will see; in this example, it looks like we’re writing some SQL queries to populate data in the table. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqr651eqx025fd16pgjfu.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqr651eqx025fd16pgjfu.jpeg" alt="Image description" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Downsides
&lt;/h3&gt;

&lt;p&gt;Before I get too far into selling low-code tools, let’s play devil’s advocate and examine some of the major downsides we should be aware of. Like anything, just because you’re building an internal tool doesn’t necessarily mean low-code is the de facto best choice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Constrained Functionality&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When your team builds a React application, nearly any functionality you can imagine is doable. It may not be &lt;em&gt;easy&lt;/em&gt;, but it’s probably &lt;em&gt;possible!&lt;/em&gt; When you use a low-code tool, that’s not the case; the functionality of the tool will constrain you. For example, many low-code tools I’ve tested and used in production do a complete browser refresh when you navigate from one page to another. Others don’t have front-end caching built in, so each time a user navigates from and back to a page, you’re making a network request (you can build caching into your back-end, of course).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Constrained UI/UX&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One major benefit of low-code tools is that they have an existing component library: tables, modals, buttons, selects, etc. Instead of having to build and maintain components, whenever your engineering team needs a table, they’ll just drag and drop one onto their app canvas. The clear downside to this is the styling of those components is very constrained. Most low-code tools I’ve used allow custom color schemes and border-radius, but that’s about it. You get what you get. Over time I see this improving, especially given that many of these low-code tools want to capture more of the external customer app market from companies like Bubble.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(Yet Another) New Thing to Learn&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your engineering team already knows React, Angular, or Vue; when you choose a low-code tool, you’re asking them to learn something new. This is a bit of an ongoing joke in the JavaScript world (for good reason), and you’ll probably be the butt of a few underhanded comments from your engineering team if you propose low-code. That’s okay. Have a discussion with your team and ask them to evaluate the low-code themselves. Each tool has its own way of doing things and its own constraints. Learning those constraints takes time. That said, I’ve found that junior engineers with more than a year or so of front-end experience are typically able to begin building in these tools very quickly. They’re &lt;em&gt;much&lt;/em&gt; easier to learn than, say, learning React.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Downtime&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Downtime is out of your control. If it’s down, you’re at the mercy of another company. If your internal tooling is mission-critical, this is absolutely something to have a conversation about. I’d encourage you to compare and contrast the uptime you think your own engineering team can provide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Breaking Changes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you wander through Retool’s community forums, you’ll find one of my posts that says something to the effect of “Please move slower and break fewer things” which garnered a lot of discussion. Low-code companies need to be agile and need to move fast, just like we at our own companies need to. When all of the buttons across all of your internal tools which are hooked up to an async API call begin failing though, this can be quite a bad thing. Usually, these companies are quick to respond, but again, there’s nothing you can do until they revert or fix their breaking change. Unlike in your own app, there’s no SEMVER, no way for you to revert the change manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  Engineering is Expensive and Scarce
&lt;/h3&gt;

&lt;p&gt;Now that we’ve taken a look at why you might &lt;em&gt;not&lt;/em&gt; want to go the low-code route, let’s consider some reasons I’ve personally found it to be a great option for internal tooling. First and foremost, engineering is expensive, scarce, and usually extremely valuable to your customers (you know, the people who actually generate revenue!)&lt;/p&gt;

&lt;p&gt;Building an app using a low-code tool is potentially &lt;em&gt;an order of magnitude&lt;/em&gt; faster than building the same tool in something like React. I don’t say that lightly and I’m not exaggerating. Don’t take my word for it: have an engineer on your team sign up and try out one or two of these tools and report back.&lt;/p&gt;

&lt;p&gt;We all know engineering is expensive, scarce, and valuable. Compare and contrast the value to your organization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3 months of one team’s engineering resources to build an internal app in React&lt;/li&gt;
&lt;li&gt;3 weeks to build the same app in a low-code tool&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What will bring more value to your customers, the internal tool or that great feature X? With that in mind, where should your team spend the most time?&lt;/p&gt;

&lt;h3&gt;
  
  
  Extremely Agile
&lt;/h3&gt;

&lt;p&gt;Low-code tools are incredibly Agile. Once a few engineers have the initial learning under their belts (which I’d estimate would take about a week), they will be able to build &lt;em&gt;incredibly&lt;/em&gt; fast. Changes/maintenance/updates are incredibly fast as well. I could yammer on about this but I doubt I’ll be able to convince anyone who hasn’t tried using these tools. Again, I recommend getting in and building a few things, trying it out, and discovering for yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Some Non-Engineers Can Build
&lt;/h3&gt;

&lt;p&gt;One major benefit to low-code tools that I think gets commonly overlooked: some technically-minded folks who maybe aren’t engineers (e.g. product manager, data analytics, marketing tech) will often be able to learn to build things with low-code. It’s unlikely they’d be able to contribute to a React project but give them the ability to spin up a standalone low-code app, and you might be surprised by the valuable tools they build for themselves and their teams! It can even be a great option for wireframing, MVP, initial hypothesis/prototype/validation scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tips
&lt;/h3&gt;

&lt;p&gt;I’ve used low-code tools extensively over the years, testing most of the major options and using both Retool and UI Bakery for complex internal apps in production. If your team decides to take this route, here are a few tips that might be helpful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Review/Test as Many Tools as Possible Before Choosing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Analysis paralysis is real, but I do think it’s very valuable to compare as many low-code tools as possible before choosing one. Would your engineering lead decide to build your back-end via an event-driven architecture without carefully considering all the options? Probably not. Once you’ve chosen a tool and built your important internal apps in it, the cost to switch can be high.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Document Standard Practices&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Inevitably, you’ll find certain things just have to be done a particular way in your low-code tool of choice. For example, my team used GraphQL Relay, and paging through results required a particular setup in Retool. Since getting data via our API and displaying that data in a server-side paginated table was a very common task, we documented how to do this. Notion for the win!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Log Errors&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Would you build a front-end or back-end without logging? If so….well, I won’t judge, but I will say a prayer for your users! In my opinion, logging problems in internal tools is &lt;em&gt;almost&lt;/em&gt; as important as logging them in your customer apps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Be Careful With Component Updates&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While it’s great that you don’t have a component library to maintain and components are just auto-magically maintained and improved, be careful when a new version of a component comes out. All the low-code tools I’ve used let you manually decide when to update a component; you should be careful when doing this. Read the documentation, do some testing, and ensure the new version of the component has all of the features you need. Often, when a new component version is released, it won’t yet be at feature parity with the previous version, which can result in you breaking critical functionality in your apps if you aren’t careful.&lt;/p&gt;

</description>
      <category>lowcode</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
