Juanito P. Galvez (1928-2022)

My grandfather died last June. His love was rarely spoken, but can be felt through his actions.

I grew up with my grandparents because my parents decided to part ways shortly after I was born. Papa, as we called him (and Mama my grandmother), provided a home for myself, my mother, and my sister.

Papa rarely showed his emotions. When Papa’s mother died, I remembered seeing him walking to the neighbor to borrow their phone. He called the funeral service to come to the house. No emotions and everything was prepared. I only saw him cry once while giving a eulogy at my mother’s funeral. My mother told him during Martial Law that they might not see each other again, if things got worse for her. When I was three or so, I remembered going with Papa to Quezon province, where we visited my mother while she was detained and was set free a few months later. Life started became stable for us after 1984.

Back in 1999, before going back to college, I recalled Papa kissing me goodbye. The feeling was also similar: back then, I thought that was the last time we would see each other. The next time we saw each other was in 2012, when things started to settle for me.

Everything has a price

How much are you willing to pay to acquire something? Furthermore, once you’ve acquired it, was it worth the price you paid?

From Financial Advice for My New Daughter:

The price of a busy career is time away from friends and family. The price of long-term market returns is uncertainty and volatility. The price of spoiling kids is their sheltered life. Everything worthwhile has a price, and most of those prices are hidden. They’re are often worth paying, but never ignore that they are true costs. When you accept this you’ll view things like time, relationships, autonomy, and creativity as currencies that are as valuable as cash.

Starting from knowing what to avoid (e.g., absentee parent, debt burden, bad health, etc.), I would have to play my remaining years by not brute-forcing through life. I believe there’s a sweet spot (if I’m not already on it) between growing a family and having a fulfilling career; I just have to play in such a way that it does not lean toward a maximal outcome for only one side. I hope that makes sense.

Staying close to Rails’ conventions

Part 1 (re: Architectural Decisions) I was recently asked about the architectural decisions we’ve made in our most recent Ruby on Rails project (an e-commerce platform for sports apparel decoration).

We decided to stay close to Rails’ conventions as much as possible. This allowed the team to build out the first features quickly. This is usually not a problem for short-term projects, but it becomes a maintenance burden after a year, because after a year the team is also concerned about supporting what they’ve built despite changes to team structure or project focus.

Project-specific conventions

In some areas where Ruby on Rails has no opinion, we’ve established our conventions:

  1. Using service classes (and using LightService)
  2. Using namespaces to partition functionality (e.g., Dealers, Admin, Checkouts)
  3. Avoiding the use of JavaScript-heavy frameworks (e.g., VueJS) in favor of Stimulus and HTML-over-the-wire (this was done pre-Hotwire)
  4. Prefer application events over ActiveRecord callbacks when triggering jobs
  5. Adopting Spree as the e-commerce engine instead of building from scratch

Conventions distilled into pattern

We also wanted to make it easy for a new developer to understand how a feature was built and where to make subsequent changes. Having these patterns in place and adopted across the entire codebase also helps the maintainers to troubleshoot issues two years after a feature has been deployed to production.

Uploading a file without using any gems

I want to upload a CSV file from a page, and I also want to resist the urge to install a gem, which seems to be the default Rails developer behavior. No need to build a model; I just need a reference for the CSV for further processing somewhere. Here’s what I did:

First, I built a simple page with a form and a submit button. Ruby on Rails provides some helper methods to generate forms, namely form_with, form_for, and form_tag. I don’t need a model, so I used `form_tag` first. Unfortunately, I ran into this problem where the CSV file handle is not passed to the request. Instead, I used form_with and I was able to parse the CSV.

See also
Source code
FormHelper API documentation
FormHelper Rails Guide
List of file uploading gems

Staying long enough to suffer the consequences of your design decisions (or lack of it)

The book Understanding Software describes starting the right way.

How do you keep the design simple as the codebase grows? We want to avoid having a large codebase with no sound design. This could lead to the Big Rewrite, where nobody wins.

While incremental efforts such as refactoring could alleviate the pain of not having an established design, the team effort could have been prevented had there been some type of guidance at the beginning of a software project.

But what if you don’t know what the “right way” looks like at the beginning? A design would eventually emerge given enough time working on the system. This insight will not appear when you are pressed for time to build something or if your tenure in the project is measured in weeks.

To counter paralysis in choosing the “right design,” sometimes you just have to build something and stay long enough to experience the pain points of your implementation. Only by experiencing pain can one be instructed on how to improve their designs, especially after being paged at odd hours of the day.

On Messy Codebases

What follows is my personal experience related to this LinkedIn post: it’s all good until the dominant values of a group change with staff turnover.

In early 2018, our project had some critical features built using Vue.js. In hindsight, the decision to use Vue.js wasn’t carefully deliberated: everybody (me included) was convinced we needed to use something that would support a complex UI. We needed to learn Vue.js quickly while building out these critical features. What initially was thought of helping to speed up development turned out to be a liability. Everybody (me included) seemed to know that using Vue.js for this project was the wrong choice, but did not stop primarily due to loss aversion and the lack of a suitable alternative.

At this point, the dominant group of developers has built a Vue.js frontend with all the supporting code needed to render these single-page applications. The team proceeded to build more features on Vue.js (I failed to constrain its scope), which continued until these developers started to leave. This was also the time we addressed bugs with the Vue.js code. The developers left to fix the problems were not the same developers who built the features, which led to time that needed to be spent on knowledge recovery (figuring out how things work) and applying fixes.

In mid-2018, difficult conversations started between our client and the team regarding quality and delivery pace. We decided we needed to stop using Vue.js and look for a suitable alternative that did not require a steep learning curve. At this point, the codebase was a mess to figure out, but it was workable due to the tests we’ve started to prepare for the critical features. A new dominant group has since emerged, which valued maintainability and remembered what came before. The new team had to work on a controlled mess: keeping the existing Vue.js implementation working while building an improved replacement in the background. This team also had to continue to deliver value to the business while rework is being done. The new team also was less than half of the size of the original team, which meant that the new structure had to be distilled into a set of patterns that new developers could grasp.