How I Grew as a Technical Leader by Learning From My Mistakes Leading Major AI Projects at IBM Db2
The five lessons that came from leading AI projects from concept to delivery — and how they reshaped my technical leadership.
I walked out of that meeting with a long list of gaps and one thought in my head: how am I going to pull all of this together?
I had just presented my plan for adding vector storage and search to Db2 at the Architecture Review Board, the committee of senior technical leaders who must approve every major new project before a line of code is written. I had walked in confident. I walked out humbled. The committee had found problem after problem in my plan that I had not considered. The list kept growing. Each item was a real use case that a customer would hit, and my plan had nothing to say about any of them.
I had spent nineteen years building software at IBM. I thought I knew what the job required.
I was wrong. Not about the technology. About what it actually takes to own a major AI project from concept to delivery inside a large, mature software product.
My Two Recent AI Projects at Db2
In the past two years I built and delivered two major AI projects at Db2.
The first was vector storage and similarity search, built directly into the database engine. This lets AI applications store collections of vector data inside the database and search through it to find similar items quickly. It is a core capability for modern AI use cases like recommendation engines and semantic search.
The second was connecting large language model APIs to Db2. This project lets application developers call these AI models directly from inside the database using standard SQL commands. Application developers no longer need to write separate code outside the database to do this.
These projects ran from the initial proposal to the final delivery under my technical ownership. More than twenty developers across multiple teams. Tight deadlines. Five Db2 platforms and many more deployment configurations. Db2 is a product used by companies for over thirty years, so a mistake is not just a bug report. It breaks the daily workflow of teams that have depended on it for decades.
The first project shipped to customers last year. The second has completed development and is scheduled to ship in the next few months.
These two projects taught me more about technical leadership than the previous nineteen years combined. Here are the five lessons I learned from leading these projects.
Lesson 1: A new feature must work with everything the product already has and does.
When we started building vector support, I thought the job was simple. Add something new. A new data type for storing vectors. A new way to search those stored vectors. Clean, contained work. Like building a new room in a house without touching the rest.
Users have built numerous business workflows around Db2’s existing features. There are tools for copying data out of the database to a file. There are tools for moving data from one database to another. There are SQL commands for every common task a user needs to do.
When we added the vector data type, users did not care about our internal design. They cared about their work. They expected the new vector type to work with all the same tools they already used every day with other data types. If the copy tool worked with varchar data type, they expected it to work with vectors too.
We were not just adding something new. We were taking on the responsibility of fitting into everything that already existed, without breaking the ecosystem. I had not understood that responsibility before I walked into the Architecture Review Board.
That is where the list of gaps I described in the opening came from. Each gap the committee found was a real use case that a customer would hit, and my plan had nothing to say about any of them.
I went straight to the senior architects and most experienced developers. We went through the list together, gap by gap. I asked for their guidance. We rewrote the plan several times until it was solid. A new shared plan, built together with the senior developers in my squad.
The method that came from those sessions: find the existing feature in Db2 most similar to the one you are adding. Search the entire codebase. Look at every place in the code that handles that existing feature, one by one, and decide whether your new feature needs to do the same thing. This gives you a map before you write a line of code. In a product built over many years, the people who built it will always find problems you missed. Bring them in before you think you are ready.
Lesson 2: A good design does not coordinate teams. A leader does.
The second project, integrating large language model APIs into Db2, made this lesson unavoidable. The feature required work from three component teams in sequence.
To add one of the new functions, we first needed new entries added to the database catalog, a central store that holds information about every object in the database. The catalog team had to finish their work before the query compiler team could start theirs. The query compiler team had to finish before the runtime team could finish theirs. Each team was waiting on the team before them. Like links in a chain.
If the catalog team finished one week late, the compiler team was stuck for a week doing nothing useful. If the compiler team was late, the runtime team was stuck too. The whole project fell behind.
I did not track these connections carefully at the start of the project. I assumed each team would manage their own work and speak up when stuck. They did not. Halfway through the project I could see that work was piling up in the wrong order. Teams were waiting on each other but not saying so out loud. Things were quietly falling apart.
I stopped the usual work and took charge of tracking every dependency myself. I asked each team one direct question: what do you need from another team before you can finish your work? I asked this at every standup meeting. If any work was not helping clear a dependency, I stopped it and pointed the team at what actually needed to happen next.
When a dependency could not be fixed in time, we found a workaround. The runtime team needed specific data from the catalog team, but the catalog work was still two weeks away. We hardcoded a temporary number as a stand-in. The runtime team used that number to keep building, completing 80 percent of their work without waiting. Once the catalog work was done, we swapped the hardcoded number for the real value. The team kept moving. The deadline held.
As a technical leader, you have to find the dependencies between teams, identify them clearly, write them down, and make sure every team can see what they are waiting for, and what other teams are waiting for from them. Do this early, or the project will slow down for reasons that are invisible until it is too late.
Lesson 3: A squad is not formed by putting people on the same project. It is built.
I formed my squad by pulling developers from different teams inside Db2. Some were experts in the runtime layer. Some worked on the catalog. Some worked on the query compiler. Every one of them was skilled and experienced in their own component.
What I did not expect was the resistance: not to the project itself, but to working outside their own component. Developers who spend years on one part of a codebase become very attached to that component. When asked to work in a different part, some resist. Not because they are difficult people, but because it is unfamiliar and they do not want to take responsibility for components owned by another team.
In a project where every layer of the product needs to work together, that reluctance causes real problems.
I had to build a new team culture through action, not words. I asked a runtime developer to write test cases for the query compiler section. I asked a compiler developer to write code for the catalog section. Every time someone stepped outside their usual area and helped another team, I called it out and thanked them. I wanted that behavior to feel normal, not unusual.
There was pushback. One situation stands out. The runtime team was waiting on a piece of work from the query compiler team. But the compiler team was in the middle of something that, if interrupted, would slow the whole project. Simply stopping their work was not the answer.
So we went deeper. We identified the specific code paths shared between the runtime and query compiler components, the intersection where both teams had a stake. Then we brought a runtime developer into that shared territory. They worked on the overlapping piece directly, consulting the compiler developer as needed and including them in the pull request review. Nobody had to abandon their current work. The dependency got cleared by finding where the two domains met and working from that common ground.
That became a pattern. Whenever two components had a dependency, I looked for the intersection, the code or interface they shared, and found a way to bring both developers to that point together. It was slower than simply assigning tasks. It was faster than waiting for one team to finish before the other could start.
I also made a point to listen. When someone had a concern about working outside their component, I heard them out and worked with them to find a way to contribute that felt manageable. People work better toward a shared goal when they feel heard.
Slowly the pushback faded. The squad started acting like a team. Once that happened, the speed of the work increased noticeably.
You cannot create a real team just by putting people on the same project. You build one by giving people a shared goal, listening to them, and reminding them, over and over, of what they are building together, until working as one team feels more natural than working apart.
Lesson 4: Testing runs alongside development. Not after it.
We wrote the code. We ran tests on our own development machines. Everything passed. We delivered the code to the release branch. I thought we were ready.
What I did not know was that Db2 has a central automated testing system. Think of it as a shared dashboard that runs thousands of tests on every piece of delivered code across all platforms and all deployment setups, automatically and continuously. Anyone can look at it and see which tests are passing and which are failing.
I had never looked at it. I did not fully understand what it showed.
Our QA lead, Darrin Woodard, showed it to us one day. The first time I saw the results for our delivered code, it was bad. Test failures everywhere. Red marks across every platform and every setup we needed to support.
Db2 runs on five different OS platforms: standard Linux, Linux on Power, Linux on Z, AIX, and Windows. Our code had to work correctly on all five. Db2 also runs in different deployment setups. Some installations spread across multiple nodes, others optimized for different types of workloads such as analytical or transactional. Every setup type can expose different bugs.
I had not thought carefully about any of this when planning the project. I underestimated how many test cases we needed to write. I underestimated how long it would take to investigate each failure and fix it.
The Db2 Chief Architect, Mike Springgay, regularly reminded me of this throughout the project. He consistently brought up the importance of estimating the QA effort separately from the development effort. Eventually that lesson landed. I began to treat QA planning as its own work stream, not an afterthought.
After seeing the QA dashboard for the first time, I requested the QA lead to join our regular standup meetings. Twice a week, we opened the dashboard together and looked at every new test failure for the features we had delivered for vector support. Before the meeting ended, every failure had a name next to it: the developer in my squad responsible for investigating and fixing it.
Week by week, the failures went down. More green, less red. Then, before our internal delivery date, everything was green.
Writing code that works on your own development machine is only half the job. The other half is proving it works on every platform, in every deployment setup, in every situation a user might encounter. When it did land, it changed how I planned every subsequent release. QA was no longer something that happened after the work. It was part of the work.
Looking back, Lesson 1 and Lesson 4 are two sides of the same coin. Lesson 1 brought ecosystem awareness to the design phase. Lesson 4 confirmed that the implementation actually honored that ecosystem. One is about seeing clearly before you build. The other is about proving it after you do.
Lesson 5: Writing code made me a better technical leader.
For a long time I believed that leading a technical project meant staying at the level of architecture and direction, and that keeping my distance from the code made me more effective.
It did not. It kept me comfortable.
I was running design meetings. Writing technical proposals. Talking with directors, architects, and customers.
But all of it kept me away from writing code for the actual product features we were shipping. The developers on my team were writing code every day. I was managing, reviewing designs, making decisions, and representing the project to people outside the team. I understood the system at a high level: what it did, how the pieces fit together. I did not understand it at the level where the real problems live: inside the code.
I gave myself a coding assignment. Real product code: the kind that gets reviewed, approved, merged into the main codebase, and shipped to customers.
I started with a relatively simpler function: the vector dimension count function. This calculates the number of dimensions in an input vector. I had built an earlier version of this as a user-defined function, a separate script outside the database. Now I needed to build it properly as a native part of Db2 itself.
I wrote the SQL grammar rules that let users call the function. I wrote the code that actually runs the calculation. I built it the same way every developer on my team builds their features: design it, write it, test it, find the bugs, fix them, write more tests, repeat.
Implementing this first function took me nearly four weeks. I was not working on it full time. I was still doing everything else too. And I was learning this part of the codebase, much of it for the first time. I wrote notes about everything as I progressed: what I tried, what worked, what did not, what I learned. I kept a running log in the Git issue tracker. Screenshots. Code comments. A record of how the feature was built from nothing.
Then I sent the code for review. To a senior developer on my team, someone whose work I had been reviewing and approving for months.
He came back with more than fifteen things that needed to change.
I had thought the code was good. It ran. The tests passed on my machine. But “it runs” and “it is ready for shipping” are very different bars. A developer who has worked in this codebase for years sees things a newer person cannot see. I read every comment. I made every change. I sent it back. More comments. More changes. Several rounds. It was hard, not because the feedback was unfair, but because it was right.
Everything I wrote down during the first feature paid off on the second. The steps were similar. I had a working template for developing new features. Four weeks became two. On the third feature, more complex than the first two, I blocked time on my calendar and focused. I opened a pull request with complete, working code in just two days.
Not because the reviewers stopped looking carefully. Because the code I was writing was getting better.
I was no longer an outsider, a non-developer technical leader telling others what to build. I was one of them. One of the developers in the front line, co-creating the feature code. When I sat in design discussions, my questions were more specific, more tied to the actual code, more connected to how things would actually work. The team’s relationship with me changed too, not because of my job title, but because they had looked at my code line by line, told me what to fix, and watched me fix it the same way I asked them to fix their own work.
The day I stopped thinking of myself only as the leader and started being a developer again. That was the day I became a better leader.
What I Know Now
On any given day across these projects I was the architect, the project manager, the developer, the QA reviewer, the stakeholder manager, and the face of the project to customers and senior leadership. Sometimes all in the same day. That is what technical ownership of an AI project at this level actually looks like. It is not one job. It is many jobs, held together by a clear goal and the discipline to keep moving toward it.
These projects gave me something harder to build than technical knowledge: real confidence, strong working relationships across many teams, and the clarity to take on what comes next. I can now lead AI projects at a scale and complexity I could not have handled two years ago. There is more to build. I plan to build it.
When I walked out of that Architecture Review Board meeting with a long list of gaps, I did not have what I have now. I had nineteen years of experience and a plan that was not ready.
What I have now came from two years of doing the work, getting things wrong, and rebuilding my understanding one lesson at a time. It came from tracking dependencies no one else was tracking. From writing code that got sent back with fifteen things to fix. From saying the same thing to the same team dozens of times until it finally landed.
These are not lessons I read in a book or learned in a course. They are the kind that only come from doing the work, from standing in the middle of something hard and finding your way through it.
I shared them because I wish someone had shared them with me.



