Rafael Romão Director of Technology · Belo Horizonte

Avenue Code · Belo Horizonte, Brazil

Director of Technology | Staff+ Technical Leadership | Software Architecture, Developer Platforms & Agentic Engineering

Systems that stay easy to change.

Twenty-four years of backend systems, and of the platforms and practices that keep them changeable. I work where implementation detail meets architecture: the data path, the failure mode, the delivery bottleneck. Then I move the boundary that caused it.

  • Professional since 2002
  • Distributed & event-driven systems
  • Agentic Engineering
  • Português, English

LinkedIn GitHub Email

The same history is written out in full in the career ledger below. Director Principal Architect / Senior Engineer Technician Delphi C# / .NET Java Agentic Engineering 2000 2005 2010 2015 2020 2025
Scope over time, and what the work was built on underneath it. The last row is not a language: since 2025 the build tool has been agentic engineering, across whichever language the problem called for. The gap in the Java row is real too, a J2EE course in 2003, then sixteen years of Delphi and C# before coming back to the platform deliberately in 2019.
I had been building microservices for a year before I learned the word.

In 2012 a CTO asked for a platform of small backend services exchanging results over a fast message bus. He had tried twice before without it landing. I built it because the monolith underneath kept tearing along the same seam, not because I had read that I should. The article that named the pattern came out the following year. I still prefer arriving in that order: from the bottleneck to the pattern, never the reverse.

01

Now

I am Director of Technology at Avenue Code, where I pair organizational leadership with hands-on technical work: architecture direction, engineering practices, delivery, and the development of engineers and technical leaders. I stay in the room for the decisions that are genuinely hard, the ones involving ambiguity, cross-team impact, modernization, scalability, or whether a system will still be maintainable in three years.

The thread through all of it is engineering leverage. Simplify systems and workflows. Draw architectural boundaries that hold. Shorten feedback loops. Give engineers what they need to decide well on their own.

Most recently I have been applying that to agentic engineering: how autonomous coding agents fit inside a disciplined delivery process through clear specifications, isolated execution, observability, verification, and human review. I build the tools to test the idea before recommending it to anyone, which is where Sandman came from.

The title on the org chart has changed several times. The work I care about has not: system boundaries, data paths, failure modes, and what a team can safely change next.

How I got here

A borrowed Delphi book in 1998, a page of phone numbers in 2002, a concurrency primitive I had no business writing in 2007, and an architecture that turned out to have a name. Sixteen chapters, including the ones that went badly.

Read the long version

02

Career

Nine roles, six companies, one continuous direction: from fixing office computers to setting technical direction across an engineering organization, without ever stopping writing software.

2016 – now

Avenue Code

Ten years. Four roles. A consultancy delivering software for clients in the United States and Brazil.

  1. Sep 2021 – now5 yrs 1 mo

    Director of Technology

    Avenue Code · Belo Horizonte, Brazil

    • Translate business and organizational priorities into technical strategy, architecture direction, and engineering initiatives that can actually be executed.
    • Provide technical guidance on cross-cutting work where system boundaries, modernization, scalability, reliability or long-term maintainability are the central concern.
    • Support engineering leaders and senior engineers through architecture decisions, problem decomposition, trade-offs, and high-impact delivery risk.
    • Establish and evolve the engineering practices that govern quality, feedback speed, developer experience and consistency across teams.
    • Mentor engineers and technical leaders toward wider system-design skill, decision-making autonomy, and organizational influence.
    • Introduce AI-assisted and agentic engineering practices with the specifications, isolation, verification, observability and human review they require, building prototypes and open-source tools to validate the approach before promoting it.
  2. Nov 2020 – Aug 202110 mos

    Principal Software Engineer

    Avenue Code

    Set the technical vision for critical client projects and drove the architectural decisions behind scalable, high-performance systems. Mentored cross-functional teams through hard technical problems and raised the floor on coding standards and process.

    Worked on the company's engineering capability itself: shaping hiring strategy, strengthening technical training, and joining pre-sales to translate business needs into architecture that would survive contact with delivery.

  3. Nov 2019 – Oct 20201 yr

    Consultant Software Engineer

    Avenue Code

    Architected and led delivery of a high-throughput, mission-critical messaging system for a client in the insurance industry, under tight security and reliability constraints. Acted as a technical multiplier for two engineering teams, resolving distributed-systems problems, optimizing message queueing and data serialization, and mentoring developers on code quality.

    Helped standardize internal practice for real-time systems, refine the technical interview process, and evolve the training curriculum.

  4. Oct 2016 – Oct 20193 yrs 1 mo

    Senior Software Engineer

    Avenue Code · Belo Horizonte, Brazil

    Drove continuous development of a business-critical mathematical planning application for a large retail client, contributing across the whole lifecycle from feature design through performance tuning and deployment.

    Engineered the performance and memory optimizations that kept a computationally intensive system stable under heavy load. Led a self-managed team of up to eight senior developers.

1997 – 2016

Before

Product engineering and architecture across messaging, utilities, and laboratory software.

  1. Nov 2015 – Sep 201611 mos

    Senior System Analyst

    Take.net

    Built and extended high-volume messaging for telecom applications as part of the core platforms team. Contributed to a proprietary chatbot platform built on the Lime protocol, which let bots be deployed rapidly across Facebook, Telegram, Skype and SMS gateways, and shipped content-driven bots that improved partner content delivery.

  2. Sep 2011 – Oct 20154 yrs 2 mos

    Senior Software Analyst

    Concert Technologies · Belo Horizonte, Brazil

    Specialized in smart grid management software, working the full lifecycle from requirements through architectural maintenance. Led the analysis and refinement of system requirements, keeping user need and technical implementation aligned, and played a central role in implementing and maintaining the architectures underneath.

    This is where Reactive Services began in 2012: a message-bus abstraction for building what the industry would shortly start calling microservices.

  3. Sep 2009 – Aug 20112 yrs

    Software Architect

    Factor SW

    Designed and maintained the architecture for client-facing products, holding it against both functional and non-functional requirements. Guided teams toward clean code and maintainable design, documented architectural decisions, ran code reviews, and set technical roadmaps for long-term product evolution.

    Partnered with development teams in the United States and the Caribbean on blood bank management software, where regulatory compliance was part of the design problem.

  4. May 2002 – Aug 20097 yrs 4 mos

    Software Developer

    CATI Informática

    Seven years of maintenance and new development on the company's core products, moving from developer to leading development teams. Pioneered the formal adoption of software architecture as a concept inside the company, which measurably improved quality, scalability and maintainability.

    Collaborated with teams in Switzerland and France on specialized laboratory software, including the instrument automation work that first pushed me into concurrency.

  5. Feb 1997 – Mar 20025 yrs 2 mos

    Computer Technician

    DIMAC · Belo Horizonte, Brazil

    My first job. I started as a storekeeper's assistant and became the technician responsible for the office's software and hardware. Then I taught myself Delphi from a book and started writing small programs to automate the work, which went well enough that in 2002 I left to write software full time.

03

Systems

Client work is described at the level of the engineering problem. No customer names, no proprietary detail, no numbers I cannot stand behind. Where the decision is the interesting part, I have written down what I rejected and what it cost, not only what I chose.

  1. 2019 – 2020

    Mission-critical insurance messaging

    A high-throughput messaging backbone where a dropped or duplicated message was a business event, not a retry. I owned the architecture and led delivery, then stayed close to the parts that decide whether a system like this holds: delivery semantics, queueing behaviour under load, serialization cost, and the security model around it.

    The lasting output was not only the system. It was two engineering teams that could debug distributed behaviour on their own afterwards, and a set of practices for real-time systems that outlived the engagement.

    • Distributed messaging
    • Idempotency
    • Serialization
    • Queue tuning
  2. 2016 – 2019

    Retail production planner

    A planning application with a spreadsheet-like interface over a large mathematical model, held to an interactive editing budget measured in milliseconds. Meeting it meant treating the calculation as a data-layout problem rather than a code-optimization problem: an in-memory, array-oriented model, results precomputed and versioned in object storage, and careful choices about what to invalidate and when.

    Three years hands-on, including the deployment path and the build pipeline, leading a self-managed team of up to eight senior engineers.

    Constraint
    An edit had to feel instant over a large mathematical model, against a budget measured in milliseconds.
    Rejected
    Making the existing calculation faster where it stood. At that budget the thing that mattered was how data was laid out and reused, not how tight the arithmetic was.
    Chose
    An in-memory, array-oriented model, results precomputed and versioned as Protocol Buffers in object storage, and an explicit rule for which version a read sees.
    Traded
    Memory, and a rebuild cost every time the shape of the model changed.
    Today
    I would settle the invalidation rules before the data model rather than after. That is the part we kept coming back to.
    • C#
    • In-memory modelling
    • Protocol Buffers
    • Blue-green deploys
    • Performance
  3. 2011 – 2015

    Smart grid platform and Reactive Services

    Management software for electric utilities, and the research that came out of it. Working across the lifecycle of a long-lived product made the coupling costs obvious, so in 2012 I built Reactive Services: a message-bus abstraction with a RabbitMQ adapter, an authorization model, and opinions about service boundaries and message contracts.

    Martin Fowler's microservices article landed the following year and gave the pattern its name. Getting there independently, from the pain rather than from the literature, is still how I prefer to arrive at an architecture.

    Constraint
    A platform of individual backend applications, each doing one job, exchanging results over a fast bus. Two earlier attempts inside the company had not landed.
    Rejected
    Letting the services share a database. It would have made them one deployable again wearing several names, which is how the earlier attempts had collapsed.
    Chose
    Messages as the only contract between services, over a bus abstraction with a RabbitMQ adapter and an authorization model, with boundaries a single team could hold in its head.
    Traded
    Local simplicity. Every former method call became a message that can arrive late, twice, or never, and each one had to be designed for that.
    Today
    The boundaries held up better than the framework I wrapped around them. I would write fewer abstractions and more contracts.
    • Message bus
    • RabbitMQ
    • Service boundaries
    • .NET
  4. 2015 – 2016

    Chatbot platform on the Lime protocol

    High-volume telecom messaging, and a platform that made one bot deployable across Facebook, Telegram, Skype and SMS gateways without rewriting it per channel. The interesting constraint was the abstraction itself: channels differ in delivery guarantees, in message shape, and in what they let you say.

    • Lime protocol
    • Multi-channel
    • Telecom scale
  5. 2002 – 2011

    Laboratory automation and blood bank systems

    Nine years of regulated, safety-relevant software built with teams in Switzerland, France, the United States and the Caribbean. Instrument automation is where I learned concurrency properly.

    Constraint
    Drive a set of motors in parallel from a simple desktop interface, on C# 2.0, three years before the Task Parallel Library existed.
    Rejected
    A thread per operation at every call site. Everyone on the team could write one; at the number we needed it would have been tedious and easy to get subtly wrong.
    Chose
    A small Task class that ran one operation on a background thread and could be composed, so the concurrency lived in one place instead of scattered through the code.
    Traded
    We now owned a concurrency primitive, and every bug in it was ours.
    Today
    .NET shipped the same idea in 2010 and did it better. Being three years early cost us maintenance, and taught me more about threads than any library would have.
    • Delphi
    • C#
    • Concurrency
    • Regulated software
    • Distributed teams

04

Method

How I approach a problem I have not seen before. Written down because saying it out loud is how a team can hold me to it.

  1. Start simple. Correctness first.

    Describe the simplest thing that is actually correct before discussing anything faster. It is the baseline every later argument is measured against, and often it is enough.

  2. Make assumptions explicit.

    Most architectural disagreements are two people reasoning correctly from different unstated premises. Say the premise and the disagreement usually resolves itself.

  3. Think in invariants.

    Name the property that must hold no matter what happens: what is unique, what is ordered, what is idempotent, what is allowed to be stale. Designs are easier to check against an invariant than against a diagram.

  4. Find the bottleneck before reaching for a pattern.

    Trace a small example, state the simple approach, identify what actually limits it, and only then choose the technique that removes that limit. A pattern applied before the bottleneck is known is decoration.

  5. Sophistication is not complexity.

    The sophisticated solution is usually the one with fewer moving parts and clearer boundaries. Complexity that impresses in review is complexity somebody pages at 3am.

  6. Elevate only after solving.

    Solve the system problem first. Then ask whether it is really a platform problem, and then whether it is really an organizational one. Skipping straight to the org answer is how architecture astronauts are made.

  7. The stated problem is the problem.

    Challenge an assumption only once I can name the evidence and its impact. Reframing a brief because it is more interesting my way is a failure mode, not seniority.

05

Open source

Side projects, all of them. They are where I test ideas at full scale before I recommend them to anyone, and where I get to work under constraints my day job does not provide.

Sandman

Sleep while your agents code.

An orchestrator for autonomous coding agents. It pulls issues from GitHub, renders them through prompt templates, and runs each agent inside an isolated sandbox, a git worktree or a container, with dependency-aware parallel scheduling and a local portal for watching the runs.

It exists because agentic engineering needs the same things any delivery process needs: a clear specification, an isolated execution boundary, an event log, verification, and a human review gate. Sandman is the argument made concrete. Released at v1.0.0 with a changelog, a security policy and a release pipeline, because a tool that asks you to trust it with your repository should look like it can be trusted.

zmk-vim-mode

A side channel that was already there.

The keyboard should be in NORMAL when the editor is in normal mode. That needs the host to tell the keyboard something, and there is no standard channel for it: HID runs keyboard to host. Custom firmware protocols exist, but they mean pairing, a transport of your own, and a different answer for USB than for Bluetooth.

There is one exception. The output report is a single byte the host sends to the keyboard, to light the Caps Lock and Num Lock lamps. It works identically over USB and Bluetooth, needs no pairing, and stock ZMK already accepts it. Of its five indicator bits, three are dead: no operating system sets Compose, Kana or Scroll Lock on its own. Read together they are a 3-bit number, which is eight states, which is more than Vim has modes.

The mechanism is described in full in the paragraphs above and below this diagram. Host HID output report · one byte, host to keyboard Keyboard Neovim plugin reports the real mode Go daemon writes the byte editor state 0x01 0x02 0x04 0x08 0x10 Num Caps Scroll Compose Kana the OS owns these left alone on purpose no OS ever sets these read as one 3-bit number, 8 states USB or BLE ZMK module tests three bits layer set a bitmask change Pressing i in Neovim code 2 → Kana bit set → byte 0x10 → VIM_INSERT
The lamps never light: without an indicator-LED node in the keymap, nothing physically turns on. It is a silent channel that happens to travel on the LED wire.

The part I find more interesting than the trick is what it takes to make it survive real typing. The keyboard keeps its own local inference and the host only corrects it, which means a host message always describes the editor as of an earlier keystroke. Two rules reconcile them: a 60 ms hold-off before believing a zero, because the kernel zeroes the whole byte whenever it sends its own lamp update, and a 150 ms guard after any keyboard-driven change, so a stale in-flight message cannot undo a correct local one. The keyboard wins in motion, the host wins at rest.

06

Writing

  1. Whitepaper

    Microservices Architecture as a Large-Scale Refactoring Tool

    Treating a migration to microservices as a refactoring problem rather than a rewrite, and what that changes about sequencing and risk.

  2. Medium

    How to pass the OCP Java SE 11 certification

    The study method behind a deliberate mid-career platform switch, written down while it was still fresh.

  3. Paper · pt

    Melhorando a eficiência no desenvolvimento de software através da aplicação de técnicas de Especificação por Exemplo

    Specification by example as a way to shorten the loop between what was asked for and what was built.

  4. Paper · pt

    Um Estudo Comparativo das Linguagens Java e C#

    A comparative study of the two languages I would go on to spend most of my career alternating between.

07

Credentials

Education

  • Big Data SpecializationUniversity of California, San Diego · 2016 – 2017
  • Strategies in Software ArchitectureIGTI · 2012 – 2013
  • System AnalysisUniversidade Federal de Minas Gerais · 2007 – 2008
  • Licentiate degree, MathematicsUniversidade Federal de Minas Gerais · 2003 – 2007

Certifications