Where do I come from?

My origin story as a software programmer is pretty common in this industry. I wrote my first lines of code when I was probably 7 or 8 years old, and my first full software application at the ripe age of 16. I remember it fondly. It was a musical notepad to write down melody ideas I had at random times on the most basic computer I had access to at the time. It was all written in one huge Pascal file, it was messy, it was inefficient, it was crafty and I was so proud of the clever solutions I had found to show a pseudo graphical user interface on a text-only screen or produce sounds even without a soundcard, just with the motherboard’s system beep speaker. It was crude, I was the only user ever, but it was an amazingly satisfying experience. The next year, I took advantage of new computer science classes and better software tools to rewrite Note Pad Score as a real mouse-based MIDI-sounding application. And the rest is history… I had fallen in love with puzzles, problem solving, micro-creativity, user interface design, struggling for hours before feeling the rush of dopamine when a semi-colon finally found its right place. I went on to study computer science and made it my career. For 5 years I worked in a consulting firm before I finally felt ready to fly on my own and went freelance.

Over the years, I have managed to make a career for myself, and to build my skillset in such a way that I could handle all the aspects of a software project, from team management, to functional and technical analysis, to architecture, to design, development and deployment management. And when it came to actually building software, I learned to build both backends and frontends, whether they were desktop, web or mobile. This expertise became particularly powerful when I decided to go full location-independent back in 2018, because it allowed me to work with startups and small companies, managing the full software lifecycle from anywhere in the world, with minimal need for meetings that would have restricted my exploration of the world. I was usually working on 2 or 3 projects at a time, helping creative entrepreneurs turn their ideas into reality, and I loved everything about it.

Then 2 years ago, everything came crashing down. Where I had been able to find new projects and clients pretty easily through word-of-mouth and thanks to my reputation, leads suddenly dried up. Some of my usual clients started vibe coding their own prototypes, budgets ran out as people started believing that my job could easily be done by a mere chatbot. Negotiation became harder, and I even lost some clients after working with them for a few months because they got duped by the sirens of vibe coding.

Then started a long period of grief.

At first I was in denial, I kept looking for projects the way I had always done it, reaching out to business managers and consulting companies, hoping to find someone that the AI infection hadn’t reached yet.

Then came anger when I realized that none of those who rejected my expertise in favor of LLMs understood what I offered, that it was so much more than just writing code. Obviously they couldn’t see they were heading straight for the wall, because everything seemed to work until they had real users, with real private data, and they needed to make real changes.

After that, I figured out I was swimming upstream, battling greed and mediocrity. The market didn’t care about clean, secure, scalable and evolutive software anymore, not enough anyway to value it like they used to. So I started negotiating my rates down, working a few days per month on each project instead of a few weeks, showing my clients that we could do so much more with the same budget, and trying to use AI where it seemed to make sense, while keeping a strong grip on places where it seemed to lack smarts.

But I was unhappy, because it changed everything about the work I used to love so much, it robbed me of all the little puzzles that made my days, it made me feel guilty for not being the author of every line of code I was delivering, it made me read thousands of lines of code I had not even written. And more importantly it felt like all this time I had spent honing my craft, building my skills, developing my intuition and my design thinking, had been for nothing.

The wake up call

Then in early 2026, 3 things, 3 events kind of collided.

For starters I had an epiphany: I realized that this had happened before, even if at a smaller scale. In the seventies and eighties, when programmers went from writing machine code to using compilers and higher-level languages, a lot of them regretted the time when they could fine tune memory usage and optimize every instruction sent to computers. But they had to realize that most compilers did a much better job than they ever could, and it enabled programmers to focus on higher-level abstractions to solve bigger problems. And here I was, facing the same kind of quantum leap in technology, refusing to adopt tools that would allow me to build truly useful software, which had always been my ultimate purpose anyway.

Then, new models started coming out, along with new workflows like Ralph loops, that finally made it possible to build some real features, end to end, with proper expert guidance. Special kudos to David Nguyen, opens in a new tab for pointing me in that direction and showing me how he worked.

And finally, there was this side project I had been dreaming about for years already, that became so much more feasible by using LLMs, not only as a development tool, but also as an internal component to make sense of complex non-structured documents.

And since in the past, I had always used side projects to learn new technologies and add new skills to my toolkit, I decided to try to embrace LLMs on my own project, to experiment with these new techniques without risking a client’s entire business on it.

5 months later, I released the first version of Skaoot, opens in a new tab, my travel assistant for digital nomads, with a feature set, a level of sophistication and quality it would have taken me years to reach if I had written all of the code myself. And now here I am, 7 months after the start of this experiment, the second version released and more confident than ever in the tools I managed to tame and curate, still a bit sad about some of the creative satisfaction I’ve lost, but excited about the new possibilities ahead of me.

So I thought I would share some of the things I’ve learned through this transition, hoping it might help other senior software engineers like myself go through it, as well as all the stakeholders who (still) depend on us.

Building trust takes time

And changing your perception regarding what the AI can and cannot do cannot be forced, only experienced.

I hear about a lot of companies where management’s only AI adoption strategy sounds something like « Here are some tokens, go ahead and use these, and keep an eye on the token usage leaderboard ». The problem is that those LLM models have a very low barrier to entry through their chatbot interaction model, which leaves a lot of people wondering how you can go from asking ChatGPT about the gestation period of an orangutan to driving Claude Code to build an entire feature, especially when they have already seen some AI being confidently wrong about the gestation period question.

And this trust issue is even more present in technical experts like software engineers who have spent years if not decades honing their craft, and have all the stories from the trenches to back that up.

At the very beginning, like a lot of developers, I used AI mostly as a more powerful code completion engine, aka tab-based development: you start typing code, and you watch in amazement how your development environment uses its AI to guess what you were trying to do, and offers you to press the Tab key to accept the guess. And the guess is sometimes so good that it’s all you need to do to generate hundreds of lines of code. Until you realize that it made the wrong guess, that an error slipped into the generated code, and it takes you almost as much time to fix the mistake and reroute the guesser than if you had written the code manually in the first place. And when that happens, your trust erodes.

Another typical situation is when you ask the LLM to create a specific piece of code, or generate a narrowly scoped test script, and the AI doesn’t have the proper context, makes a bunch of assumptions without asking you for clarifications, and generates thousands of lines of code. And since your unspoken assumptions seem obvious enough to you, you don’t necessarily check what was generated, and you just add some technical debt into your code, that you end up having to pay back further down the line because of the assumption mismatch.

All those mistakes, along with the expert’s confirmation bias, create a situation where the developer doesn’t trust the model, and as a consequence stops using it altogether, continues using it in the wrong way because they didn’t have a chance to learn what exactly went wrong, or simply refuses to give the model more advanced tasks, since it already failed on such small things.

The answer to these issues is progressive workflows: instead of force-feeding your AI with every problem in the same way, you need to experiment with bigger and bigger tasks the techniques you need to implement at each level to leverage the full power of your model while minimizing mistakes and inefficiencies.

For boilerplate code generation, you learn to point your AI at example files where similar code already exists, and you learn to manage your master context file to keep track of your coding habits and conventions.

For tests, you learn to use a Test-Driven Development skill to make sure all the edge cases are covered.

For bigger feature development, you integrate a workflow framework that creates a loop that analyzes the requirements, generates a specification, criticizes that specification adversarially, turns the specification into an action plan and lets you review the deliverables after each of those steps before moving on to implementation.

But you learn that progressively, through experimentation, within a low-stake project with a minimal scope before applying those learnings to a real project. In fact, integrating an AI model into your software team is akin to onboarding a new junior developer. The existing team needs time to trust the new recruit, and to reposition their own work around the integration of this new team member. This doesn’t happen overnight. It took me a month or two.

Vibe coding can only get you so far

Vibe coding refers to the practice of generating code for apps or websites without ever seeing that code or understanding it really, through a loop of trials and errors with visual feedback. Spiritually, it is an extension of what already existed before AI as no-code. And essentially it promises people who have no notion of software engineering or coding to generate entire apps and websites without any assistance, just by prompting ChatGPT or Claude or Lovable or any other AI.

The main problem is that most vibe coding tools and practices are aimed at people who precisely don’t understand how software is built, and who often assume it’s mostly about translating raw ideas into gibberish code, as if software developers were only interpreters. And nothing could be further from the truth. Even when I was still writing code by hand, writing code represented at most 20% of my work, the rest being spent on:

  • Integrating external libraries and packages and reading their documentation so that I don’t have to reinvent the wheel for generic needs. Which also implied testing several competing libraries for the same things to make sure I use the best one for the job, taking into account all the constraints. And then maintaining those third-party dependencies, watching for bugs and technical upgrades, and dealing with domino effects when dependencies have compatibility issues with one another.
  • Designing code components for security, making sure nobody can access data they are not supposed to, trying to anticipate common and less common attack surfaces that would allow hackers to get in and steal users’ personal information, and staying compliant with privacy regulations like GDPR and so on.
  • Architecting systems to adapt to the specific constraints of the app I’m building: do users need to access their data offline? what kind of channels do they need to access it on (web, mobile, etc.) and so on
  • Optimizing code for scalability, because there are many ways to load and modify data, and a lot of them can work well when you are testing with one user with a small amount of data, but can become a disaster when you reach production. And loading time can have a huge influence over your business, it can crash systems, frustrate users and even make your app completely unusable.
  • Like I said in my story at the beginning, my very first application was made up of one long multi-thousand line file with everything entangled in the same place. Technically, it worked, but changing anything to it, adding features, fixing bugs, testing things would have been a nightmare. Designing code to be able to evolve, improve and be tested is more of an art than a science, it’s a craft that comes from years of experience, knowing best practices and a general intuition that’s often not even conscious.
  • Filling the gaps. Very often, when you think of a feature, you think of the ideal scenario, when everything goes right and the user does what he is expected to. But apps usually interact with a whole ecosystem of third party connections, changing connectivity, complex hardware where your code has to deal with those changing constraints gracefully, without crashing, without confusing the users, finding workarounds and so on. And of course, the biggest variable of all is the end user: they tend to do things you don’t expect them to. They forget to fill in a required field in a form, they click a button several times in a row because they get impatient, they do things out of order. And as a developer it is your job to anticipate all of these variables, make the unsaid explicit, deal with all the edge cases, ask questions about which fields are required or not, what their data type is, which timezone is the data supposed to be presented in and so on.
  • Improving user experience: don’t you get annoyed when yet another app asks you for your first name and you have to type it in full instead of clicking a suggestion, or when the keyboard in a mobile app doesn’t adapt to the fact you have to input an email address, with the @ sign directly available and so on? There can be a huge difference between a working implementation and one that integrates all those micro user experience improvements that minimize clicks and work for the user.

Sometimes I got some help from business analysts, functional analysts, technical analysts, designers, QA testers, but in any case, it is thinking work that needed to be done.

Modern AI models are becoming better at thinking about these things, but often you need to add context, integrate skills, point the model at knowledge sources and keep all of this up-to-date over time.

And then there is all the satellite work that often gets overlooked if you don’t even know it exists, like for example:

  • Version control: how do you keep track of the history of changes made to the app’s code so that you can easily revert something, or replicate a solution instead of rebuilding it from scratch? That’s where it becomes crucial to track the history of the code, even if it’s generated by AI, because both developers and machines often need to recall the memory of what happened to your project.
  • Integration: what happens when a third party system needs to integrate with yours, when you need to send or receive data to another system through secure connection points? You need to document that, not just implement it, otherwise it will be almost impossible for external collaborators, whether they are human or AI, to integrate with your system
  • Troubleshooting: when a problem happens, you want your system to give you information about what went wrong where, to help you resolve the issue as quickly as possible so as not to disrupt your business at the worst possible time. That usually requires some instrumentation, logging issues, tracking and recording what users do in real time, and then having tools to troubleshoot issues quickly.
  • Release management: if you are building a mobile app for example, it needs to be released to an app store, and then users have the choice to update your app or not, while you keep releasing features to the server (aka backend) that the app connects to. So what happens when an old version of your mobile app (frontend) connects to your shiny new backend? Will it crash? Will it handle changes gracefully? Will it corrupt your data? Those are things you need to factor in constantly when you code. And of course, you also need to handle the future and prepare for it. The very first version of Skaoot only processed flight and accommodation bookings, but when I released it, I already knew that soon I would need to handle train bookings, vehicle rentals and more types of bookings. Sometimes these changes require code changes, sometimes they are just configuration parameters you can handle without releasing a new version. And knowing where these changes are implemented is also part of the work.

And those are just some examples of things you don’t necessarily think about when you ask Lovable to let users log in to your website with their email address and a password.

Vibe coding can be sufficient for simple generic use cases like generating an entire landing page for a new business with a contact form. It can be enough to generate a single-use throw-away prototype with you and your cofounder as the sole users.

But you don’t have to believe the old biased interested developer that I am to read all the horror stories, opens in a new tab of people who vibe coded, opens in a new tab entire systems into production (when they even got there) and all the security, performance, reliability, opens in a new tab, evolutivity and other issues they faced.

Now if you can generate some things super quickly without knowing anything about code, can you even imagine what an experienced developer can do when embracing an AI to do all the time-consuming work and leverage all of their expertise to avoid most of the pitfalls and drive the AI in the proper direction?

It’s as if you never learned how to fly a plane, and now you got your private pilot license so you know how to fly a small single-engine Cessna. Are you really sure you would be able to land an Airbus A350 in one piece?

Context management is paramount

When you delegate software development to an AI, you don’t just pass the baton on writing code, but also on remembering the context that code fits into. All the mistakes that have been made before, all the good ideas we should replicate, all the changes we have made over time and the reasoning behind them, all the business knowledge that served as a basis to all those decisions.

Typically, that knowledge lives in developers’ heads, outdated documentation or code comments and of course existing code and code history. And when a developer starts a task, they have to selectively load some of that context into their own memory and work from there. It’s imperfect, it’s messy, it’s limited in time, it has holes, it is usually fragmented over several people in the team, but it’s an important part of the work of any software developer because it keeps the software consistent over time.

If you want proof of that, just look at the disaster created when high-turnover teams develop a piece of software: solutions are short-sighted, code is duplicated and unmaintainable, fixing bugs feels like playing wack-a-mole, features are inconsistent.

Coding LLMs usually operate on several layers of context:

  • A short term memory context, usually about a million tokens or so, that can be reset at any time, per session
  • A project context (CLAUDE.md, AGENTS.md, etc) that documents the general architecture of a project, which folders contain what, as well as the general best practices we want to follow in the project
  • A longer term memory system made up of text files stored in the LLMs configuration file system or in a code wiki like Obsidian for example
  • Some kind of history of specifications, plans and other task-specific documents describing past implementations in the project (or even sometimes across several projects)
  • Some skills that document how to do some repetitive tasks like how to perform a code review or generate a certain data fixture for example
  • Selective and secured access to your own infrastructure, the logs of your server, the remote logs of your frontend, your database, your files, etc.
  • And of course most LLMs have access to the internet, where they can fetch the documentation of the tools and libraries you are using in your code, among other useful information

What I have learnt over time is that, in order to improve outcomes, you have to be very diligent about managing all those different kinds of context. If you do nothing about them, that is what leads to bugs, inconsistencies, maintainability issues and just a whole lot of technical debt.

AI-friendly architecture

Software architecture is already important when you are coding manually. There are a lot of engineering principles that you have to apply to keep your code testable, easy to maintain, easy to evolve, easy to troubleshoot. The software engineering world is full of acronyms like SOC (Separation of Concerns), YAGNI (You Ain’t Gonna Need It), KISS (Keep It Simple, Stupid), DRY (Don’t Repeat Yourself) and other architecture styles like microservices, MVC (Model-View-Controller), MVVM (Model-View-View Model) and other design patterns that developers learn to apply very early to keep things clean and sustainable.

Some of these principles are pretty universal and clear cut, others are a matter of project context, or even personal preference. And the way they are implemented also varies widely from one technology to another.

So if you don’t know about these things, it’s easy to overlook in an AI generation context and have your LLM go crazy with architecture and code design. But why would you care after all, if the outcome is a working app?

The truth of the matter is that those principles came out of necessity for human development, and are even more crucial in an AI-driven environment.

If you have a standard way to organize every feature, it’s easier for your LLM to figure out where things are and where to insert new code. It’s easier for it to generate proper tests to minimize regression over time (aka the wack-a-mole effect). The working context is less complex, which means lower token consumption. If data flows are easier to observe, it’s easier for your model to trace the source of issues and fix it with fewer tokens in less time.

That’s why when I started working on Skaoot with Claude Code, I had already set up a basic project implementing Andrea’s Flutter and Firebase layered architecture, opens in a new tab. And every new feature I have added after that has followed the same principle, organized the code in a similar way, and every time I have had a bug to troubleshoot or a new feature to add, it has sped things up considerably. Because of that preliminary work, I am now very confident in the robustness of my code base.

Software engineering is dead, long live product engineering

I saw a video this morning of a software developer who was explaining that before AI, she didn’t really care about the kind of product she was working on, the business it dealt with, because what she really loved was the puzzles, the micro-creativity, the technical aspects of it. But now that all of that is essentially delegated to LLM generators, if she doesn’t care about the reason why she is building things, it’s all pretty boring. And I can relate so much to that.

It’s incredible how much our work has completely changed in just a few months. Before, we needed to understand the intricacies of the technologies we were using to the point that some people felt like they had to specialize, to be either a frontend or a backend developer for example. Writing actual code was already a small part of our daily routine, but it involved a lot of reading, research, training, experimentation, trial-and-error before we could finally write that working code. Not to mention all the overhead that came with aligning entire teams of frontend engineers, backend engineers, infrastructure engineers, designers, quality assurance testers, product managers, project managers, and more.

But now, those days are pretty much gone. Or at least they are when you choose to embrace this revolution and use the tools in the right way.

I was lucky enough that I had decided a long time ago already to expand my skillset across a wide range of activities across the software lifecycle. I have been a digital nomad for 8 years now, traveling the world constantly, and I just could not spend most of my time in daily meetings while in crazy timezones away from my freelance clients. So I had to consolidate my frontend and backend skills, integrate them with my experience as a project manager, build up my expertise as a product manager, and work directly with startup founders and small company business managers to build solutions from the ground up.

And now, the software coding part is pretty much entirely gone. I spend most of my days writing and reviewing specifications and technical plans to drive AI models to generate the right code, after which I can test what the AI has done, make decisions about what comes next, and move on. I still drive AI models to use technologies I understand and generate code I can read and intervene on when necessary, but for the most part, I don’t write code anymore.

Now, what’s important is that even though I don’t write code myself, I still heavily influence how code is generated by AI:

  • Through the technologies and frameworks I ask it to use
  • Through the architecture I set up at the beginning of my projects, the shell inside of which the AI operates and it takes inspiration from
  • Through the detailed context I include in every interaction I have with the AI, the things I ask it to pay attention to, the vision I describe, the things I insist on. For example, for Skaoot, in all the context layers I pass on to Claude Code, I insist on the importance of data privacy, reducing data noise, minimizing user effort, and all those general principles are in turn translated into architecture choices, code conventions, and so on.
  • Through the workflows I put in place

The importance of workflows

One of the things I really hated when I started experimenting with AI was the fact that all this code that was generated, I was still the one committing it into version control, I was still responsible for it, which meant that I couldn’t see myself deploying it to production without reading it, reviewing it and fixing it.

And as much as I like writing code and solving puzzles, I have always hated code reviews, having to read someone else’s code, getting frustrated about all the ways I would have done things differently, constantly fighting with myself to focus on what really needed to be fixed versus what was merely a personal preference. And let’s face it, the first AI models were ok at generating working code, but not necessarily quality code. So it was really like not getting the gratification of solving any problem myself and instead reviewing and fixing the work of 20 junior developers at the same time. It was awful.

And then models started to improve, and also got better at matching my code style, following my instructions and checking their own work, and also workflows appeared.

The first one I tried was the Ralph Loop, opens in a new tab. Essentially it was a whole set of skills and prompts to guide the AI through a process involving specification of a new feature, turning that specification into a list of tasks, and then launching the model on a series of autonomous loops where it would take the context of the specification for a task, implement it, verify its own implementation, and then reset the context and move on to the next task.

I used that for a few months and it was truly groundbreaking. Some feature development projects would take a few hours between the original specification and the end of the implementation, and then I would spend another few hours testing the end result, asking Claude to fix some things, but rarely did I have to completely throw away an entire feature. When it happened, it was because I had forgotten a key piece of context that I took for granted and didn’t bother to include in my specification, and the process being designed to be fully autonomous, it would take initiative and guesses to stay autonomous.

Another thing I noticed was that multi-tasking didn’t work very well for my projects: in a Ralph loop, you can specify how many agents can work on individual tasks in parallel, but increasing that number above 1 to try and go faster would actually slow me down in the end because of all the dependency management negotiation happening (« before I can work on this, I need that to be complete ») and all the merging that had to happen when agents stepped onto each others’ toes.

But one thing I started getting more and more comfortable with Ralph loops was the fact that I didn’t need to review every line of generated code anymore. My code reviews became more and more useless as I focused on reviewing the specifications and plans that came before the code. Through its own verification process, the AI model also generated unit tests and could even interact directly with the app for integration testing. And I also started using some special skills to have AI models review the code themselves.

But overall, I felt like the autonomous aspect of Ralph loops stood in the way of meta-evolution. What I call meta-evolution is evolution not of the code itself, but how the code gets made. In software engineering in general, one key practice to adopt is to always favor systemic solutions.

When a bug happens, you don’t just solve the bug itself, you ask why the bug was allowed to be there in the first place, and you ask « why » many times until you reach a solution level where you are confident that similar bugs won’t pop up anymore.

When you apply that to AI models and their contexts, it’s the same thing: when you notice that Claude made a mistake, or guessed wrong, or made an incorrect assumption, it’s not enough to fix the outcome, you have to figure out what piece of context was missing, where it was missing, so that it doesn’t make that mistake again in the future. That is how your generated code improves in quality and your building gets more and more productive.

With Ralph loops, I felt like I didn’t have enough visibility or intervention points to see those mistakes, and by the time they had compounded into a complex piece of software, they were harder to analyze and find the root cause of. So incremental improvement was slower, like natural selection with very long generations and not enough opportunities for mutations.

So then I started using Agentic Coding Toolkit, opens in a new tab, which is developed by Andrea Bizzotto, whom I have always respected and learned a lot from for his expertise in architecting Flutter and Firebase applications. But with ACT, he came up with a workflow that was perfect for the technologies I am using, while giving me more control and intervention points throughout the feature development lifecycle. And to this day this is what I am still using:

  • I describe the general idea of the new feature I want to build
  • ACT asks me questions to better understand and define the scope in the context of the existing app
  • Once I have answered all the questions, ACT uses all the knowledge at its disposal and all my answers to create a specification document
  • ACT then reviews this specification in an adversarial way, verifying each and every assumption it made while generating it, and it updates the specification
  • Then I read the specification in detail (a few hundred lines) to be sure we didn’t forget anything or make incorrect assumptions. If so, I ask Claude to amend the specification until I’m happy with it.
  • I then commit this specification into the code history to remember it for future evolutions, I reset the context, and I ask ACT to turn this specification into a concrete implementation plan, a series of work items with clear boundaries and references to the specification
  • I usually review that part more loosely, because it references a lot of code entry points that I have not written myself, but I just make sure that it doesn’t propose to do something completely out of the usual compared to the existing code, or tries to reinvent the wheel instead of using a third-party library to solve a common problem, things like that.
  • I commit the plan, reset the context again, and start the work on the first task in the list.
  • At the end of each task, I check the task report to make sure no recurring issue popped up, but if it does, I amend the context with a systemic solution, or I add a follow up task to the plan, or fix the specification in some way.
  • Then I check how full my session context is. If it’s between 33 and 50%, I will run a special reflection skill (more on that later), then reset the context. And then I move on to the next task until everything is done.

When the code produced this way is really big or complex, I use a special Claude Code skill to review the code and propose improvements that I let it implement. When it involves data security or access control, I also run a security review skill.

And as I explained, every time I want to reset the context after a big work session, I run a special « reflect » skill that analyzes the session and searches automatically for opportunities to improve the local project context, the general Claude Code context, or to create reusable skills for repetitive tasks. And this is my automated meta-evolution process. This is product engineering. This is my work now.

Instrumentation

In these workflows, whether we are talking about a Ralph Loop, ACT or any other workflow variation out there, one key element is to empower your AI model and connect it with as many context sources as possible so that it can make informed decisions and act on your behalf without you having to intervene at every turn. That is also what makes AI models so productive.

Some go as far as giving free reigns to their AI by setting up something like OpenClaw, opens in a new tab. In the context of software systems that can serve a lot of people and need to stay reliable, all while protecting users’ data, you have to be a little more subtle and cautious. But still, here are a few examples of what my Claude Code has (secured) access to when I build Skaoot:

  • Of course the entirety of the project’s code and its history through Git and Github
  • All the backend logs in Google Cloud and Firebase through the Firebase MCP server
  • My Jetbrains IntelliJ IDEA development environment through the Jetbrains MCP server (which in turn gives it access to all the coding and analysis tools exposed by the IDE)
  • Maestro, opens in a new tab to launch my app on simulators, interact with it programmatically (click buttons, scroll, etc.) and take screenshots
  • Playwright, opens in a new tab to do the same with the web version of my app
  • Context7, opens in a new tab to fetch the proper version of the documentation for all of the libraries and frameworks I’m using
  • Posthog, opens in a new tab and Appsflyer, opens in a new tab to analyze usage and attribution data from users and detect potential issues
  • My GMail inbox where I receive Google notifications about things I need to change in my code, or authentication links when I’m testing my app (Skaoot uses passwordless link-based authentication)
  • RevenueCat, opens in a new tab to analyse purchase flows
  • Linear, opens in a new tab to view, update and create project tasks
  • Sendgrid, opens in a new tab to create email templates and analyze email logs
  • Sentry, opens in a new tab crash reports
  • My Firebase, opens in a new tab infrastructure including files stored in Cloud Storage, data stored in Firebase Firestore, Remote Config and more

By having access to all of these tools, Claude Code can:

  • troubleshoot issues by analyzing backend and frontend crash reports and logs, and propose relevant solutions I can deploy in minutes instead of hours
  • integrate new code into existing code while maintaining consistency and optimizing reusability
  • write and execute integration tests that interact with the app and check the end result of every implementation or bug fixing task
  • upgrade or install new dependencies and integrate them based on proper documentation
  • keep my project plan up-to-date

Connecting all those tools through MCP servers happened by implementing systemic solutions and evolving my approach. When I realized I kept having to copy-paste backend logs into the Claude Code terminal, I gave it access to Cloud Functions logs directly so that I didn’t have to do that anymore. When it kept having to fix data corruption or generating testing data, I gave it direct access to Firestore with some safeguard to make sure it doesn’t destroy anything in production. This overall led to less hallucinations, less assumptions, more token consumption sometimes, but better solutions in the end.

How vs what and why

Even though writing code was always a small part of my work (though a big part of my day-to-day joy), reading code, organizing code, managing dependencies, architecting data and behaviors were all part of the « how » of my work, and that part was big. Now that this « how » part has become much cheaper, either through outright outsourcing (I don’t have to do it anymore) or through huge productivity leaps (I still have to do it, but I can do it much faster), « how » is not the bottleneck anymore. My focus has shifted to the « why » and « what ».

As a matter of fact, the « how » used to be so expensive, that people came up with a lot of tools and techniques to analyze the « why » and « what » so that you didn’t waste money building stuff nobody wanted or needed: lean startup, agile methodologies, kanban, etc..

Now that experimenting, trying things out is so much cheaper, it is less critical, and most people can afford to waste a little bit of time and tokens building the wrong thing. But even if, in absolute terms, you spend less time thinking about « what » and « why », overall it still represents the majority of your work now.

So the priorities have completely shifted. And with them, the skills required to build software have dramatically changed too. You don’t need nitty-gritty deep-reaching technical expertise as much, but you need better abilities to see the big picture, articulate a vision, identify problems, design solutions, express them and integrate them in a way that drives the AI to generate secure, scalable and evolutive software.

In essence, where you used to need a whole team of software engineers, designers, testers, project managers and so on, you now need a supercharged product owner with a strong technical understanding and a good design sense, and that person alone can potentially own the entire software building lifecycle. That is what I call a Product Engineer. Someone who focuses on « why » and « what », while knowing enough about the « how » to produce sustainable software quickly and continuously.

And that’s also why I think a lot of companies completely underestimate the change management aspect of AI adoption. They usually fire the most expensive developers, stop hiring junior developers, instruct the remaining engineers to use as many tokens as possible, and don’t change anything to their internal organization or culture.

But in my opinion based on how my own work has evolved now, I am now convinced that companies need to completely rethink the kind of profiles they need, think thoroughly about who they keep or fire, train their teams on how to trust AI models and leverage them intelligently, and reorganize their teams and how software is managed, owned and maintained. This is no small feat, and it has to be handled on a case-by-case basis, taking into account the specific constraints and assets of each and every company, their history, their expertise level, their resistance, their fears and their curiosity. No generic silver bullet tool or methodology is truly gonna help you optimize this transition.

AI is not this miracle tool that you can use to reduce cost by buying a license. The best way to really gain in productivity without decreasing the quality of the software you produce, and while doing more than what you used to do with the same budget or even a smaller one is to carefully transition and adapt the entire organization around this new paradigm that became possible because of AI. There will always be those who take shortcuts and don’t do this change management work, but in most cases they will fail, and blame the AI for it. Imagine if after the invention of the printing press, we had only built those printing presses for monasteries for copyist monks to use.

Productivity

In its simplest form, productivity is a ratio between how much you can build and how much it costs you to build it. So of course the most obvious way to increase productivity is to build the same amount of software value, and decrease the investment you make to build it.

But there is another way. You can also keep your investment as is, and consider all the things you didn’t build before, all the value you didn’t extract because it was just not worth the effort, and dramatically increase the scope of what you can build. Every technological revolution has always been an opportunity for a quantum leap in the level and scale of issues that become profitable to tackle. Would we have been able to go to the moon without IBM mainframes instead of human calculators? Would I have been able to build a sophisticated app like Skaoot all by myself without using AI? I don’t think so.

As a matter of fact, Skaoot made me realize something else that is very important: of course AI-driven development has multiplied the amount of things I can do with the same time, but it has also allowed me to build features that I couldn’t have even dreamed of before, with no chatbot involved. Too many software products today use LLMs to add a chatbot interface to their app, or offer suggestions to users where they didn’t really need them, or to replace humans with robots where it clearly doesn’t make sense.

But end users are fed up with that, and I don’t think that’s where it can create the most value. In Skaoot, I also use AI generation to parse non-structured emails in any format or language and extract structured data from them. I use Gemini to combine existing historical data with new incoming data into a snapshot that makes sense to the end user. And soon, I plan to use generative UI (not generative AI) to customize the way data is presented to the user in real time. No chatbot or suggestion popup involved.

« Give me a lever and I will move the world » said Archimedes. Well, we’ve just been given a huge lever, and so far we’ve mostly focused on reducing the size of the person weighing on the lever to move the same world, or slapping an AI logo on their back. Now you know what we have to do.

Next step

As I explained at the beginning of this novel of an article, I had been a software engineer for 20 years before AI came along and shattered all my certainties. And I went through an entire grief process that has now reached its conclusion.

I am not a software engineer anymore, I am a product engineer now.

Which leads me to shift my consulting career in 3 big ways:

  1. Skaoot: I’m gonna keep working on my new product, Skaoot, and grow it as much as I can, all on my own, without any employees, investors and getting external help in areas I still lack the minimum amount of skills to reach the AI lever. It will be my playground, my showcase, and a revenue stream.
  2. Adopt an AI: I’m gonna start sharing my transition journey with companies and teams who struggle to adopt AI and leverage it properly, through custom coaching and training interventions that focus on building trust incrementally, and integrating AI adoption into a real change management process.
  3. Augmented Intelligence: And I’m going to offer my services to entrepreneurs and companies to help them turn bigger ideas into successful business cases while leveraging the full breadth of my expertise to build even more ambitious software while using AI as a tool AND as a feature enabler, just like I’ve been doing on Skaoot.

If you’re interested in my first endeavor and you are a digital nomad or any kind of frequent traveler, you can check out Skaoot’s website, opens in a new tab. For the last 2 points, you should check out my new consulting home.