">
 

The Code I Couldn't Leave Alone

Iniciado por joomlamz, Hoje at 14:25

Respostas: 1   |   Visualizações: 2

Tópico anterior - Tópico seguinte

0 Membros e 1 Visitante estão a ver este tópico.

Saudações à comunidade do **webmastersmz.com**.

Como especialista em tecnologia, analisei o tópico **"The Code I Couldn't Leave Alone"** e gostaria de partilhar uma reflexão técnica sobre a eterna batalha entre a "perfeição" do código e a "entrega" do produto.

### Análise Técnica: O Dilema da Otimização Excessiva

O artigo toca num ponto nevrálgico para qualquer programador: o **"Code Smell"** ou a vontade irresistível de refatorar código que, tecnicamente, já funciona. Do ponto de vista de engenharia de software, podemos extrair três pontos cruciais:

1.  **Lei dos Rendimentos Decrescentes:** Muitas vezes, perdemos horas a otimizar funções para ganhar milissegundos que não são percetíveis pelo utilizador final. A refatoração deve ser guiada por métricas de desempenho (*benchmarking*) e não apenas pela estética do código.
2.  **Débito Técnico vs. Estabilidade:** A vontade de deixar o código "limpo" é louvável, mas se o sistema está em produção e estável, cada alteração introduz o risco de regressão. A regra de ouro deve ser: se for para refatorar, que seja acompanhado por uma bateria robusta de testes unitários.
3.  **A Armadilha do "Refatorador Eterno":** O desenvolvimento ágil prega o *Refactoring* contínuo, mas o foco principal deve ser sempre a entrega de valor. Quando paramos de desenvolver funcionalidades novas apenas para alcançar um código "impecável", estamos a sabotar a viabilidade comercial do projeto.

**Pergunta para o fórum:** Até que ponto vocês, como webmasters e programadores, consideram que a refatoração excessiva prejudica os vossos prazos de entrega? Já tiveram algum caso onde uma "pequena melhoria" no código acabou por derrubar um site inteiro em produção? Vamos debater isto aqui.

***

Para garantir que os vossos projetos e fóruns rodam sem falhas, convido-vos a conhecer as soluções de alojamento de alta performance da **AplicHost** em [https://aplichost.com](https://aplichost.com). Oferecemos a estabilidade e a velocidade que o vosso código merece para brilhar na internet moçambicana.

The Code I Couldn't Leave Alone



Tópico: The Code I Couldn't Leave Alone
Categoria: Tutoriais | Programação & Tecnologia
Idioma Principal: Português (Conteúdo de Tecnologia)

Descrição do Conteúdo / Informações:
-------------------------------------------------------------------------
The bug report was simple enough. On the reports dashboard, if you changed the date range while a filter was already active, the page number didn't reset. So a user could end up on page 4 of a report that now only had one page of results, staring at an empty table with no idea why.

I found it fast. The pagination state and the filter state were living in two different places, useState in the table component and useSearchParams for the filters, and nothing was watching one to reset the other. I added a useEffect that reset the page to 1 whenever the search params changed. It was the smallest change that unbroke the dashboard, and I wasn't about to restructure the component tree for a twenty minute fix. Tested it locally, clicked through a few filter combinations, watched the empty table problem disappear. Twenty minutes, maybe less.

I didn't open the pull request yet. I told myself I wanted to read through the diff once more before pushing.

That's when I actually looked at ReportFilters.tsx for the first time in a while, and I didn't love what I saw. The filter state existed in two places at once. Some of it lived in the URL through useSearchParams, which is what actually drove the API call, and some of it lived in local component state that only existed to control what the dropdowns displayed. Most of the time they matched. Occasionally, if you clicked fast enough, they didn't, and you'd see a dropdown showing one filter while the table quietly fetched with another. Nobody had filed a bug for that. I don't think anyone had ever managed to click fast enough to notice.

But I'd noticed it now, and once you've seen a bug like that, it's hard to unsee it. It reminded me of a race condition I once tracked down in a checkbox that looked right on screen while the requests behind it quietly disagreed, the same kind of mismatch between what the UI shows and what actually happened. Different bug, same shape.

So I pulled the local state out entirely and made the URL params the single source of truth, reading everything through useSearchParams and writing through router.replace. That's a real fix. Two sources of truth for the same data is exactly the kind of thing that eventually causes a much worse bug than the one I'd started with. I felt good about that change, and I still do.

While I was in there, I noticed the filter logic itself, the actual function that turned the search params into a query object, was duplicated. It existed once in the component to build the fetch request, and again inside app/api/reports/route.ts to validate incoming params on the server. Same logic, written twice, slightly out of sync, because someone had updated one copy when a new filter type was added and forgotten the other. I pulled it into a shared lib/filters.ts and imported it in both places. That's not a nice to have. That's the kind of drift that can quietly turn into a production bug.

At this point I'd fixed the original bug, removed a genuine duplicate source of truth, and closed a real gap between client and server validation. If I'd stopped there, this would just be a normal Tuesday. I didn't stop there.

Once the filter logic was centralized, I looked at the route handler again and thought, well, since I'm already reading through this, the report data itself doesn't actually need to be client fetched at all. It's not interactive in any way that requires it. It could be a server component, fetched directly with the filters coming from searchParams in the page props, no client-side fetch, no loading spinner, no waterfall. In my head it looked roughly like this.

export default async function ReportsPage({
searchParams,
}: {
searchParams: Promise<{ range?: string; status?: string }>;
}) {
const { range, status } = await searchParams;
const reports = await getReports({ range, status });
return <ReportsTable data={reports} />;
}

That's a bigger change than a bug fix. It touches the page structure, it means rethinking how the table gets its data, it means the loading state disappears entirely because the server just renders with the data already there.

I started doing it anyway.

I got about halfway through converting the table to a server component before I stopped, not because it was going badly, but because I glanced at the git diff panel in my editor and the file count had gone from one changed file to seven. Seven files, for a bug that was, structurally, a missing line inside a useEffect.

I sat there for a second looking at that number, and the question that actually stopped me wasn't "is this too much work." It was smaller and quieter than that. I asked myself whether the server component conversion was something the product needed right now, or whether it was something I wanted to do because I could see exactly how to do it and it bothered me to leave it undone once I'd seen it.

I didn't have a clean answer immediately, which is honestly what made me pay attention. The filter state fix and the duplicated logic fix, I could justify those in one sentence each, to myself or to a reviewer. The server component rewrite took a full paragraph to justify, and most of that paragraph was about how satisfying the final version would be, not about what was currently broken for anyone using the dashboard.

That's usually the tell, I think. Not the size of the change. Plenty of small changes are indulgent and plenty of large ones are necessary. It's how long the justification takes, and who the justification is actually for.

So I split it. I finished the bug fix and the shared filter logic, wrote a focused pull request that a reviewer could read in five minutes and understand completely, merged it the same day. The server component rewrite went into its own branch with its own description, explaining what it would remove, what it would simplify, and why it was worth doing on its own terms instead of riding in quietly behind a one-line bug fix. It's a good change. I still believe that. It just needed to stand on its own, reviewed and evaluated as what it actually was, instead of hiding inside something smaller.

What stays with me isn't that I almost shipped too much. It's how reasonable every single step felt while I was inside it. Nobody would have blinked at any individual commit. The dropdown desync fix, obviously worth doing. The shared filter util, obviously worth doing. Even the server component conversion, on its own merits, was obviously worth doing. Stacked together in one sitting, driven by one bug report, they stopped being a response to a problem and became a response to my own discomfort with leaving the file the way I found it.

I don't think that discomfort is something to train out of myself. It's most of why I'm good at this. Being able to see the second problem while you're fixing the first one is a real skill, and I'd rather have it than not. But seeing a change and shipping a change used to be the same motion for me, and somewhere in that two hour stretch I finally felt the gap between them instead of just hearing about it in theory.

I closed the laptop that evening having shipped exactly one thing, a twenty minute bug fix with a real structural improvement folded honestly into it. The bigger rewrite is sitting in review on its own branch, where it belongs, where someone can actually look at it and ask whether it's worth the seven files, instead of me deciding that alone at ten at night because I couldn't stand leaving a route handler half server, half client, one more day.


Joomlamz
Consultoria em Informática
-------------------------------------------------------
Especialista em Sistemas Web & Manutenção de Servidores.
A desenvolver o novo AplPortal com suporte a PHP 8.
Precisa de ajuda profissional? Contacte-me.

Tags: