Don’t use internal tooling, contribute to your tools.

There is a dichotomy in software engineering organizations, some only use public tooling, entirely avoiding building their owns tools. Other companies  follow the ‘Not invented here’ principle and try to only use software developed internally. 

There are two forces driving this split, first building software tooling is expensive, small companies often cannot afford to build and support internal tools. It is an expensive recurring cost that can easily get out of hand. Building 2 internal tools a year will set you on a path to supporting 20 tools 10 years from now eating huge chunks of your operations budget. 

The other force in play is that if you use public or off the shelf tooling you will encounter workflow discontinuities that are difficult to fix. Using off-the-shelf tool A with tool B might require an entire employee to bridge the gaps manually, while still be a pain for everyone involved. Decision makers at some companies think to themselves, “We can just build a tool B that works perfectly with our use case.” And that works great when you have one tool, but then when need C comes along your team  makes the same case again, “We already invested in custom tool B we can’t throw away that work, we need a new custom tool for need C”. And now your company is on the path towards building an alphabet’s worth of internal tools that aren’t useful outside of your business.

Luckily, there is a solution to this. Use Open Source tooling and when you run into a workflow problem, work with the maintainers to contribute a fix. Even in poorly managed projects extending the code to support your use case will be less costly than building an entirely new internal tool to solve the same problem. 

Previewing image uploads with stimulus.js

I’ve been working on a website with file uploads lately and after a bunch of googling put together a solution using stimulus.js instead of jQuery as not using jQuery is the thing now.

The website I’m working on allows people to upload images and then to tag them before sharing and I thought it was a bit sub-optimal to ask people to tag their images without being able to see them. 

I’m using rails so this component has two parts the javascript file and my html template file. In the html template file I have a html form created via the rails form_with helper. 

<%= form_with scope: :look, url: looks_path, local: true do |form| %>

  <div>
    <%= form.label :title %><br>
    <%= form.text_field :title %>
  </div>

  <div>
    <%= form.text_field :tag_list, multiple:true %>
  </div>

  <div data-controller="image-preview">
    <%= image_tag("preview.png",  :width => "100px", :hight => "100px", 
    data: { target: "image-preview.output" }) %>
  
    <div class="my-2">
      <%= form.label "Look Image" %><br>
      <%= form.file_field :image, :class => "form-control-file photo_upload", 
      data: {target: "image-preview.input", action: "image-preview#readURL" } %>
    </div>    
  </div>

  <div>
    <%= form.submit %>
  </div>
  <% end %>

You can see there that my stimulus data-controller encapsulates the form file_input and an image tag. The image tag loads a “preview.png” on page load and then replaces that white square when the user uploads an image. Ideally, you may want to play with the visibility attribute instead of using a blank square. 

// Visit The Stimulus Handbook for more details 
// https://stimulusjs.org/handbook/introduction

import { Controller } from "stimulus"

export default class extends Controller {
  static targets = [ "output", "input" ]

  readURL() {
    var input = this.inputTarget
    var output = this.outputTarget

    if (input.files && input.files[0]) {
      var reader = new FileReader();

      reader.onload = function () {
       output.src = reader.result
     }

     reader.readAsDataURL(input.files[0]);
   }
 }

}

The stimulus.js controller is here. It uses two targets the “input” which is the form file field and the “output” which is the image tag we are updating with the new image. This javascript uses the FileReader (https://developer.mozilla.org/en-US/docs/Web/API/FileReader) API to read the image off of the user’s computer and display it without needing to move the image across the network. 

This ended up being pretty simple to do in stimulus.js. I like that we don’t need QuerySelectors or anything non-deterministic like that and can just reference our targets directly. I haven’t included the webpack and rails integration code, it was a little tricky, and is a topic for another blog post.