March – A Retrospective

I’m fond of saying that if you don’t schedule maintenance for yourself, maintenance will schedule itself for you. And like much fine advice in this world, it’s the kind of thing we should take our own word on more often. Such is the case with this past March – I had much I wanted to write about in this space, but I let this slide in favor of other things.

Client Satisfaction

I’m happy to report that this year’s contract work may be coming to a close – there will be a post out by the end of the summer with a retrospective on the process of building a new website and adopting new tooling for the Fort Madison Art Center, a process which I assisted. It is as always an honor and a pleasure to see business owners and organization staff see their visions for delivering their ultimate customer experience come to fruition, and to feel more comfortable and empowered with technology.

The Guild of the Magi

A set of two circle or pie charts. The top one is a fully colored circle titled "Why I assumed I procrastinated" and the colored circle section is labelled "Laziness".

The second pie chart has five segments of varying sizes and is labelled "Why I actually procrastinated". 

In order of ascending size, the sections are "Feeling inadequate", "Stretched too thin", "Perfectionism", "Didn't know where to start", and "Fear". Fear is about 10-15% larger than the next largest wedge.

I used some of my contract fees to invest in my game The Guild of the Magi – I now have the very first custom music for the game commissioned and I will be writing about what a joy it was to work with Liam Frievald when it is ready to share.

I also spent a considerable amount of time analyzing and paralyzing on some technical decisions upcoming with this game. I knew from the start that I didn’t want to continue using Ruby as the backend, but that meant deciding what I did want to use as the backend. Do I do something either in php or resolving to php so I can continue using my current host and save costs? Do I switch hosting providers, spend more money, but gain flexibility?

And what do I want to write? I really want to go ahead and have some sort of highly structured, performant language. I toyed around with using phel but as it is earlier in development I decided that I would rather write a small card game in it instead of my main game. Instead I am currently leaning towards using Clojure as it means I can move between using Lisp and Java as I please.

Further, I migrated my task list out of my personal Shortcut organization to the GitHub organization. This means that as I gain a userbase, they can see and comment on issues in an organized fashion, which is important to me. Many petsites have forums that… don’t seem super organized or well suited to being a support tool to me. Some petsites have support forums and a helpdesk tool!

I am pretty strongly of the opinion that immersion works better in on-lore and off-lore areas. YouTuber GoodTimesWithScar has a good summary of how theme parks handle park immersion for guests, building entire maintenance areas that are not visible to guests and using color and landscaping to draw attention to theming instead of the off-lore HVAC sitting behind a hedge.

Having a single point of support where users can see what is being prioritzed and why should help improve the experience of on-lore areas.

And now that my task list is far more organized, it’s getting to be doable to actually follow through on planned functionality.

What I’ve learned from two technical interviews at the same company

Interview 1

Think Fast – It’s a language you haven’t used in at least three years

The interviewer was kind enough to allow us to pretend that I remembered how to do string interpolation in python because I at least knew what I wanted to do and that there was a method to do it, and this is not entirely a test of how fast I can get through the Python documentation.

I was glad at least that I’ve heard of a lambda before even if I don’t use them a lot. I tend to prefer named functions simply because as a newer programmer, it’s really nice if automatic errors are labelled with the name of the function that raised the exception instead of going to a line of code and evaluating all the tasks in your head to see where things went wrong.

Performance Considerations

Honestly, the biggest performance consideration (how do you handle gathering insights across an increasingly large dataset that constantly needs to be indexed) is a ‘solved problem’. Yeah, I’m sticking with my comfort zone to crib how Splunk does it but on the other hand, they have a tool that can sort and search multiple terabytes of data in seconds. To be honest, I’m just not that interested in reinventing this particular wheel at this time. It’s a little advanced for my skillset and I’d like to do some more learning and growing before going toe to toe with Big Data greats.

I did have some experience using an API in Python, though

While not shown here, I did have some Python program code left over from an initiative that I tried to get going at a previous employer. The interviewer was impressed that I had identified a common pain point facing the clientbase – which was that as the clients were a largely on-premises deployment strategy, they were vulnerable to losing access to their patient data in the event their main office lost power. Their main office could lose power for a variety of common reasons like a tree hitting a power line, but there are major storm seasons that hit various regions of the US every year. This is a regular and predictable event. So what I had done was I had obtained a then-available free-tier API key to Wunderground, and had it cross reference the clients I was responsible for with whether they were currently under a serious weather-related event. Then I could proactively alert clients to do things like print off schedules and patient contact information, ensure that their generator had fuel if they had one, that kind of thing. For the lifetime of this tool there was a period of time where my clients were able to be more responsive to weather events. Because my immediate supervisor didn’t see the value in this, when Wunderground retired their free tier on their API the wider clientbase never got this protection, and the clients who got hit by the Texas snowstorm the following year were far less prepared than they could have been.
The interviewer loved it, and I was really excited for how things were going and was confident that I could re-learn and surpass my previous Python knowledge.

from stream import streams

changelog = []


def frontend_read():
    print(changelog3)


def main():
    global changelog
    global changelog3
    # Each stream is going to return logs in sorted timestamp order.
    # Merge these sorted streams into a single sorted stream in the var `changelog`.

    # Assume `changelog` has a .read() method attached which the Frontend can
    # use to display the Changelog to the end user. We'll just call print to simulate
    # what the end-user will see.

    # The user will want to see a "timestamp", "integration", and "message" for each log.
    # Logs should be sorted in reverse chronological order.

    okta = streams[0]
    goog = streams[1]
    jamf = streams[2]

    while len(changelog) < 10:
        # the first way I want to attack this is here: each integration value is aware of where it came from and this is where they are concentrated before being used
        m1 = next(okta)  # . + "okta" (.append())
        m2 = next(goog)
        m3 = next(jamf)

        changelog.extend([m1, m2, m3])
        # sorting the changelog - https://stackoverflow.com/questions/18563680/how-to-sort-a-2d-list Considering using a lambda to access the first element in each element to use as the sorting value
        changelog3 = sorted(changelog, reverse=True, key=lambda l: l[0])
    frontend_read()


main()
#stream.py

from random import randint, choice

random_logs = [
  "User created", "User given app access", "User removed app access",
  "User added to group", "User removed from group", "Group created",
  "App created"
]


def _event_stream(start, low, high):
  timestamp = start
  i = 0
  while True:
    i += 1
    timestamp += randint(low, high)
    yield (timestamp, choice(random_logs))


streams = [
  _event_stream(0, 0, 1),
  _event_stream(0, 0, 10),
  _event_stream(0, 2, 5)
]

Interview 2

/**
Implement a restaurant waitlist data structure. It should support the following features:
A party of customers can join the waitlist.
    - one or more
  - the party size is then static
A previously joined party can leave the waitlist at any time.
The restaurant serves the first party whose size fits the empty table size at a time (a table size is given as an argument).
    - tables being stored is handled by another function
**/

//store waiting parties

// remove parties - either customer initiated or because they're beings served


const waitingList[];
// array of objects
//[n] = {name: string , partySize: int}

waitingList.push({ name: "suyog", partySize: 4 });

function joinWaitingList(name, partySize) {
    newParty = { name: name, partySize: partySize }
    //mutate the global array so that everyone has access to the new waiting list
    waitingList.push(newParty)
}

function customerRemoveFromWaitingList(name) {
    /*
    - loop over array
    - find value associated with key 'name' of selected element
    - slice this element from the array or return error if name not found
    - waitingList array no longer has name's party 
    */


    //party is the value of the selected element
    waitingList.forEach((party, index) => {
        if (party.name === name) {
            waitingList.splice(index, 1);
        }
    })

}

function serveCustomer(tableSize) {

    findParty = waitingList.forEach((element, index) => {
        if (element.partySize <= tableSize) {
            waitingList.splice(index, 1);
            return element.name;
        }
    })


}

Interview 2

This one I struggled with as well, but again the interviewer was willing to let me pretend I remembered how to do interpolation because I knew where and what I wanted to do. But because I tripped up on that, I then proceeded to forget variable definitions throughout the space as I let my nerves get to me.

My Friend The Senior Software Engineer looked at it as well

Long Documentation vs Code

Friend: It’s generally not helpful to document how code is doing something. that makes reading the documentation the same as reading the code. it’s more helpful to summarize what the intent of the code is. ideally as briefly as possible. ideally in the function name

Comments are mostly useful if you need to clarify some Arcane Bullshit

Like, # we need to call so-and-so function even though it doesn’t seem to do anything because it actually secretly initializes this undocumented dependency

I’m not sure how much of this is really a problem. Sure, there’s a lot to be said for “the code should be self documenting”, but the need of a junior engineer is different from the need of someone who is far more familiar with the institutional knowledge and the reason why certain decisions were made. In the case of a live technical interview, my view has always been that it is a great strategy to write down the method that will be used to achieve the prompted goal. That way the interviewer immediately gains insight into your problem solving style. One can reference it if they get nerves or lose track, or show how as they get into the problem their proposed solution changes to better fit the need.

Performance Considerations

  • The interviewer mentioned that it would be better for an applicant to have some understanding of what the O notation is of their proposed approach

Friend: like seriously “big o” is so tiresome. saying “o value” is like saying “flywheel pattern”, “first order normalization”, or “a monad is a monoid in the category of endofunctors” . it just makes something really simple sound really complicated.

I don’t disagree here, but there’s a middle ground between having low sense of the performance capability of a proposed solution and an advanced sense of performance considerations.

Things are heating up in the Data Structures and Algorithms Fandom

  • Could have used linked lists to increase performance of removing a party from the global waitlist

Friend: – I disagree about linked lists. It should be an immutable array using Array.filter and Array.concat. And it should not be stored in a global scope. if performance is an issue due to massive theoretical arrays, then this in-memory exercise is no longer relevant anyway and you should be using a DB to store customers rather than a variable.

O value is unnecessarily obfuscating language. It’s more constructive to just talk about this in terms of “how many times do you have to traverse the array”.

You should always use const, then let, then var, in that order of priority. use const as much as possible except when it forces you to do something complicated.

I love watching senior programmers fight, it’s always educational.

I ended up not getting hired by this company, and I’ll add “makes you schedule four interviews yourself with a bunch of people to campaign for joining the company” to my list of Weird Vibes That Make Me Not Want To Work For Your Company. I don’t think I’ll ever want to spend that much time interviewing again – between the calls, take home, and four interviews I think I spent over seven hours interviewing with this organization. I learned a lot from talking with incredibly smart people, and I hope I get to run into some of these folks again at different points. It was a little disappointing to spend that much time and not get the offer, but I am feeling confident that there are other positions out there and I can pursue those to grow as a programmer and be of use to society.

Thank you for reading. Please let me know if there are any clarifications I can make or further questions I can answer either down in the comments, on LinkedIn, or hit me up on Mastodon.

Related Posts