<?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: Matt Suhay</title>
    <description>The latest articles on DEV Community by Matt Suhay (@suhay).</description>
    <link>https://dev.to/suhay</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%2F283480%2F7a3086f1-b063-4170-b83f-aa55b0560e55.png</url>
      <title>DEV Community: Matt Suhay</title>
      <link>https://dev.to/suhay</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/suhay"/>
    <language>en</language>
    <item>
      <title>Sandwich Shop: A containerless, serverless experiment</title>
      <dc:creator>Matt Suhay</dc:creator>
      <pubDate>Sun, 21 Nov 2021 22:33:00 +0000</pubDate>
      <link>https://dev.to/suhay/sandwich-shop-a-containerless-serverless-experiment-b2j</link>
      <guid>https://dev.to/suhay/sandwich-shop-a-containerless-serverless-experiment-b2j</guid>
      <description>&lt;p&gt;Some jobs in your career will be pleasant, engaging uses of your waking hours. Challenges are welcome, and the pursuit of bettering yourself ahead of the product is the leading reason you show up every day. However, this was not one of those jobs. Instead, the days felt like they dragged on, with the only way of telling them apart was by weekends, forced birthday celebrations, or the occasional company meeting. The kind of meetings that applause for the senior leadership wasn't only expected but warranted a one-on-one with HR if you didn't provide one. An awkward call to the principal's office where your "company loyalties" were called into question.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;HR person: I know we are entirely dissecting your team, putting you in the overflow building on the other side of the city, changing your fundamental job description, and firing a few people you've grown to rely on to do your job. But why weren't you clapping after we announced the half a million-dollar bonus we're giving the CEO instead of the usual 3% raise we offer our warehouse workers every year?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The day began like the rest—the acrid aroma of too cheap coffee brewed for too long in a forever-neglected Black and Decker was my usual welcome. I spent that morning writing serverless functions for a fledgling e-commerce site, a practice that usually involves explaining to the director that the term "serverless" didn't actually mean the absence of a server. Still, I humored him with the burden of explanation. Once completed and with the pitchy coffee cleansed from my mug and bowels, it was time for a lunchtime pilgrimage to Subway.&lt;/p&gt;

&lt;p&gt;My co-workers had chosen the topic for the meal—a recount of a game they had recently picked up. Not having much to contribute, I sat quietly and unpacked my sandwich. I'm not sure how long I sat there, not saying anything when one of my co-workers asked what was on my mind.&lt;/p&gt;

&lt;p&gt;"Ya know, serverless architecture is a lot like owning a sandwich shop. You put the foundations down, hire the people, stock the kitchen, and put out a menu. Only, with serverless, after the first customer comes in and places an order, we bulldoze the whole thing to the ground and start over when the next customer arrives." I don't believe I have ever seen a table with so many confused faces since my four-year-old nephew tried to tell a joke. At least my nephew got a couple of sympathetic chuckles.&lt;/p&gt;

&lt;p&gt;But why do we do it that way? Why do we put our functions inside wrappers or only use specific languages? I want to put my code up somewhere and just use it as-is instead of the extra bits that go with it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I didn't stay much longer with that company and was soon on my way to the next set of forced birthday celebrations.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/suhay" rel="noopener noreferrer"&gt;
        suhay
      &lt;/a&gt; / &lt;a href="https://github.com/suhay/sandwich-shop" rel="noopener noreferrer"&gt;
        sandwich-shop
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Containerless, Serverless experiment using Go and GraphQL
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Platform agnostic and Sandwiches (PaaS)
&lt;/h2&gt;

&lt;p&gt;One of the more complex parts of having an idea is finding a way to use it. Logistics, good intentions, and planning aside, solving a problem for someone separates a good idea from a great one. Like the inventors of the cell phone when just starting off, "Who would use something like that?"&lt;/p&gt;

&lt;p&gt;In a previous experiment, The Exothermic Project, we discussed what a platform would look like without a front or backend. This pet rock-like creature that neither eats nor poops would solve many problems for would-be pet owners, but it isn't exciting. And let's face it: there are web problems that can't be solved without a backend. I wanted to address this issue by providing a friend our pet rock could talk to. Stack agnostic website, meet the code agnostic platform. Now we had a place where we could write APIs against a database without exposing our passwords or integrating with 3rd parties without distributing our keys. Sandwich Shop will be the gateway, but having it just do one application's heavy lifting seemed like a waste.&lt;/p&gt;

&lt;p&gt;With that in mind, we came up with a tenant architecture. By coming up with, of course, I mean we stole the tenant architecture idea from all the other PaaS (Platform as a Service) providers. The idea was to separate our applications by the tenant name. If a site wants to pull something from a database, it would just call &lt;code&gt;https://example.com/shops/theSite/getPage&lt;/code&gt;. The webserver would proxy any call for &lt;code&gt;/shops&lt;/code&gt; to Sandwich Shop, with the next part of the path being the tenant, and the last part being the function to run (or the Order to place).&lt;/p&gt;

&lt;p&gt;Each tenant would have its own workspace. It would define an &lt;code&gt;orders.yml&lt;/code&gt; file containing all the essential parts of placing an Order. It'll provide a path to the script, pick the runtime required to run it, set any custom authentication steps it needs to take and add any environment variables.&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;getPage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# order name&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node14&lt;/span&gt; &lt;span class="c1"&gt;# shop to run in&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;getPage.js&lt;/span&gt; &lt;span class="c1"&gt;# path where function lives&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# any variables to include&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NODE_ENV=dev&lt;/span&gt;
&lt;span class="na"&gt;getNews&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# order name&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;go1_17&lt;/span&gt; &lt;span class="c1"&gt;# shop to run in&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;news_sync.go&lt;/span&gt; &lt;span class="c1"&gt;# path where function lives&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt; &lt;span class="c1"&gt;# any variables to include&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tenants are also able to determine their own access authorization. By default, a tenant can provide a &lt;code&gt;.key&lt;/code&gt; file within its workspace. An authorization will be provided to requests that have an &lt;code&gt;Authorization: Bearer whatever-is-in-the-key-file&lt;/code&gt; header. Pretty basic, but it's at least something. Orders can also provide their own header definition, just in case &lt;code&gt;Authorization&lt;/code&gt; is not used, and a custom &lt;code&gt;auth&lt;/code&gt; function. These functions will be run just before the Order to check if the request is authorized. For example, something that comes from GitHub webhooks:&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="c1"&gt;# orders.yml&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;suhay.dev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;parse.py&lt;/span&gt;
  &lt;span class="na"&gt;auth_header&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;X-Hub-Signature-256&lt;/span&gt;
  &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;auth.py&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# auth.py
&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;tokenb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sha256=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compare_digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we defined a custom &lt;code&gt;auth_header&lt;/code&gt; and &lt;code&gt;auth&lt;/code&gt;, we will skip the default authorization step and immediately send the request to an available Shop. The Shop will then execute the script specified in &lt;code&gt;auth&lt;/code&gt;, passing in the &lt;code&gt;auth_header&lt;/code&gt; to be checked. The rest of the execution then waits on whether or not we return true or false from &lt;code&gt;auth.py&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Franchising
&lt;/h2&gt;

&lt;p&gt;Sandwich Shop will define a set of Shops used to broker an Order based upon the Shop's runtimes. A Shop is what actually runs the code associated with the Order and can live anywhere. For this example, we have one defined on localhost and port 4007.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ciabatta"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ciabatta"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"host"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4007&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"runtimes"&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="s2"&gt;"go1_17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"node14"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"node16"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"python3"&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="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We wanted to keep Sandwich Shop and the Shops as separate processes for scaling purposes. You also might want to specialize your Shops to run certain kinds of code. For instance, you can have one Shop that only does Node.js and lives in one place while another handles Python found in another.&lt;/p&gt;

&lt;h2&gt;
  
  
  If this, then paywall
&lt;/h2&gt;

&lt;p&gt;I've always loved the idea of connecting my different apps and services together. When I'm researching something or writing an article, grabbing images or stories and sending them to my notes is simply incredible. However, they can be limited without a subscription, and I don't feel I use it enough to justify paying for one.&lt;/p&gt;

&lt;p&gt;One of the first things I used Sandwich Shop for was to listen for GitHub webhooks. I can then use a development server to run any build steps and move the readied files to their respective webroots. By eliminating the need to SSH into multiple servers to deploy a change by hand has been lovely.&lt;/p&gt;

&lt;p&gt;I also just started opening a few Shops that handle home automation. We can then set up a few Alexa skills and other triggers that you would see in IFTTT or Zapier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Containing the excitement
&lt;/h2&gt;

&lt;p&gt;One thought was to wrap the Shops in Docker containers. I decided this would be against the idea of being containerless. We should instead deploy them on different ports and across other machines if we need to scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;Something the current version of Sandwich Shop is missing is the ability to check on long-running processes. Right now there is really no way to see if there is an error, or even if it's stuck. You place the Order and then just hope you get what you want. &lt;/p&gt;

&lt;p&gt;Standing up another Shop or tenant is something you have to do yourself, today. That's not the best, so allowing an easier way to add either from the command line or even from a web interface would make it a lot easier to scale and add additional projects to the flow.&lt;/p&gt;

&lt;p&gt;Although we have added a layer of security to the requests themselves, we need to prevent malicious code from running in a Shop. If this experiment were to move forward to being a PaaS offering, we would want to make sure the code is executed within a &lt;code&gt;rbash&lt;/code&gt; or even use something like jailing to prevent code from leaking into another tenant's workspace.&lt;/p&gt;

&lt;p&gt;Lastly, comparing Sandwich Shop up against other solutions such as AWS would be interesting to see if we got anywhere close to solving a problem or just something fun to play around with.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Exothermic Project: Poor design decisions for a new age</title>
      <dc:creator>Matt Suhay</dc:creator>
      <pubDate>Mon, 20 Sep 2021 00:07:34 +0000</pubDate>
      <link>https://dev.to/suhay/the-exothermic-project-part-2-poor-design-decisions-for-a-new-age-1a28</link>
      <guid>https://dev.to/suhay/the-exothermic-project-part-2-poor-design-decisions-for-a-new-age-1a28</guid>
      <description>&lt;p&gt;Since learning React, I've willingly thrown myself into the embrace of starry-eyed fandom. Not quite to the level of getting a tattoo of my obsession, but more than willing to show pictures of my work as if they were photos of my children to strangers. Like a proud parent watching their little ones pick up a Fisher Price hammer for the first time, I encourage my React-lings to treat every web problem as a nail and beam while they smash it into working order. I never once ask if React is the correct answer or even the easiest, so, naturally, when a CMS-shaped nail appeared, we got to work.&lt;/p&gt;

&lt;p&gt;We looked at the different aspects that cause a content management system to become bloated in part one. In part two, we will dive into the murky waters of excessive features. We will do a little more experimenting and a lot more thinking—maybe even taking a few pictures of our React-lings along the way to be shared or included in this year's Christmas card.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An idea for a future post: AI Christmas card generator??&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i3JOwpme--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/suhay"&gt;
        suhay
      &lt;/a&gt; / &lt;a href="https://github.com/suhay/exothermicjs"&gt;
        exothermicjs
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      YAML-based template engine for React
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Maestro of many
&lt;/h2&gt;

&lt;p&gt;The learning curve that accompanies React can be a non-starter for some. If you are unfamiliar with the framework, a developer may return to something more comfortable to achieve complicated requirements. Especially when doing client work, we are rarely afforded the time needed to learn something new, and this is precisely when a project can fall into the trap of "Master of None" from part one. When returning to our comfort zone, we start rearranging and renovating what we have into what we want—usually without checking if what we wish will even fit into the space. But, like moving a too-big couch up a too-small staircase, we still attempt to make it work by gouging, scraping, pivoting, and partially disassembling it on the way.&lt;/p&gt;

&lt;p&gt;This is called "feature bloat." We fill our programs with more feature furniture than butts to sit on them, and this is a problem and a symptom of an inside-out design pattern. The application assumes that the page it's rendering needs everything until it's told differently. An example of the inside-out approach in WordPress is with their filters and hooks—how it handles injecting work into the render loop. There are over 400 default hooks and filters that do more work than we need for most pages. Even just checking if there is work to be done can waste time and resources.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I worked on a project that had over 100 feature flag checks. It was impossible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, we started experimenting with the idea of "feature delegation" instead of bloat. We wanted to take a more outside-in design approach allowing the core to conduct the application while the page dictates what it needs. Our core is mainly a YAML interpreter that stands at about 330kb, and it will stay there regardless of how long the page is or how many different pieces are needed. We made the render loop more efficient by completely eliminating it.&lt;/p&gt;

&lt;p&gt;We took a simplified run of WordPress' render loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Request -&amp;gt; index.php -&amp;gt; query_posts&lt;span class="o"&gt;()&lt;/span&gt; -&amp;gt; new WP_Query&lt;span class="o"&gt;()&lt;/span&gt; -&amp;gt; query&lt;span class="o"&gt;()&lt;/span&gt; -&amp;gt; get_posts&lt;span class="o"&gt;()&lt;/span&gt; 
  -&amp;gt; the_post&lt;span class="o"&gt;()&lt;/span&gt; -&amp;gt; setup_postdata&lt;span class="o"&gt;()&lt;/span&gt; -&amp;gt; apply_filters&lt;span class="o"&gt;()&lt;/span&gt; -&amp;gt; wp_reset_query&lt;span class="o"&gt;()&lt;/span&gt; 
  -&amp;gt; wp_reset_postdata&lt;span class="o"&gt;()&lt;/span&gt; -&amp;gt; HTML -&amp;gt; Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and made it into this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Request -&amp;gt; &lt;span class="o"&gt;[&lt;/span&gt;url].exo -&amp;gt; useExothermic&lt;span class="o"&gt;()&lt;/span&gt; -&amp;gt; buildTemplate&lt;span class="o"&gt;()&lt;/span&gt; -&amp;gt; HTML
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Intended side-effects
&lt;/h2&gt;

&lt;p&gt;With our outside-in experiment, one question came up frequently:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"How do we create a dynamic app if the core will never change?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We needed an abstraction layer that kept track of where our components were. We decided to use YAML and define our components as &lt;code&gt;!custom&lt;/code&gt; tags. And since YAML is just a text file, we had the side-effect of manipulating our structure whenever we wanted to without needing to recompile the bundles.&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="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!section&lt;/span&gt;
  &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;row w-100&lt;/span&gt;
  &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!col&lt;/span&gt;
      &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;col col-6 align-items-center&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;Coder&amp;lt;span&amp;gt;&amp;amp;#8226;&amp;lt;/span&amp;gt;  &lt;/span&gt;
        &lt;span class="s"&gt;Wheelman&amp;lt;span&amp;gt;&amp;amp;#8226;&amp;lt;/span&amp;gt;  &lt;/span&gt;
        &lt;span class="s"&gt;Dragon slayer&amp;lt;span&amp;gt;&amp;amp;#8226;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!col&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;me&lt;/span&gt;
      &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;col col-6 d-flex align-items-end&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;![](/images/pxArt.png)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="o"&gt;-------&lt;/span&gt; &lt;span class="nx"&gt;Rendered&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;-------&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Section&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"row w-100"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Col&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"col col-6 align-items-center"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    Coder&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;#8226;&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;be&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    Wheelman&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;#8226;&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;be&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    Dragon slayer&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;#8226;&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Col&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Col&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"me"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"col col-6 d-flex align-items-end"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/images/pxArt.png"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Col&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Can be turned into:&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="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!section&lt;/span&gt;
  &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;row w-100&lt;/span&gt;
  &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!col&lt;/span&gt;
      &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;col align-items-center&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;Coder&amp;lt;span&amp;gt;&amp;amp;#8226;&amp;lt;/span&amp;gt;  &lt;/span&gt;
        &lt;span class="s"&gt;Wheelman&amp;lt;span&amp;gt;&amp;amp;#8226;&amp;lt;/span&amp;gt;  &lt;/span&gt;
        &lt;span class="s"&gt;Dragon slayer&amp;lt;span&amp;gt;&amp;amp;#8226;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!section&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;me&lt;/span&gt;
  &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;row w-100&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;![](/images/pxArt.png)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="o"&gt;-------&lt;/span&gt; &lt;span class="nx"&gt;Rendered&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;-------&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Section&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"row w-100"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Col&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"col col-12 align-items-center"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      Coder&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;#8226;&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;be&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      Wheelman&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;#8226;&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;be&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      Dragon slayer&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;#8226;&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Col&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Section&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"me"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"row w-100"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/images/pxArt.png"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Section&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Effectively re-arranging components with a simple text editor, no Webpack or Babel, and all at runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  0 to live
&lt;/h2&gt;

&lt;p&gt;There is always a ramp-up period when starting something fresh. You have to hook up the routes, judge which state management to use, wait for packages to load, and so on. We wanted to focus on getting pages up with as little bootstrapping as possible. The building blocks come predefined yet generic, the routes are handled by the &lt;code&gt;.exo&lt;/code&gt; files, and the states are managed for you. Add the core library to a page, define a few blocks in the &lt;code&gt;index.exo&lt;/code&gt; file and you're done. You can structure your landing page and subsequent pages with only these parts and without running &lt;code&gt;npm&lt;/code&gt;, &lt;code&gt;yarn&lt;/code&gt;, &lt;code&gt;webpack&lt;/code&gt;, or &lt;code&gt;make&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The great decoupling
&lt;/h2&gt;

&lt;p&gt;Something that always amazes me is how many different flavors a tech stack can come in. Some will say theirs is better than another for reasons, but they all do just about the same thing, although in just about every configuration you can imagine. We wanted to be as agnostic as possible from the schema to the server, backend, microservices, containers, databases—everything. YAML and Markdown will get you started, but if you want to keep your blog authors in WordPress, then keep them in WordPress. Build out a plugin to handle the back and forth, and it's yours. It doesn't make sense to force a workflow change if you don't need to. The rivalries and infighting that result from preferring one thing over another don't make sense in the end when it's all just text on a screen.&lt;/p&gt;

&lt;p&gt;By separating the different facets of the application from each other and from the core library, security patches can happen when they need to. Authorization and authentication can be anything you want or nothing at all. Hugely complicated roles and memberships should never have existed in the first place. When content and page layouts become separated, and when Exothermic eventually goes the way of the TRS-80 computer, you can bring your pages to wherever the hell the future has in store next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making it more better-er
&lt;/h2&gt;

&lt;p&gt;Plugins will take center stage now that the lights are set and the cast has been—cast. Exothermic is meant to be a launching point, a substrate, for attaching whatever else you want it to do and plugins are how you'll make it happen. There is currently an example of a plugin that handles &lt;a href="https://github.com/suhay/exothermicjs/tree/main/packages/plugin-blog"&gt;blog posts&lt;/a&gt; that you can reference.&lt;/p&gt;

&lt;p&gt;On the roadmap, we've also started putting together what we're calling the Layer Engine, which allows you to create more reusable components across multiple pages. Hopefully reducing any extra copy-paste. This is specifically targeted at how content management systems currently treat templates. The templates enforce the reusable parts of a site by punching holes into what can be changed by the developer. They are restrictive by design and cause significant collections of one-offs to get around their limitations. With the Layer Engine, we want to relook at this and make it better.&lt;/p&gt;

&lt;p&gt;I'd also like to see some kind of GUI to manipulate the &lt;code&gt;.exo&lt;/code&gt; files, but we'll see what happens there.&lt;/p&gt;

&lt;p&gt;Lastly, we want to go further with making everything as agnostic as possible. This started another experiment we're calling &lt;a href="https://suhay.dev/sandwich-shop/"&gt;Sandwich Shop&lt;/a&gt;, where you can turn any piece of code into a microservice—with your choice of cheese, and served hot or cold.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Exothermic Project: What I learned from 15 years of Content Management Systems</title>
      <dc:creator>Matt Suhay</dc:creator>
      <pubDate>Sun, 11 Jul 2021 19:42:39 +0000</pubDate>
      <link>https://dev.to/suhay/the-exothermic-project-what-i-learned-from-15-years-of-content-management-systems-part-1-2h56</link>
      <guid>https://dev.to/suhay/the-exothermic-project-what-i-learned-from-15-years-of-content-management-systems-part-1-2h56</guid>
      <description>&lt;p&gt;Many years ago, a great happening occurred that forever changed my low-stress development job. My day-to-day activities were typically filled with acts of building mundane addons that would live out their short, six-month lives as part of low-traffic ad campaigns. That was all replaced by a massive and excruciating task of moving an entire higher education institution's content management system to a new home. I will take some of the blame. The application we were using showed its age, and I was personally eager for career advancement by working with the newest, shiny thing. So, like any good, and very bored programmer, I began researching how to make our jobs more enjoyable by completely changing everything about them. If there was anything that I learned from all the time we spent moving stacks of content, revamping countless designs, or applying the latest buzzword in any number of three-letter acronyms—every single content management system was the same.&lt;/p&gt;

&lt;p&gt;All of them.&lt;/p&gt;

&lt;p&gt;I will concede that there is a use case for everything. I’m not here today to throw shade at the idea of a CMS. Instead, I’m hoping to open up the conversation and shed some light on the parts that might be overlooked. Look for any missing pieces that may drive any seasoned developer into a dark room at the end of days spent working with them. To push out the "That's just how it is" culture and replace it with a more welcoming one.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i3JOwpme--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/suhay"&gt;
        suhay
      &lt;/a&gt; / &lt;a href="https://github.com/suhay/exothermicjs"&gt;
        exothermicjs
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      YAML-based template engine for React
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  A master of none
&lt;/h2&gt;

&lt;p&gt;At some point during a CMS's lifetime of feature additions and bug fixes, the core diverged to try and become a one-stop shop for everything, everyone, everywhere, every time, and ever after. Maybe it was to increase the demographic that would want to use the application, or perhaps it was because a client was putting on some added pressure. Whatever it was, at that point, the application should have split instead of continuing down a single-lane road towards a maintenance nightmare.&lt;/p&gt;

&lt;p&gt;When the fundamental requirements changed, it should have been embraced and allowed for the two ideas to go off separately. Instead, the project will absorb these additions and mark them as breaking changes. You don’t realize that some of these new features had to be bolted on either by abstracting an already established data contract or by altering underlying core functionality. In most cases, the backend is sporting some kind of hack living freely in production code made to make something like this work. Don't try and deny it—you probably could list off several right now if you were asked to. They are found while stumbling around fixing something else and are surrounded by a big &lt;code&gt;TODO&lt;/code&gt; with good intentions of being refactored. Comments that were added several years ago and haven't been touched since.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;// TODO: this seems inefficient, will rework in next sprint ---&amp;gt; some_person, 2 years ago via PR #35 • final, final bug fix, for serious this time.&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So why is this the rule instead of the exception? What if we removed this burden of effort by introducing a more modular architecture for our features? If you just want a blog, then you should only need to install the blog. There is no need to have the portfolio or e-commerce stuff in the mix when you're only trying to draw buzz for your client's opening day. And, trust me, we've all worked with those people that want everything in one place. It was probably one of them that started the initial fracture in the code.&lt;/p&gt;

&lt;p&gt;By keeping things separate, we nurture these very different parts to be developed in parallel and by the people who want to do it. This internal API will talk to the core, should never change, and be nonrestrictive and nondestructive. Free your developers instead of handing them a 200-page document listing all the things you can and cannot do.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I got an integration manual from a fortune 500 company where all the coding examples were written in Silverlight and typed up in purple Comic Sans.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Content, aka the TL;DR
&lt;/h2&gt;

&lt;p&gt;Most mainstream content management systems love shoving all of your content into a database, keeping everything centralized. However, these large &lt;code&gt;TEXT&lt;/code&gt; or &lt;code&gt;BLOB&lt;/code&gt; types can cause performance hits, especially if you run a search. There are ways you can get around these bottlenecks by using caching, but then you have to start worrying about when you should and shouldn't drop that cache. And then, by doing so, letting everyone know that the cache isn't there anymore so that they stop calling you on the phone about how it looks, "[...] correct in fox-fire, but not in the blue E one."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I should have asked them to check Netscape, just to make sure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Up to this point in the article, I have written roughly 4500 characters. We are pushing about 7000 symbols into the database with markup and class names, meaning 33% of our storage is being used on—well—nothing. At least nothing a reader is going to see. All this extra data is taking up unnecessary space and locking large institutions into remaining with aging software because of how stuck their content is inside of these things. They have massive archives going back years and years through multiple upgrades and requiring many people to keep everything backward compatible. What if SQL or NoSQL disappears tomorrow? What if a major version release removes something that your architecture needs? At that point, do you just tell your users you can't upgrade even though there's a security issue?&lt;/p&gt;

&lt;p&gt;Content should be stored in non-periphery forms, should only be the content that the user wants to see, and should be kept wherever the hell you want it to be. If a content solution has to retain customers through a hostage situation with your data, they probably need to change their business model. And the content that is coming into the core should be just that—content. If it's stored in flat files or cloud drives, it shouldn't matter. The core asks for page 5's content, so the only thing it should be expecting is page 5's content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trust your contributors. No, really
&lt;/h2&gt;

&lt;p&gt;One of the site owners I was working with was planning on getting some temporary help to speed up their site move. I said, "Sure, we can get them all set up with accounts. Just let us know their email addresses." But that was when it was made clear that the site owner wanted this temporary help but didn't want them to publish content without it going past their eyes first. And they also shouldn't be allowed to upload new images. Or link to anything just in case the links went somewhere inappropriate. And everything should be time stamped to make sure the helpers are doing their job.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This was a genuine request.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Why would you hire someone to work on your site that you couldn't trust enough to publish a simple page? Or even let you know that a draft is ready to be viewed before going live? Adding granularity to security will reward you with a beach covered in sand. Making a change in the sand will only fill your shoes with it. Set your contributors up for success and show them the tools they will use the most, but not block their ability to do anything requiring more people to be involved. By saving time with temporary hires, you lose it all if they're still waiting on you for approval.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I worked in a system where the roles were: reviewer, author, author2, contrib, contrib2, contrib3, admin, admin2, and superAdmin&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Plugin frameworks: wat?
&lt;/h2&gt;

&lt;p&gt;So often developers are expected to learn a new framework. If it's changing jobs or starting a new side gig, there will always be a new way they have to learn to do something they've been doing for years. I can't even begin to count how many plugin frameworks I know, filed away in my mind, next to childhood addresses and that mental list of purchases I wanted to make at the next Scholastic Book Fair from the 3rd grade. A developer has to ingest unnecessarily complex function loops, hook names, and file structures to introduce one thing into one place used only one time and then never spoken about again. We attempt to qualify this effort by making the plugin open source, but who else needs this niche, one-off solution?&lt;/p&gt;

&lt;p&gt;A plugin should have a single entry point and be defined through simple metadata. A plugin should be what its name suggests, plug and play, and not just for the consumer. The core only needs to get data into and then out of it, opening up avenues for upgrades and security patching by preventing instances where the plugin is so deeply integrated that it becomes two versions behind the current release.&lt;/p&gt;

&lt;h2&gt;
  
  
  A templated, template system of templated templates
&lt;/h2&gt;

&lt;p&gt;This is where the developer's true creativity can shine. Building the perfect template requires adding layers upon layers, hooking up dynamic call-outs to bring in generated lists, and fleshing out semantic markup that would make any markup validator proud. But that's not the real world. Content is messy. Authors are fickle and quickly grow bored of the cookie-cutter-shaped baked goods that your masterfully nested templates stamp out.&lt;/p&gt;

&lt;p&gt;"But can we put the images on the left?" suddenly, you are using template names like &lt;code&gt;content-main-with-left-image&lt;/code&gt;. Bugs begin to appear in odd places, and tracking them down becomes a nightmare as you wind through the patchwork of conditional branches that add hero images on some pages, but not others, and only if they are tagged by &lt;code&gt;informational&lt;/code&gt; or &lt;code&gt;temp-tag-4&lt;/code&gt;. Your once beautiful markup is now marred by class names that extend further than the content.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I think &lt;code&gt;temp-tag-4&lt;/code&gt; may still be in use today since I introduced it for testing something in 2010.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Templates should be organic and not set in stone. If you have to make a one-off template for more pages than that use the base template, then they aren't one-offs anymore. Content artifacts should work regardless of how their page is structured, and a template should aid in the efficiency of publishing content while staying out of the way.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;.page .main-content .content .content-w-tabs .image-con .image-noFloat .image-noFloat_5 .float-left&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  EOF
&lt;/h2&gt;

&lt;p&gt;These are the main points I plan on focusing on while I revisit the ExothermicJS project in part 2. I like to think of these bullets as ideas to keep in mind while working on the next big thing. Thoughts that will hopefully end your next marketing pitch with applause, instead of an awkward silence followed by the question, "So what did you think?"&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is really how one of our demo calls ended with a potential vendor. I think there was dead air for a good 15 seconds after the sales person was finished before someone from my team forced out, "Seems—neat?"&lt;/p&gt;
&lt;/blockquote&gt;

</description>
    </item>
  </channel>
</rss>
