You know the feeling; you've integrated three payment providers, and each one has its own special snowflake implementation. Copy-paste, tweak and repeat. After six months, you're debugging the same bug in three different places, which is not funny.
This is what happens when you optimize for speed without optimizing for coherence. Now, with AI generating code 10x faster than you, the problem is worse. AI doesn't know your patterns. It just generates what you ask for, three times, three different ways... if it's not in the context, it does not exist.
The Pattern I Wish I'd Known Earlier
Here's a real example from a property management system I built. The requirement was to sync properties across Airbnb, Booking.com and VRBO.
Before: The Spaghetti Pattern
If you work on a team using Agile which is not quite well organized or used the first response AI provided, you might end up with this spaghetti approach:
// Airbnb integration
class AirbnbService {
public function updatePrice($propertyId, $price) {
$client = new AirbnbClient($this->apiKey);
$response = $client->put("/listings/{$propertyId}", [
'price_per_night' => $price
]);
// 50 lines of error handling...
}
}
// Booking.com integration (completely different structure)
class BookingService {
public function syncPrice($id, $amount) {
$booking = new BookingAPI($this->credentials);
$booking->rooms()->find($id)->update([
'base_rate' => $amount,
'currency' => 'EUR'
]);
// Another 50 lines of error handling...
}
}
// VRBO integration (yet another approach)
class VrboManager {
public function setPropertyPrice($vrboId, $priceData) {
// You get the idea...
}
}
We have three integrations, with three patterns and three new places to fix bugs on. And when the PM asks "can we add Expedia?", you enter rage mode.
This is what happens when you optimize for speed without optimizing for coherence.
After: The Pattern Approach
The alternative is to build a pattern so the same logic or pattern can be followed for all platforms
// One interface to rule them all
interface Origin {
public function get(string $key): mixed;
public function update(string $id, array $data): void;
public function delete(string $id): void;
}
// Clean, consistent usage
$property->source('airbnb')->update(['price' => 150]);
$property->source('booking')->update(['price' => 150]);
$property->source('vrbo')->update(['price' => 150]);
// Or batch update
$property->sources(['airbnb', 'booking', 'vrbo'])->update(['price' => 150]);
// Adding Expedia? Just implement the interface
class ExpediaOrigin implements Origin {
// Done in 2 hours, not 2 weeks
}
The result is the same, However we used just a single pattern., so there's also a single place to fix bugs on, except when they are aspecific for each platform. Your coding Agent can now generate new integrations that actually follow your architecture.
The ARC Methodology
Agile does not work anymore in the ear of AI. It fixed velocity, but not consistency, so in the era of AI you can create a compelte mess using Agile while coding with AI at your company.
To force the team to follow, we use a simple cycle called ARC, which is composed of three stages:
1. Align: before coding
Spent some time mapping the problem:
- What do all these platforms have in common?
- What's different?
- What will we need in 6 months?
The output a diagram showing Source (the platform) -> Origin (how we connect) -> Model (our data).
2. Realize: build the pattern + the feature together
I didn't build the pattern first, then the features. I built them together:
- First I built the Airbnb integration + extracted the
Sourceinterface. 2, Then built the booking integration using the interface and validated it worked. - Refactored, as the interface wasn't quite right.
- Built the VRBO integration in 10 minutes suing the pattern I created.
The key insight is that you discover the right abstraction by building concrete things.
3. Consolidate: validate it scales
After shipping, I validated the pattern against three criteria:
- Whether it handled edge cases I hadn't anticipated.
- Whether a new developer could understand it without asking me questions.
- Whether AI could generate new Origins correctly.
I wrote a .md file explaining the pattern, and now when I prompt Claude or Copilot with "create a new Origin for X following this interface", it works 95% of the time as I expected. Documentation is not just for humans, but for AI context.
The AI Multiplier
Here's where it gets interesting. Without using this methodology, each new integration takes a lot fo time of custom code, and when using AI generated code, it can be inconsistent. My AI generated code usually needs a full rewrite unless I specify exactly what I want. The integration of these paltorms can takes around 2 weeks.
Using a pattern, you first create the pattern assited wiht AI, integrating each platform in hours.
The pattern becomes an instruction manual for AI. Instead of just saying a vague:
Jut build me an Airbnb integration bro
You say in more precise way:
Implement the Origin interface for Airbnb.
And if the .claude file or the documentation is up to date you will not even need to specify that.
When to Extract a Pattern
Not everything needs a pattern. Here's my rule:
- First time: Build it concrete.
- Second time: Notice the repetition, and if you foresee another one, extract the pattern.
- Third time: If you're still copy-pasting, extract the pattern 100% sure.
You are not over-engineering or building patterns just in case. You build them when the duplication hurts.
To try this on the next sprint
You don't need to adopt a whole new methodology. Just just need try this:
Before coding, spend some time mapping: what connects to what? What's the shape of this feature?
While building, ask: have I written this before? Is there a pattern emerging?
After shipping, check: could a new developer, or AI Agent, extend this without asking me questions?
That said, as opposed as it happens with Agile, new features, pure architectural features, can spawn at any point in time when needed. Coherence is the thing to maintain here, as speed is assumed.
The outcome
It's not a rigid process, and AI-generated code will actually fit the architecture more and more with each new feature, as opposed as most developers and fans of "clean code" and "do not comment your code" usually say. In addition, new team members will productive in days, not weeks.
Do you think that Agile is already a thing of the past?
*More on this approach: The ARC Methodology, a framework about building coherent systems in the AI era.
Top comments (0)