Paddock Tech Progress — May 2019

9 mins
May 01, 2019

Accomplishments

GraphQL

I now have a GraphQL API server that I’ve used to convert the web app over to dynamically fetched content! Here is a snippet of what this looks like when you query it

A core focus of the design is pagination, i.e. requesting a small set of data up front and loading the next set when requested. This will keep data usage low as it only downloads the data it needs to render the UI as soon and as fast as possible. Any additional data will only be retrieved when the user needs it. For example, pages that infinitely scroll or buttons that Load More when clicked.

All data will be cached in the web app so if the page is revisited or refreshed it should load data from the cache and avoid unnecessary network connections to the server. Data being downloaded will be automatically compressed with GZip. When I ran a query for of the data the server had the size was ~14KB and when compressed it was ~2.3KB. I do care about cell phone data plans, y’all.

The server is implemented with TypeGraphQL. Here is the entire implementation of the events object returned in the query from the picture above

@ObjectType({ description: 'A motorsports event' })
export class EVENTS_Event extends Node {
    public data: IEventData;

    constructor(data: IEventData) {
        super(data);
        this.data = data;
        this.name = data.name;
        this.slug = data.slug;
    }

    @Field({ nullable: true, description: 'The human-readable name' })
    name?: string;

    @Field(
        returns => ORGANIZATIONS_OrganizationConnection,
        { description: 'The organization hosting the event' }
    )
    organizers!: ORGANIZATIONS_OrganizationConnection;

    @Field({ nullable: true, description: 'A unique identifier to be used within URIs' })
    slug?: string;

    @Field(
        returns => EVENTS_EventStageConnection,
        { description: 'Each "day" or stage of the event.' }
    )
    stages!: EVENTS_EventStageConnection;
}

As a bonus, GraphQL supports subscriptions which means that adding notifications and propagating event schedule changes to event participants as they happen will be relatively straight forward and simple 😍

Graphics

I’ve known I’d need something to help me draw track maps since I started mocking up the web app concept in Sketch. I originally created the rough versions of a fair amount of track maps using Affinity Designer on my computer using a mouse. It was extremely difficult and time consuming due to the lack of precision and finesse needed to draw accurate versions of each map subdivided into turns, straights, pit in/out, etc.

After I bought a new iPad Pro I’ve been able to draw the tracks with incredible precision in a fraction of the time. This should help reduce the amount of work I have to do when I start loading real events into the system in the coming months. My iPad will also be a great device to use for demos to users and potential customers, to test how the web app looks and behaves on a tablet, and as a general travel device.

I now have pixel perfect SVG graphics for:

On the docket:

Product Awareness

I’ve been thinking about marketing and raising awareness of my efforts in the broader public since the beginning, but I have been having the desire to keep it secret until beta/launch at the same time. This has kept me from putting the product and myself out there until I have something tangible that people can play with which isn’t exactly a great idea.

Despite inhaling all types of advice and lessons from founders, entrepreneurs, and other professionals for the past 2-3 years, I think it has taken me until now, being in the thick of it, to fully understand and appreciate the notion that ideas are cheap and easy — it’s the execution that really matters.

To this end I want to start building a user base as soon as possible, before I launch. While it’s critical for every app to have early adopters, I think it is especially important for me given that when you break it down I’m ultimately building a two-sided marketplace. This, by definition, creates a chicken and egg problem which I believe I can kick start with some luck and hard work on my part.

The idea is that if a bunch of drivers, instructors, and other participants are using it and the host of their event isn’t they become an influencer for the event host to join the platform. The cost of this to me in the early days will be a lot of manual work ensuring as many events as I can find are in the system whether the host of the event is a customer or not.

I’ve created a landing page and email list for early access to the app that I’m using to raise awareness of the app. Please feel free to share with anyone or any organization you think might be interested. The landing page is geared more for drivers and instructors than event hosts at the moment, but there is a contact form for event hosts to email me and get the ball rolling.

Brand

Indie Hackers is one of my favorite places to get real and honest information from successful and unsuccessful entrepreneurs. The podcast they put out is amazing and a source of inspiration for me. A member posted that they were offering to make free logos for anyone that asked so I submitted the landing page and a short description of what I’m doing and was one of products he chose to make a logo for! I think it turned out well. I’m probably going to play with it and tweak it to feel more modern and thin, but it seems like it could be a good product logo for the launch. You can check out the post here.

Technical

UI Performance & Data Loading

My implementation tactic for data loading has been to focus on UI speed and responsiveness. This essentially means that

  1. When data is needed draw the UI immediately with a placeholder (a spinner).
  2. Begin fetching data asynchronously.
  3. As data is returned from the server, redraw the UI with the real data.

I’ve taken some captures of what this looks like with the network speed reduced to “Fast 3G”. At the bottom of each picture you can see all the network requests and how those overlap (performed in parallel).

  1. Loading the list of organizations, their names, and logos. You can see how the main UI loads, then the cards with the organization names and image loading spinners, and finally each logo. All images are dynamically resized and scaled by the server to whatever size the web app wants.
  1. Loading a track, a list of organization logos, and the map for that track. The main UI load immediately and card with the track name, location, and spinners for the map and organization logos loads next. You can see each segment of the map appear on the page as it is loaded from the server. This is a contrived example given that the map is only loading one straight and one turn at a time.
  1. This is the same as example #2 above, but loads 25 straights and 25 turns in parallel. It only takes one UI update to show the entire map in this case and the UI loads much faster.

Event Filtering and Generation

Testing the event filtering logic led me to create a pseudo-random event generator. It uses an existing template that I have for HPDE events and randomizes the event host, track, circuit, number of stages, passing zones for each group, start and end dates of each activity, and color of each group. I used it to create a bunch of events that could be filtered on the page. I’ll probably leave these events in for the initial Alpha release to act as a demo.

Feature Scoping

I’ve decided to table 100% offline support until later in the project due to the complexity certain things like filtering results. I’d need to maintain two implementations of the filtering logic (one on the server and one in the web app) to work offline which I don’t have the time to implement or maintain at the moment. For the time being, the app will work for any page that was loaded offline, show data that was downloaded, and only work with the combination of filters specified before the device went offline.

Issues

I took some time to load all of the tracks that I’ve been drawing into the app, but ran into a small problem with how they render. You can see the slices between each segment and since the physical size of some of the circuits of a given track (e.g. VIR Patriot) in relation to their parent track makes them render unnaturally large in the app. I also am using the actual SVG viewBox value for each map now which made them all scale up and clip the edges of each track. It also causes the cards and panels to have inconsistent sizing and alignment. I’ll need to get this fixed soon as it is a pretty critical component of the app.

Oh, and my Nespresso machine broke. It is going to be long week. 😭

Timeline

I am terrible at time estimation. QED. I’ve adjusted my timeline and here is the new plan. I tried to add some pessimism into the process so hopefully 🤞 things get completed sooner. At least it will make me feel less bad if I miss targets again? On the bright side, I feel that I’m “leveling up” at the fastest pace I’ve ever been in my career and wouldn’t trade it for the world!

After the alpha is out, I can start building the production-ready backend in preparation for primetime. I fully expect I’ll be able to iterate faster once the production server and databases are done. By then I’ll have a set way of doing things and I can focus more on building features and fixing bugs rather than laying the foundation of a modern app.