As 2025 wraps up, I wanted to touch on some broader topics that I thought deeply about this year.

Active Record (Laravel Eloquent) and Domain Purity

Active Record is fine, maybe even good. I worked on a project in 2024 where I wanted to go full-on, all-in domain objects and repositories. I had just left a Java shop with some great devs, and I thought I needed to fully replicate their patterns. I also read Clean Architecture by Uncle Bob, which is typical Java-bro meat and potatoes. If it’s in a book, if micro-service Java devs use it, I thought, it must be The Way. I don’t like it, but I can admit it: PHP has a stink to it. It’s not taken seriously. Its execution model is alien to modern programming languages. Java is the backbone of so many big corps, from Netflix to Amazon. So I guess I wanted to write this project like it was in Spring Boot, so I could feel like I was a real developer…

But the project was in Laravel, so I had some real problems.

The framework is designed to work with models. It’s baked into its DNA. By leaning on this fact, everything is simpler, from auth to route binding.

Developers who worked at the company already knew Laravel, so onboarding them to a new style of writing code was a cost. And it would remain a cost for every developer who had to onboard to the project.

Laravel is quite good at rapid app development. The project was for a burgeoning market, and forcing the code to look like how I thought real code must be written for some unfounded belief I had meant going slower. Except I couldn’t go slower, due to the business demand… so I just worked longer hours for some kind of domain purity.

Domain purity in apps which are basically just CRUD is a silly thing to shoot for. The right tool for the right job. There are times where I:

  • Map an Eloquent Model into a domain object
  • Pass that domain object to a repository method
  • Use Eloquent’s Query Builder in order to insert the data
  • Construct a different domain object with hydrated data
  • Return that domain object to the caller

What am I doing? A lot of work for idealism.

I was missing the fact that active record forces the developer to think in terms of the database, which is actually incredibly valuable for CRUD apps. I liken it to mechanical sympathy. When I think about how the data is being stored and retrieved, I can make greater efficiencies and optimizations. I can retrieve exactly what is needed, rather than constructing a rich domain object which has data I don’t care about. My series of inserts, updates, or deletes can run inside of a small, very tight database transaction. I have witnessed developers write code where they treat all abstractions as the same: whether it’s reading from a database or an external API. This is dangerous. Understanding what is actually happening in our code is absolutely critical. Abstractions are great, but they are hard to get right. As a developer, I cannot just wave my hands at an interface. I must know what is happening in my production code in order to make informed decisions.

I am not here to make the claim that anyone else is doing it wrong. I do think the benefit of active record carries a stink similar to PHP, but memes and tropes are not a reality. As always nuance is critical, but not always something that our current climate values.

And what did I really bring with me from that Java team I briefly worked on? That testing is important. Good testing is made possible through good code composition. There’s nothing about using Eloquent Models that makes it impossible (or even harder) to compose code. There are some guard rails to put in place (requiring data to be preloaded or passed as a separate argument to a function; being careful about how data is mutated; never using Model Observers; using bulk inserts whenever possible, rather than single updates in a loop), but the code can lend itself to testing just as it would be if written in a different paradigm.

Testing

Big test suites are a liability. They cost time to develop and time to maintain. If a test pipeline takes too long, I see two outcomes:

One, developers get in the habit of not running the test suite locally. They just leave it for CI. Our laptops are much more powerful than the runners, so preferring the CI pipeline slows the feedback loop.

Or, the second option: I think to myself “I’ll just go and work on something else for nine minutes.” 30 minutes later, I remember to check the suite locally, see there was a failure, and switch context back. The time I spend waiting for the pipeline is usually not terribly productive: I’m either doing something non-work related (twitter, reddit, etc), or I’m half-reviewing someone else’s code.

Oh, and then once my suite looks clean on local, I push my code and run the pipeline there, potentially repeating the process of waiting, getting lost, and paying a context switch.

Slow CI pipelines slow down merges to trunk and releases to production. Slow dev feedback robs developer productivity.

Flaky tests cost money. Without fail, if a test is going to fail intermittently, it’s going to do so when I am in a hurry to merge something. I don’t know if there’s a way to retry just a single test in a CI pipeline, but I know I haven’t found it. That flaky test just cost me another full run through the test suite, which means I’m liable to fall into the trap of finding something small to focus on while I wait, and forgetting about the pipeline.

Mocking frameworks are problematic. Not because of how they work, but because of how they allow for poor code architecture, low-value tests, and misleading tests. I had a former colleague who told me “mocking frameworks are the devil,” and I thought he was being a bit extreme. I still don’t know if I would call them devilish, but I would say they’re worth actively avoiding.

Not to mention in PHP, classes cannot be marked final or readonly if you wish to use them with Mockery or PHPUnit. This isn’t the end of the world, but it feels like the tail wagging the dog.

AI Agents

As much as I hate to admit it, AI agents are pretty great. I don’t see them killing the career of software engineers just yet, but I do think they are here for the duration.

It is my belief that we are in a transitional state for software engineers. As software development enters a new frontier, we will be forced to change the way we work. Code reviews will be different. Upfront planning will be different. And of course, the practice of building software will be different. Clinging to the old way of doing things isn’t going to work, but neither is letting AI write and build everything.

I strongly dislike how much code I have to review now, either within my editor reviewing an LLM’s code, or the influx of pull requests from other devs. Agents, specifically Cursor’s BugBot, that automatically review code are a good first step. However, I see a problem with all of this: my brain turns off. I stop thinking about code the same way, or even really trusting my own instincts.

I also realize that anything over a few sentences becomes intolerable to read. My brain just starts seeking out context clues, and if I can’t find them, I have an LLM summarize it for me. The biggest scourge on all of business is the amount of doc-slop we create. Someone has two or three sentences that they want made into a Notion or Markdown document, which their LLM of choice expands into something that takes 30 minutes to read. No one reads it, and instead passes it to an LLM to summarize back into 2 or 3 sentences. Combine this with the tells of LLM writing: too many emojis, the word “blazing-fast,” em-dashes (if they haven’t spent a billion dollars training that out of new models), or just a writing style that doesn’t match the person who generated the doc. I immediately lose confidence in the document and get frustrated because I don’t believe they even read it.

It is a vulgar act to ask someone to read a document or review code that you yourself have not read. But our brains are atrophying and we’re losing confidence in our own ability to write, read, and think. I think that this is another place we need to change our practices as LLMs become ever-present.

Work-life balance

I have not figured out a way to suss out work-life balance in job interviews. I have seen work-life balance be bad in a couple of ways:

On-call rotations where something always goes wrong. If I have to be handcuffed to my laptop for an every entire week every six weeks, I’m going to be unhappy. If I expect that I’m going to be paged at 2 AM at least once every rotation, I’m going to be resentful.

Continuous, unrealistic deadlines. Having to work long hours occasionally isn’t something that I mind; in fact, I think it’s pretty standard in the industry. Once it becomes the norm at a company, it’s unbearable.

Support rotations are tough. Being in the support role when I am brand new feels like drowning. I don’t even understand what the ticket is describing or what the expected behavior is. Hell, I don’t even know if the ticket is describing exactly what is supposed to be happening. I am forced to ask for help, which doesn’t always feel comfortable. Five hours spent looking at support tickets feels longer than eight hours of coding and reviewing.


2026 will probably be a somewhere between good and great. It’s all in how we show up for it. I’m going to have to get comfortable with some of the things which at present make me uncomfortable. I’m going to have to open myself up to new ways of doing things. I know these are the paths to growth, and like all good things, they’re uphill.