Sam Bosell
Ambient Data

Ambient Data

Weekly Notes 2021-W10

Weekly Notes 2021-W10

Sam Bosell's photo
Sam Bosell
·Mar 16, 2021·

5 min read

These logs are my work logs (anonymized) mixed in with a few thoughts and maybe some personal anecdotes. Just to keep my mind focused and to allow some expression of what is going on during the week because sometimes it feels unproductive when it is all but.

Having had many developers work with me over the years many have asked what is the difference between a senior v regular developer, usually because they want a raise but it is a fair question. Yesterday I reviewed some code due to a client reported issue and noticed that the developer probably understood that when importing a typescript (ts) module the import is basically a singleton and leveraged that fact to make the code work with regards to the documented and obvious requirement. A dev and senior dev will get the job done in the time allotted.

What the developer failed to realize is that the architecture they built should never have relied on a singleton for data in the first place because it doesn't allow his dependent class to be independently instantiated more than once. With ts/js module imports this is very easy to overlook. I am not a fan of edge cases to make points because those are almost always a time suck, this is a common enough case that a senior dev would have accounted for in the basic architecture. I removed the singleton data (array) and placed it inside the class where it belongs and refactored the methods outside that were "integrated" with it. The end result was a reduction of a few lines and a much cleaner interface.

Once you get to be a senior it isn't about years of seniority but leveraging your knowledge, recognizing and accounting for requirements, architecture and scenarios that may not be obvious or even documented but are important. With the particular case I outlined above, the in-your-face-job got done but not as well as it should have with the difference being some pretty minor code updates. I may use his code as an example the next time I interview someone who claims they are an expert in javascript/typescript. For the record I don't claim to be an expert just knowledable.

Work Logs

Some general maintenance requests like updates to some client site signup widgets for an email marketing program that were failing. We often run into the battle of fixing something quickly vs fixing it robustly. I chose the former route this time only because I know there is little value in investing time in a robust solution that may require 4 times more effort which would be easier to maintain but the maintenance may never exceed those costs.

SSL Cert updates. Does everyone hate SSL certifications as much as I do? At least Azure makes it nice to save them in the vault and easily apply them to different resources.

Planning for how to handle professional services for certain client markets.

Started on new mobile app project update. Boils down to a pdf generator for a large form that is filled out for a pharmaceutical company. The original implementation was fun and perhaps warrants a blog post on how to easily generate a pdf form from some json data.

eGift card project work to integrate into a Square Space eCommerce site. The fun part is the integration, Square Space is just an API to me.

Personal and Coding

Last week we worked through how Service Stack does server side validations and this week we will tie it all together. Here is a simple form with a few required validations and a recaptcha (not shown).

Weekly Notes 2021-W10

To keep this simple this is a part of a template in a vue component for the screenshot above. A label, input and error message for an email field. Notice we apply the error class from inputError and the field name along with getInputError to get the error message.

            <div>
              <label
                for="email"
                class="sr-only"
              >Email *</label>
              <input
                id="email"
                :class='inputError("email")'
                name="email"
                v-model='request.email'
                type="email"
                autocomplete="email"
                class="block w-full shadow-sm py-3 px-4 placeholder-gray-500 focus:ring-indigo-500 focus:border-indigo-500 border-gray-300 rounded-md"
                placeholder="Email"
              >
              <div class='text-red-500'>
                {{getInputError('email')}}
              </div>
            </div>

The code is relatively simple (shown below) when the server returns the error messaging in the ResponseStatus, the vue component has some methods inputError and getInputError which are just wrappers for the Service Stack response parser, errorResponse to get the error messaging out of the client's response if it doesn't validate. In one case it returns a list of classes to show the red UX highlights and the other the error messaging shown below the field. There is also an errorResponseExcept which can be used to build a summary list as well. Also, Service Stack generates the entire api surface in Typescript (and other languages) so you can see how nice it is to call something like client.post(new Contact()) where Contact is a dto class. This removes the need to build and maintain routes as it is all taken care of. Pretty nice having it all integrated with the validation. The full contact code is below and will guide you on how a Typescript front end benefits from the Service Stack provided utilities.

import { defineComponent, ref } from "vue";
import {
  JsonServiceClient,
  errorResponse,
  errorResponseExcept
} from "@servicestack/client";

import { Contact } from "../dtos";
const client = new JsonServiceClient("/");
declare let grecaptcha: any;  

export default defineComponent({
  name: "ContactForm",
  setup() {
    const request = ref(new Contact());

    return { request };
  },
  data() {
    return {
      response: null as undefined | null | any,
      success: false,
      loading: false
    };
  },
  computed: {
    errorClasses(): object {
      return {
        "border-dashed": this.errorSummary,
        "border-red-500": this.errorSummary,
        "border-4": this.errorSummary
      };
    },
    hasError(): boolean {
      return this.errorSummary;
    },
    errorSummary(): any {
      if (this.response) return errorResponseExcept.call(this.response, "");

      return null;
    }
  },
  methods: {
    inputError(name: string): object {
      return this.response && errorResponse.call(this.response, name)
        ? this.errorClasses
        : {};
    },
    getInputError(name: string): any {
      return this.response ? errorResponse.call(this.response, name) : null;
    },
    async send() {

      if (this.loading) return;
      this.loading = true;
      grecaptcha.ready(async () => {
        this.request.recapchaResponse = await grecaptcha.execute("",
          {
            action: "submit"
          }
        );

        try {
          this.response = await client.post(this.request);
          this.success = true;
        } catch (e) {
          this.response = e;
        } finally {
          this.loading = false;
        }
      });
    }
  }
});

As an aside some of the methods above are extracted out and shared, however I moved them into the component to demonstrate it all together. As an example the computed errorClasses and methods inputError and getInputError are the same in all the form components to ensure consistency in the UX.

 
Share this