{
  "$type": "site.standard.document",
  "content": {
    "$type": "at.markpub.markdown",
    "text": {
      "$type": "at.markpub.text",
      "markdown": "Clean. Code. Clean code. CLEAN CODE! C-L-E-A-N C-O-D-E. Clean code.\n\nWhat does that even mean? It's something we all say at some point, but it's meaningless. Or, more accurately, means different things to different people with different priorities and contexts.\n\nI'm going to focus on separating business logic from the template.\n\n## The setup\nTo illustrate this, I'll be using a code snippet I pulled from actual production code a developer on my team wrote. I've slightly modified it for clarity. Additionally, this is not meant to be an end-all-be-all way to write \"clean code\", but rather how I would approach writing this bit of code.\n\nBefore I get started, just a couple notes about the code:\n\n1. The code I show is not intended to be production-ready; it's meant to demonstrate the concepts only.\n2. I am using server-side rendered [goatee](https://github.com/simpleviewinc/goatee) for templating, so syntax may seem unfamiliar at times.\n\nLet's get into it!\n\n```html\n<picture>\n\t<source\n\t\tsrcset=\"{{image.getUrl({\n\t\t\twidth: 900,\n\t\t\theight: 300,\n\t\t\tcrop: 'fill',\n\t\t\tquality: 60\n\t\t})}}\"\n\t\tmedia=\"(min-width: 641px)\"\n\t/>\n\t<source\n\t\tsrcset=\"{{image.getUrl({\n\t\t\twidth: 1280,\n\t\t\theight: 500,\n\t\t\tcrop: 'fill',\n\t\t\tquality: 60\n\t\t})}}\"\n\t\tmedia=\"(min-width: 1025px)\"\n\t/>\n\t<source\n\t\tsrcset=\"{{image.getUrl({\n\t\t\twidth: 1600,\n\t\t\theight: 700,\n\t\t\tcrop: 'fill',\n\t\t\tquality: 60\n\t\t})}}\"\n\t\tmedia=\"(min-width: 1440px)\"\n\t/>\n\t<img src=\"/path/to/default.jpg\" alt=\"…\" />\n</picture>\n```\n\n## The issue\nHere our dev created a responsive image to draw on the page. It works! But there's a few things that stand out to me about it.\n\nFirst, there are 3 source elements that are nearly identical; that looks like an opportunity to simplify.\n\nSecond, it looks like the crop and quality properties are the same across all calls to `getUrl()`.\n\nThird, if I need to introduce another source, then I need to make yet another source element and it's own call to `getUrl()` which grows adds visual clutter to the template and promotes copy/pasting which can lead to unexpected results if the dev isn't paying attention.\n\nLet tackle this in phases.\n\n## Phase 1\nTo start, I'm going to pull out the `getUrl()` calls and make the HTML simpler to read.\n\n```html\n{{~exec(function() {\n\thelpers.var.srcSm = data.image.getUrl({ width: 900, height: 300, crop: 'fill', quality: 60 });\n\thelpers.var.srcMd = data.image.getUrl({ width: 1280, height: 500, crop: 'fill', quality: 60 });\n\thelpers.var.srcLg = data.image.getUrl({ width: 1600, height: 700, crop: 'fill', quality: 60 });\n})}}\n<picture>\n\t<source srcset=\"{{~var.srcSm}}\" media=\"(min-width: 641px)\" />\n\t<source srcset=\"{{~var.srcMd}}\" media=\"(min-width: 1025px)\" />\n\t<source srcset=\"{{~var.srcLg}}\" media=\"(min-width: 1440px)\" />\n\t<img src=\"/path/to/default.jpg\" alt=\"…\" />\n</picture>\n```\n\nAlready, this feels better. It isn't *actually* better, but I'm headed in the right direction. I still have a lot of repeated code, but at least I can more readily see how I might be able to simplify the multiple sources into a loop over a single source.\n\n## Phase 2\nNow that I've pulled out the `getUrl()` calls into a JS context, I can standardize how I generate the URLs.\n\n```html\n{{~exec(function() {\n\tconst props = {\n\t\t641: { width: 900, height: 300, crop: 'fill', quality: 60 },\n\t\t1025: { width: 1280, height: 500, crop: 'fill', quality: 60 },\n\t\t1440: { width: 1600, height: 700, crop: 'fill', quality: 60 },\n\t};\n\tconst widths = [641, 1025, 1440];\n\thelpers.var.srcs = widths.map(width => ({\n\t\twidth,\n\t\tsrc: data.image.getUrl(props[width]),\n\t}));\n})}}\n<picture>\n\t{{#~var.srcs}}\n\t\t<source srcset=\"{{src}}\" media=\"(min-width: {{width}}px)\" />\n\t{{/}}\n\t<img src=\"/path/to/default.jpg\" alt=\"…\" />\n</picture>\n```\n\nThis is starting to look much better now.\n\nStarting with the HTML, I've condensed the multiple sources into a single, easy-to-read loop. This also means, that if I needed to add a 4th or 5th source, I modify the array.\n\nNext, let's take a look at the JS. I've created an array of viewport widths called `widths`; these widths are also the keys in the `props` object so I can associate a width with a set of arguments for our `getUrl()` call. And lastly, I map over the widgets to create and array of `srcs` which is what drives the generation of source elements in our HTML.\n\n## Phase 3\nAt this point, the HTML is pretty much where I want it. However, there's still room for improvement in the JS; `crop` and `quality` are still shared across all the sets of arguments.\n\nLet's address that.\n\n```html\n{{~exec(function() {\n\tconst sizes = {\n\t\t641: { width: 900, height: 300 },\n\t\t1025: { width: 1280, height: 500 },\n\t\t1440: { width: 1600, height: 700 },\n\t};\n\tconst settings = { crop: 'fill', quality: 60 };\n\tconst widths = [641, 1025, 1440];\n\thelpers.var.srcs = widths.map(width => ({\n\t\twidth,\n\t\tsrc: data.image.getUrl({\n\t\t\t...sizes[width],\n\t\t\t...settings\n\t\t}),\n\t}));\n})}}\n<picture>\n\t{{#~var.srcs}}\n\t\t<source srcset=\"{{src}}\" media=\"(min-width: {{width}}px)\" />\n\t{{/}}\n\t<img src=\"/path/to/default.jpg\" alt=\"…\" />\n</picture>\n```\n\nHere I've pulled out the `crop` and `quality` into their own object called `settings`. I've also renamed `props` to `sizes` which is much more descriptive now since all that object is concerned with are the sizes of the images to render.\n\nNext, in the map, I spread the sizes and settings into an arguments object to be passed to `getUrl()`.\n\n## Phase 4\nThis is looking really slick now, but I'm not a fan of managing the viewport widths both in the `sizes` object and in the `widths` array. I really would like to keep it to a single touch point to reduce my chances to break something.\n\n```html\n{{~exec(function() {\n\tconst sizes = {\n\t\t641: { width: 900, height: 300 },\n\t\t1025: { width: 1280, height: 500 },\n\t\t1440: { width: 1600, height: 700 },\n\t};\n\tconst settings = { crop: 'fill', quality: 60 };\n\thelpers.var.srcs = Object.entries(sizes).map([width, size] => ({\n\t\twidth,\n\t\tsrc: data.image.getUrl({\n\t\t\t...size,\n\t\t\t...settings\n\t\t}),\n\t}));\n})}}\n<picture>\n\t{{#~var.srcs}}\n\t\t<source srcset=\"{{src}}\" media=\"(min-width: {{width}}px)\" />\n\t{{/}}\n\t<img src=\"/path/to/default.jpg\" alt=\"…\" />\n</picture>\n```\n\nTo simplify the handling of widths, I removed the `widths` array altogether and am, instead, mapping over the entries of the `sizes` object and destructuring out the size and the width. This is what I would consider \"clean code\".\n\nFirst off, the HTML is greatly reduced and can support an indefinite number of sources. And there's no ambiguity about what the HTML is doing: it's putting a picture on the page.\n\nSecond, I have a single entry point for getting the actual image URLs that, ideally, I or a future developer supporting this site shouldn't need to touch.\n\nThird, moving out the shared settings like `crop` and `quality` afford me two things:\n\n1. I can easily make a global quality or crop change.\n2. I can ignore them if I don't actually care about what they're set to.\n\nLastly, I am freed up to focus on the part that I most care about: defining sizes of images for different screen sizes.\n\n## Wrap up\nI would and have delivered something like this in production. I find it to be much more readable, maintainable, and extendable compared to any of the previous iterations I ran through in this post.\n\nHow would you approach this? Do you have a better idea? Let me know in the comments below."
    }
  },
  "description": "CSS Frameworks like Bootstrap, Foundation, and Bulma help us describe our HTML in terms of layout structure and components, but I'm not a fan of that approach.",
  "path": "/posts/write-cleaner-code-by-separating-logic-from-templates",
  "publishedAt": "2019-07-24T00:00:00.000Z",
  "site": "at://did:plc:2lm4lab5fhnj6kaazrxopv37/site.standard.publication/self",
  "tags": [
    "clean-code",
    "html",
    "javascript"
  ],
  "title": "Write Cleaner Code by Separating Logic from Templates"
}