[{"data":1,"prerenderedAt":76},["ShallowReactive",2],{"profile-en":3,"articles-en-{}":27},{"brandName":4,"fullName":5,"headline":6,"manifesto":7,"contactIntro":11,"avatar":12,"manifestoImage":13,"social":14},"Danilo Fernando","Danilo Fernando - Senior Software Engineer","Well-built software, reliable integrations, and architecture designed to last.",[8,9,10],"My journey is guided by the belief that code is just a tool to solve complex business problems. With solid experience in the Java and Spring ecosystems, I focus on systems that work AND are easy to maintain and evolve.","Specialised in robust APIs and critical integrations, I believe technical maturity shows up in balanced decisions that weigh innovation against real business needs.","I chase real impact: Clean Code is not aesthetics, it is an economic necessity for long-term product sustainability.","I'm always open to new professional opportunities, technical exchange, or conversations about architecture and software engineering.","\u002Fimages\u002Fprofile\u002Fdanilo.webp","\u002Fimages\u002Fprofile\u002Fdanilo_manifesto.webp",[15,19,23],{"kind":16,"label":17,"href":18},"email","Email","mailto:danilo.bossanova@hotmail.com",{"kind":20,"label":21,"href":22},"linkedin","LinkedIn","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fdanilo-fernando-dev\u002F",{"kind":24,"label":25,"href":26},"github","GitHub","https:\u002F\u002Fgithub.com\u002Fdanilobossanova",[28,41,52,64],{"slug":29,"title":30,"excerpt":31,"category":32,"tags":33,"readTimeMinutes":37,"publishedAt":38,"author":4,"coverImage":39,"body":40},"outbox-pattern-na-pratica","Outbox pattern in practice with Spring Boot","How to guarantee at-least-once delivery without distributed transactions.","Architecture",[34,35,36],"events","spring-boot","kafka",9,"2025-03-01","https:\u002F\u002Fpicsum.photos\u002Fseed\u002Foutbox\u002F1200\u002F600","## The problem\n\nReliably publishing events next to a database transaction is one of the classic\npitfalls in distributed systems. If you write to Postgres and then publish to\nKafka:\n\n```java\n@Transactional\npublic void confirm(Order order) {\n    orderRepository.save(order);       \u002F\u002F ✅ inside DB transaction\n    kafkaTemplate.send(\"orders\", order); \u002F\u002F ❌ outside the transaction\n}\n```\n\nA crash between the two calls is enough for the DB to say *\"confirmed\"* while\nthe rest of the world never hears about it.\n\n## Outbox pattern\n\nThe idea is to write the event in the **same transaction**, in an `outbox`\ntable. A relay reads the table and actually publishes it.\n\n### Minimal schema\n\n```sql\nCREATE TABLE outbox (\n    id           UUID PRIMARY KEY,\n    aggregate    VARCHAR(64)  NOT NULL,\n    event_type   VARCHAR(128) NOT NULL,\n    payload      JSONB        NOT NULL,\n    created_at   TIMESTAMPTZ  NOT NULL DEFAULT now(),\n    published_at TIMESTAMPTZ\n);\nCREATE INDEX outbox_unpublished_idx\n    ON outbox (created_at) WHERE published_at IS NULL;\n```\n\n### Relay\n\nA simple job reads unpublished events, ships them to the broker and marks them\nas published. What matters:\n\n1. **Consumer idempotency** — the relay will republish on failure.\n2. **Lag monitoring** — alert if `outbox` grows faster than it drains.\n3. **Controlled batches** — don't lock the DB pulling 10k rows at a time.\n\n### Gotchas\n\n- Never rely on strict broker ordering; partition by `aggregate_id`.\n- Don't dead-letter into the same table — create `outbox_failed`.\n- Always record the payload schema version.\n\n## When to avoid\n\nIf your system doesn't need at-least-once guarantees, outbox is overkill.\nSpring's `@TransactionalEventListener` covers 80% of cases.",{"slug":42,"title":43,"excerpt":44,"category":32,"tags":45,"readTimeMinutes":48,"publishedAt":49,"author":4,"coverImage":50,"body":51},"custo-real-da-complexidade","The real cost of unnecessary complexity","Why over-engineering is often the fastest path to project failure.",[46,47],"clean-architecture","technical-decisions",5,"2025-02-10","https:\u002F\u002Fpicsum.photos\u002Fseed\u002Fcomplexity\u002F1200\u002F600","## Complexity on compound interest\n\nComplexity is the biggest cause of technical bankruptcy I've seen up close.\nEvery \"just in case\" abstraction is an implicit contract with the future —\nand the future always cashes in.\n\n> \"The only thing more expensive than solving the wrong problem is solving\n> the right one with three layers of indirection nobody asked for.\"\n\n### Warning signs\n\n- Abstractions that exist for a single use case.\n- In-house frameworks for problems the ecosystem already solves.\n- \"Let's make it pluggable\" **before** two plugs exist.\n- Dynamic config for something that changes once a year.\n- Mapping layers between identical objects.\n\n### Practical heuristic\n\nBefore creating an abstraction, ask:\n\n1. Are there **two** real consumers today?\n2. Is the cost of extracting later prohibitive?\n3. Does the behaviour actually vary, or just the name?\n\nIf the answer is \"no\" to all three, **inline is the right answer**.\n\n### A concrete example\n\n```java\n\u002F\u002F Before — flexibility nobody asked for\npublic interface UserNotifier {\n    void notify(User user, NotificationPayload payload);\n}\npublic class EmailUserNotifier implements UserNotifier { \u002F* ... *\u002F }\n\n\u002F\u002F After — the system only sends email, period\npublic class EmailService {\n    public void sendWelcome(User user) { \u002F* ... *\u002F }\n}\n```\n\nWhen the second channel appears, you extract the interface in **five minutes**,\ngreen tests and a clear head about what actually changes.\n\n### Summary\n\nStart from real pain, not theoretical elegance. Clean Code is about\n**maintenance cost**, not interfaces per megabyte.",{"slug":53,"title":54,"excerpt":55,"category":56,"tags":57,"readTimeMinutes":60,"publishedAt":61,"author":4,"coverImage":62,"body":63},"testes-integracao-que-nao-mentem","Integration tests that don't lie","TestContainers strategies to keep CI\u002FCD fast without losing confidence in your code.","Spring Boot",[58,35,59],"testing","testcontainers",8,"2025-01-18","https:\u002F\u002Fpicsum.photos\u002Fseed\u002Ftests\u002F1200\u002F600","## Green suites, fragile code\n\nA green suite without confidence is worse than no suite — it gives you license\nto ship while the system burns.\n\n### The pattern that works\n\n1. **TestContainers** for real dependencies (Postgres, Kafka, Redis).\n2. **Deterministic fixtures** — no `@Sql` + random.\n3. **One seed per test**, no shared state.\n4. **Assert on data**, not on mock invocation counts.\n\n```java\n@Testcontainers\n@SpringBootTest\nclass OrderConfirmationIT {\n    @Container\n    static PostgreSQLContainer\u003C?> db = new PostgreSQLContainer\u003C>(\"postgres:16\")\n        .withInitScript(\"db\u002Finit.sql\");\n\n    @DynamicPropertySource\n    static void props(DynamicPropertyRegistry reg) {\n        reg.add(\"spring.datasource.url\", db::getJdbcUrl);\n    }\n}\n```\n\n### What that buys\n\n- Tests that **turn green with the code**, not after.\n- Fearless refactors.\n- Objective conversations at code review.",{"slug":65,"title":66,"excerpt":67,"category":68,"tags":69,"readTimeMinutes":72,"publishedAt":73,"author":4,"coverImage":74,"body":75},"decisoes-tecnicas-peso-do-legado","Technical decisions and the weight of legacy","Being senior is less about \"how to code\" and more about \"when not to code\".","Career",[70,71],"career","tech-leadership",6,"2024-12-05","https:\u002F\u002Fpicsum.photos\u002Fseed\u002Fcareer\u002F1200\u002F600","## Seniority is context\n\nThe job shifts from *\"solving the right problem\"* to *\"picking which problem\nto solve\"*. That requires little about how to code and a lot about **knowing\nhow to say no**.\n\n### The weight of legacy\n\nLegacy code is the cost you **didn't pay** when the system was born. Every\nshortcut from the past became high-interest debt. The senior's job isn't to\nrewrite everything — it's to pick *which piece* of debt is worth paying off\nthis quarter.\n\n### The map I use\n\n- **High pain + high risk** → surgical refactor with new tests.\n- **High pain + low risk** → replace and move on.\n- **Low pain + high risk** → monitor and document the danger.\n- **Low pain + low risk** → **leave it alone**.",1776457051446]