Rafael Romão Director of Technology · Belo Horizonte
← Back to the short version

The long version.

Twenty-eight years, told as sixteen chapters. A borrowed book, a page of phone numbers, a concurrency primitive I had no business writing, and an architecture that turned out to have a name. I have kept the parts that taught me something, including the ones that went badly.

  1. 199801

    A borrowed book

    I was sixteen and working as a storekeeper's assistant. What I knew about computers was Windows 3.1 and 95, Word, Excel and MS-DOS, from the kind of computing course pack everyone in Brazil took at the time. Then a friend lent me a book about Delphi 3.

    I started going into the office in my spare time to use my boss's computer, working through the examples and then writing small programs that automated bits of our own work: stock lists, simple reports, anything with a form and a table behind it. My boss noticed he was getting free software and told me I could use as much spare time on that machine as I wanted. I do not think either of us understood what kind of arrangement we had made.

    What it taught meNobody gave me permission to become a programmer, and nobody was going to. The useful move was to find a real problem near me and solve it badly, then less badly.

  2. 200202

    The yellow pages

    Four years of that and I decided it was time for a real job. A friend who wrote Clipper told me I was already good enough, which I did not believe but wanted to. I was twenty.

    So I got the yellow pages and wrote down the name and number of every software company in Belo Horizonte. It was not a long list. Then I called each one, said I wanted to apply for a programmer position, and asked for an email address to send my CV to.

    It was a sassy thing to do, and it worked.

    By May 2002 I was a software developer at a company with clients in Brazil and Switzerland. The thing that got me through the door was not the Delphi. It was that I had been teaching myself English since 1999, purely to read what people wrote about Delphi on the early Internet. English was the working written language from my first day.

    What it taught meThe skill that opened the door was the one I had picked up sideways, for my own reasons, with no career plan attached to it. That has happened to me more than once since.

  3. 200203

    The mess

    I remember opening the codebase on my first job and thinking: this is far more complicated than I expected, and I have a very long way to go before I am as good as these people.

    That code was just messy. Structured-programming habits carried into a language that had moved on, a years-old Delphi desktop application being dragged from DBase to Paradox. I was not able to tell the difference between complicated and badly organised until years later.

    The senior developer told me not to touch the other project, the one for the international client, until he said so. That took about two years.

    What it taught meJunior engineers cannot yet tell essential complexity from accidental mess, so they assume the mess is their own ignorance. I try to name which one a new engineer is looking at, because nobody did that for me and it cost me two years of unnecessary doubt.

  4. 200304

    The joy of objects

    Delphi 7 had some object orientation, but not all of it. In 2003 I got onto a Java course, J2EE on Java 1.3, and finally saw the ideas I had been reading about actually working.

    I disliked J2EE itself. It had a strong do-it-exactly-this-way character that I have distrusted in frameworks ever since. But objects in practice, after years of objects in theory, were a revelation, and not only to me. Within weeks our Delphi code started sprouting camelCase method names. We regretted that fairly quickly.

    What it taught meA team that has just learned something will import it wholesale, including the parts that do not belong. Enthusiasm is not judgement, and the gap between them is where conventions go to die.

  5. 200705

    Going international

    I spent those years mostly on blood bank management systems, which meant learning a regulated domain where being wrong has a physical consequence, and starting to form idioms of my own. I was now senior enough to make my own mess rather than inherit someone else's, and to learn from that instead.

    As demand from the international client grew, my English, at that point still only reading and writing, got me onto their team. In 2007 I flew to Europe to work on site. It was my first experience of a team spread across regions, and it set the direction of everything that came afterwards.

    What it taught meDistance does not just slow communication down, it changes which kinds of decisions are affordable. You stop making the ones that need everyone in a room, and start designing so that fewer of them are needed.

  6. 200706

    Tasks, three years early

    The client was building a new laboratory robot and we had to write the software driving it. Another team's attempt in Java had gone badly and Delphi was visibly ageing, so we chose the shiny new C# 2.0. The tool had a simple interface and had to drive a set of motors in parallel.

    Everyone on the team could write a thread. At the number of concurrent operations we needed, writing them one at a time at every call site would have been tedious and quietly error-prone. So I wrote a small Task class: one operation, one background thread, composable, with the concurrency in one place instead of smeared through the application.

    The Task Parallel Library shipped with .NET 4 in 2010 and did the same thing properly. I was pleased they called it Task, rather than Future as Oxygene and Java had.

    What it taught meBeing early is not the same as being right. We owned a concurrency primitive for three years and every bug in it was ours. I would make the same call again, and I now ask out loud how long we expect to carry a thing before we build it.

  7. 200907

    Architect, for the first time

    A big new contract, a large system, a large team, and the first time the title was actually mine. My job was to say how the software would be structured and to build the foundations the team would deliver on. Our first real move to web services in the backend.

    The part I cared most about was not the module structure, though a replicable one is what made new features cheap. Delphi succeeded in the 2000s largely because its component libraries and drag-and-drop model made ordinary work fast, and I had been writing VCL extensions since I started. Here I got to write an entire client-side component library over our RemObjects services, an alternative to their Data Abstract.

    GitHub did not exist yet in any way that mattered to us. That library is almost certainly gone.

    What it taught meWork that is not published does not survive, no matter how good it was. It is one reason nearly everything I build now is in the open, even the small things.

  8. 201108

    Time for a big change

    Nine years at one company accumulates a particular kind of tiredness. Everything I had built so far was desktop software, Delphi or WPF, and the web had long since become where things happened. Web Forms was giving way to MVC, jQuery had made single-page applications thinkable. The conclusion was not subtle: learn web development or become unmarketable.

    Up to then I had learned almost entirely from blog posts and forums. This was when I started reading books properly: Clean Code, HTML5 and CSS3, jQuery, ASP.NET MVC 3, test-driven development.

    Then someone I had never met called to ask whether I was the WPF developer who had been recommended on a forum. I still do not know who recommended me. I took the job, and it was WPF again. The move to the web did not happen for years. What did happen was that I became a person who reads.

    What it taught meThe plan was wrong and the habit was right. I did not become a web developer that year; I became someone who learns from primary sources, which turned out to matter far more.

  9. 201209

    The word came later

    Two years into geographic information systems in WPF, the CTO called us into a kickoff. He wanted his dream platform: individual backend applications, each responsible for one job, passing results to each other over a fast message bus. He was excited and also frustrated, because it was his third attempt.

    I asked him to give me the job. He did.

    It was my first large backend system and the results were not as good as they could have been. It was research and development, and by that standard it worked. One thing that came out of it was Reactive Services: a message-bus abstraction with a RabbitMQ adapter, an authorization model, and opinions about where service boundaries belong. I did not put it on GitHub until years later, but it was written in 2012.

    Martin Fowler's article named the pattern the following year.

    I had not read my way to that architecture. I had been pushed into it by a monolith that kept tearing along the same seam. Docker and Spring Boot were becoming interesting around the same time; today the whole stack has names and a literature and Kubernetes underneath it.

    What it taught meI trust an architecture I arrived at from a bottleneck more than one I arrived at from an article. A pattern adopted before you can name the pain it removes is just decoration that is expensive to remove later.

  10. 201510

    A step back

    I was working as an architect and team lead when a better-shaped opportunity appeared elsewhere: leading a team, in the setting I thought I wanted. I took it. By the time I started, the leadership position had evaporated. There was a job for me, but as an ordinary programmer. No team, no architecture to own.

    It turned out to be a gift. I had the salary I wanted, I was writing code all day, which is the part I love, and none of the weight. I also knew exactly how it would end. I was being paid for a role I was not performing, and less than a year later I was let go.

    What it taught meA mismatch between what you are paid for and what you actually do is not a comfortable secret, it is a countdown. I would rather renegotiate the title early than enjoy the gap while it lasts.

  11. 201611

    A step forward

    I had been getting ready for this for a while. My English was there. My algorithms were not: I had not studied computer science, and self-teaching plus a mathematics degree leaves gaps that any serious international interview will find. So I closed them deliberately, with Sedgewick's Coursera course, CLRS, and a book on interview technique.

    The surprise was that the mathematics degree, which I had half filed away as unrelated, turned out to be the qualification that mattered. The role needed heavy numerical work and optimisation.

    A position opened a week after I was let go. I got the consulting job, and within a year I was a reference point for colleagues again.

    What it taught meI could name my weakness precisely, which made it a study plan instead of an anxiety. Vague self-doubt is unfixable; a named gap has a reading list.

  12. 201912

    Back to Java

    From 2012 onwards I worked mostly in C# and .NET on the backend. But most of the books I was reading used Java, most of the operational work I touched sat in a Java ecosystem, and the market I wanted was not especially interested in .NET even after .NET Core. My last real contact with the language had been around Java 6.

    There was also a plainer argument, and it is the one that actually moved me.

    I could not defend the claim I was making about myself.

    I was presenting as someone with judgement about software architecture while being a decade out of date on one of the two platforms I claimed to know. That is not a gap in a CV, it is a hole in an argument. So I closed it deliberately: certified on Java SE 11, then Spring properly. Hard study from mid-2019, comfortable and productive again by mid-2020.

    What it taught meChoosing what to learn is a technical decision, and it deserves the same honesty as any other. The question was not which language I preferred. It was which claim about myself I could still support under questioning.

  13. 202013

    The multiplier

    A high-throughput messaging system for a client in insurance, where a dropped or duplicated message is not a retry, it is a business event somebody has to explain. I owned the architecture and led delivery, and stayed close to the parts that decide whether a system like that holds: delivery semantics, queueing under load, serialization cost, the security model around it.

    What I remember is not the architecture. It is the week I realised I was spending most of my time in other people's problems rather than my own, and that this was not an interruption of the work but the work. I was attached to two teams as a technical multiplier. The distributed-systems bugs I helped chase were theirs. The practices we standardised for real-time systems were going to be used by people I would never meet.

    The system shipped. The teams outlasted it.

    What it taught meAt some point your output stops being code and becomes other people's capability, which is uncomfortable because it never shows up in a diff. I had to learn to count a week as productive when the only artefact was that two engineers could now debug something without me.

  14. 202114

    The other side of the desk

    Principal engineer first, setting technical direction on critical client work and helping shape how the company hired and trained. Then Director of Technology, which is a different job wearing a similar name: organisational priorities translated into technical programs, delivery, internal tools, engineer development, and pre-sales work for AI and cloud in North America.

    The story I am most pleased with from these years is not a system. An intern arrived from a non-traditional background and would not have passed a conventional screen. We built an actual path: regular milestones, a senior engineer alongside, work that got harder on purpose, checkpoints where we said plainly how it was going. Billable within six months, converted to full time, and now a senior engineer who mentors other people.

    I stayed in the room for the hard technical decisions, and I would not take a role that did not let me. But the decisions I could make by authority turned out to be the least interesting ones available.

    What it taught meAt this scope you are rarely choosing the answer. You are choosing which questions are cheap for other people to answer, which constraints they inherit, and what the default is when nobody is looking. That is leverage, and it is slower and less satisfying than being right in a meeting.

  15. 202215

    Forty keys

    In 2022 I started building my own keyboards, and I have not really stopped: a split keyboard configuration tuned for Portuguese, English, numbers and programming with Vim, then a layout of my own for people who write both languages, then firmware modules, then designing the hardware itself. Somewhere past two thousand commits.

    People assume it is a hobby that happens to be near my job. It is closer to the opposite. Firmware is the most honest environment I work in. There is no room for a vague abstraction in a devicetree file, the memory budget is measured in kilobytes, and a keypress either resolves correctly in single-digit milliseconds or you feel it in your hands immediately. Nothing about being senior helps.

    It is the smallest system I own end to end: hardware, firmware, host daemon, editor.

    It is also the only place I still get to hold an entire system in my head at once, which is a thing I was doing daily twenty years ago and now have to go looking for.

    What it taught meSeniority quietly removes you from the feedback loops that made you good. A constraint you chose yourself, with a physical consequence and no way to delegate it, is one of the few reliable ways to put yourself back in one.

  16. 202516

    Agentic engineering

    Since 2025, most of what I build personally is built with coding agents. That is a real change in how I work and I would rather be explicit about it than quietly impressive: Sandman is a tool for orchestrating them, and its implementation was itself largely agent-written. I am not presenting it as evidence of Go fluency. I am presenting it as evidence of what I think this practice needs.

    Which is the same thing any delivery process has always needed. A clear specification. An isolated place to execute, so a mistake is contained. An event log, so you can reconstruct what happened. Verification that does not depend on the thing being verified. A human review gate. Sandman pulls issues from GitHub, renders them through prompt templates, and runs each agent in its own worktree or container with dependency-aware scheduling, because those are the shapes those requirements take when you make them concrete.

    I built it before recommending any of this to an engineering organisation, on the principle that I would rather find a practice's sharp edges myself than watch a team find them on my advice.

    What it taught meAgents change the cost of producing code. They do not change the cost of being wrong. Everything downstream of that, boundaries, contracts, verification, knowing which part of a system you cannot afford to guess at, gets more valuable rather than less. Twenty-eight years in, that is the most reassuring thing I have learned recently.

That is the long version.

The short version has the systems, the decisions behind them, and the open-source work. The blog is where I am still working things out.

The short version