Posts in "life"

Week in Review

This week I started getting back into some serious work for other clients. My schedule is kind of weird, I’m a consultant working 50-50 for two different companies (~20 hours each), so in a way I have two clients. However; one of the companies is an agency so I contract for them and then I contract for additional clients through them. I have two clients I bill but three or four clients I work for.

I’m happy to get back into agency work, it’s a lot of fun flitting from project to project. This is an overview of my week:

  • Working in a legacy Phoenix code base I spent a few hours doing PR review and then developing a new feature which will change the way a specific type of order gets processed. This project has a fairly lengthy state machine that orders will pass through (think, credit check, sales order, customer notification, shipping), it can get pretty complex depending on the customer’s location, configuration, and the product they ordered.
  • I’ve been working on some infrastructure updates in an old Rails project, we had fantastic junior do the back breaking work of migrating the app from Rails 5 to Rails 8. It’s working locally but there are some issues running it on the actual EC2 instance.
  • Working with TypeScript, GraphQL and Rails to develop a history modal to display PaperTrail versions. Most of the back end work was done by another developer to convert the actual Version record into a nice “log” I’m just trying to query them and display them with some filtering by date. This was part of a larger sprint this week and last which was all-hands on (about 8 developers).
  • Personally, I made a few improvements to my Go tool to fetch my current time for the month from Harvest. Further improvements would only be a waste of time but I’m having a lot of fun playing with Go.

Harvest Timers and Go!

This week I put together a tiny Go project. Go’s been on my “to learn” list for years now but I’ve never quite gotten around to it. Over the summer I got as far as reading a few articles and skimming the documentation but I didn’t have the time to make anything.

I’m a contractor working, primarily, for two clients. One is an agency that has their own Harvest account for tracking time against client projects. The other client is a traditional product company, I track time and bill them with my own, separate, Harvest account. It’s a bit of an annoyance because having two separate Harvest accounts means I have to sign in twice just to figure out how many hours I’ve worked in the month so far. I created a little CLI (the CLI part is not quite implemented yet) to query both accounts, grab my monthly hours, and total them.

Strapped for time I asked Opencode to generate a basic query to an endpoint and parse the returned JSON, this outline was enough for me to go the rest of the way implementing what I needed.

You can check it out here, but unless your in the exact same situation as me, it’s likely not going to do you much good!

codeberg.org/tfantina/…

Legacy Software

After about 7 months exclusively working on a product team I’ve started delving back into a bit of agency work with clients. It’s a stark difference moving from a code base with an up to date version of Rails, the latest TS/React best practices, etc. to just trying to get docker compose up to run on a Rails 5 project but it’s also a lot of fun.

As frustrating as working in ancient code bases can be, and I get why a lot of programmers hate it, solving these kinds of problems especially within the constraints of a tight budget can be a lot of fun. Greenfield projects are basically writing code, and writing a lot of it, legacy projects help you flex your Docker muscles, read release notes, and calculate end of life scenarios for Ubuntu versions!

Tableau

I’ve been slowly rebuilding my personal site, from the ground up, with Tableau. My goal is to include as little JS as possible and keep the payloads as light as possible. The main thing is that I want to be working in Elixir as much as possible, which Tableau allows me to do. It’s a lot of fun and, currently, the Tableau project is in the early stages so anything I tweak may be a nice little PR I can open in the future.

Pride and Prejudice

Finished reading: Pride and Prejudice by Jane Austen ๐Ÿ“š - is it cliche to give this 5 stars? Such a great book. I haven’t read it before, but I grew up watching the movies (in particular the 1995 mini-series). It’s been almost 20 years since I’ve seen any of them though. This was, actually, a delightful way to read the book; I found that it was familiar, but I remembered so little that the plot wasn’t betrayed by my memories.

I never posted an updateโ€ฆ both chrysalises hatched and began their journey mid-September. One we saw fly via our camer set up and the other we were lucky enough to see in person!

Hatching monarch in its jar

Weekly Round Up: June 13, 2025 ๐Ÿ‘ป

It was a week of state machines. Two separate Rails projects, two separate state machine libraries (state_machines and aasm), both sending emails. One is a fairly straightforward project for a department of education, it’s an old codebase but Objective built it and has been working on it ever since. As such, it’s fairly clean and straightforward for it’s age. I think that the more contractors and firms a codebase passes through the more muddled it gets. I’ve been working on this codebase for about two years now. The entire time I’ve been working to convert an old paper process to a digital one, it’s not an overly ambitious project but the budgeting has necessitated a slower pace of development. With only a few months left in the yearly budget (in education I guess the fiscal year ends with the school year) I was asked to quickly implement a form that allows users to draft a custom email message and attach a PDF. It’s been a while since I’ve done this with Rails, my last experience doing so was in the Paperclip days and that was not too fun. I’ve been pleasantly surprised with ActiveStorage, it’s much more plug-and-play then I recall (I’ve also been developing a lot longer now).

The other project is far more involved, my new full-time at gig at Built. It’s been exciting to work in tandem with another developer who has been handling the front-end work. Coming from a small agency I’ve always developed features full stack. Part of why I wanted to switch to a dedicated product team was to have experiences like this one where a greater degree of planning and coordination between developers was required. I started by creating a model last week and writing as many tests as I thought would be relevant. I’ve been through TDD phases in the past; but I think in small teams and projects TDD offers diminishing returns. It makes a lot of sense in a scenario like this, even on a fairly small team, since I’m developing features that I can’t be able to test in the browser until the other developer has her features in place. She in turn won’t be able to know if the front end works until my code is merged into her branch. This feature was the bulk of my week but it came together in time for some Friday afternoon QA of which I’m sure there will be several things to fix on Monday morning.

Weekly Roundup: May 2, 2025

This week I formally transitioned from my fulltime consulting gig at Objective for a fulltime gig at Built For Teams more details on that in a future post. However; broadly speaking it means that I’m dusting off my Ruby skills, diving deeper into the realm of OO programing then I ever have before.

Farewell ASDF

Last Friday night I pulled a Flutter repo I’m working on with a friend. I started having all kinds of issues trying to install Cocoapods. gem install cocoapods but then flutter run produced this error:

Warning: CocoaPods is installed but broken. Skipping pod install.
...
Error: CocoaPods not installed or not in valid state.

Ok. So do some more research throw in a sudo, no luck. pod version produces this error:

<internal:/Users/travis/.asdf/installs/ruby/3.3.5/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>:136:in `require': linked to incompatible /Users/travis/.asdf/installs/ruby/3.1.6/lib/libruby.3.1.dylib -

Ah! I’ve seen this more than once! Ever since I shifted to a Ruby focused team at the start of the year I feel like Ruby version management has been an uphill slog. I’ve reshim’d multiple times, removed versions of Ruby, removed the Ruby plugin, and reinstalled ASDF. Things work for a time but eventually I run into errors like the above. My hunch, which may be ovbious, is that something was wrong with my setup that was placing versions of Ruby inside other versions (ruby/3.3.5/lib/ruby/3.3.0); I’m not sure if the path is supposed to look like that but it doesn’t make sensee to me. I’m willing to take responsability here, it may be that my $PATH was misconfigured (although I attempted multiple times to proide a concise path for ASDF) or that something in my system was messing with ASDF. I love ASDF, it’s served me very well for years. Being able to remove rvm and nvm and seamlessly manage Elixir versions between projects was a breath of fresh air. The docs are clear and concise, the tool provides enough functionality to get stuff done without getting in the way. However; for whatever reason, the slog to get Ruby working just took its toll. One of my coworkers mentioned Mise which is a drop in replacement for ASDF. I installed it in about 30 seconds and in 45 seconds my project was running with Mise. ๐Ÿ‘

Weekly Roundup: Apr 25, 2025

At the agency, we have a customer who has asked that customers accept terms of service before checking out. This is for an Elixir project; mostly fullstack Elixir however the frontend has an odd assortment of sprinkles: StimulusJS and React. I created a terms_and_conditions versions table and an accompanying view helper which will check a terms_version_accepted on the user record if the last terms_and_conditions.inserted_at date matches the terms_version_accepted then the user is shown an active “proceed to checkout” button, if not the button is disabled and a note asking them to acccept the terms of service will display.
Since most of the Elixir projects I work on are fullstack (Phoenix LiveView) I don’t often get to write API endpoints. The API work on this was admittidly very small, a simpl endpoint that takes the user’s ID and updates the terms_version_accepted timestamp when they click “accept” in the modal. It returns a URL which we then append to checkout link allowing the user to proceed. This feature is due May 5th but I’m hoping to get onto the staging server on Monday or Tuesday.

Internal Tooling:

I’ve been using fzf for a while but I’ve wanted to filter only unstaged files, ideally whenever I type git add I just want to see a list of unstaged files that I can add. Admittidly I got some help from AI to do write this up:

function git_add_unstaged() {
    local files
    files=$(git diff --name-only --diff-filter=ACMR | fzf --multi --preview 'git diff --color=always -- {}')
    if [[ -n "$files" ]]; then
        BUFFER="git add $files"
        CURSOR=$#BUFFER
    fi
}

function git_add_unstaged_widget() {
    if [[ $BUFFER == 'git add' ]] && [[ $CURSOR -eq $#BUFFER ]]; then 
        git_add_unstaged 
        zle redisplay
    else 
        zle self-insert
    fi
}

zle -N git_add_unstaged_widget 
bindkey ' ' git_add_unstaged_widget

I’m wondering if I’ll find the automatic git add to be jarring or have situations such as a merge conflict where this may not work. If so I can always fiddle with the bindkey but for right now I’m enjoying my new found git add speeds.

Weekly Roundup: Apr 18, 2025

Working for a small agency I am fortunate to work on a number of fast moving projects simultaneously. For years I’ve failed to document what I do during the week but I’m going a little recap of my week. One part historical record, one part general interest. I’m posting it on my blog in the off chance that somebody reads it and, facing a similar problem will reach out I’m always happy to discuss what worked for me and what didn’t work. It also doesn’t hurt to put this stuff into the world to show that yes I actually do work; I haven’t always had the most active GitHub but most of my client projects a private/propriety. I’m easing into this, all week I was looking forward to this post; now, however, I realize I should have been working on this not cramming it in from memory on a Friday night.

This week was a balance between my ongoing Elixir projects and a newer (to me) Ruby project.

  • For the past five years I’ve either supported, or been the lead dev on a large B2B ecommerce platform which handles a few million in daily sales. Over the winter the company began consolidating their North American and European processes which includes using said platform for sales in the EU. Although the hope is that the European process will align with the North American there are some relevant differences. For example in North America the client’s product is technically considered a “raw material” which means there is no “Value Added Tax” (VAT); however in Europe, depending on the country of origin and the destination VAT may be charged, other relevant changes are shipping across borders, truck loading calculations and different invoicing procedures. At this point we are still in the research and discovery phase but I’ve been working with another developer to scope this project out and write some preliminary tests as research.
  • For another client I’ve been moving from a Quickbooks Online integration to Quickbooks Desktop, this is a multi-tenancy Elixir Phoenix app so I’ll be keeping the Online functionality and just adding a connection to Quickbooks Desktop. The API docs for QBOnline are fairly good, this is not the case with QB Desktop, it’s evident that Intuit either has the platform on life support or intentionally obfuscates the functionality to foster a consulting industry around the product. QB Desktop uses an SOAP XML type endpoint. Having wrangled fairly nasty endpoints with SAP I wanted to, if at all possible, avoid dealing directly with QB Desktop. I discovered a service called Conductor that does the bulk of the heavy lifting and allows you to hit a very concise REST endpoint.
  • Since the beginning of the year I’ve been transitioning from primarily Elixir projects at the agency to a single Ruby based product. On that front I’ve been involved in an ongoing integration with BambooHR; partnering with Bamboo to pull employee data from their endpoint.
  • On a personal front I finished the migration of this blog from Ghost back to markdown files. I still love Ghost but managing my own instance and integrating it with my Garden proved to be more management than I wanted.