Your Abstraction Layer is Lying to You
Every developer goes through it. That moment in Q2 when you look at your codebase and think "there's a lot of repetition here."
So you abstract it.
You abstract it so much that by Q4, nobody โ including you โ can tell what the actual code does anymore. You've built a layer cake of interfaces that call interfaces that call abstractions over the original function that just did fetch(url).then(r => r.json()).
The Lifecycle of an Abstraction
Week 1: "I'll wrap this API call so we can swap providers later."
You write a 30-line wrapper around a 2-line fetch. You feel productive.
Week 4: "Now let's abstract the config."
There's a config object with 14 properties. Three are used. Nine are undefined. Two are typos.
Week 8: "We need a factory for the factory."
At this point your import graph looks like the New York City subway system. Every file imports @/utils/helpers/core/base/init/setup/config/types. The types file is 400 lines and half of it is just type Maybe.
Week 12: The original API changes one field name and now you have to trace through six layers of indirection to find where the actual network call happens. Good news: you can't. Nobody can. The function that was supposed to "just wrap fetch" has been extended, overridden, and monkey-patched so many times that it's basically a new language.
The Anti-Pattern
// What you started with:
const data = await fetch('/api/users').then(r => r.json());
// What you ended with:
const client = DataClientFactory.create({
provider: ApiProviderRegistry.get('users'),
config: ConfigLoader.load('api', 'users'),
transformer: TransformPipeline.build(UserSchema),
cache: CacheManager.getInstance('user-data'),
retry: RetryStrategy.exponential({ maxAttempts: 3 }),
timeout: TimeoutConfig.resolve('users-api'),
});
const result = await client.execute(QueryBuilder.users().all().build());
const data = result.transform(UserTransformer);This is 17 lines of code to do what fetch does in one. Congratulations, you've replaced a network call with a software engineering project.
The Rule
Abstract when you've seen the same thing three times. Not twice. Not "maybe we'll need it." Three. And even then, keep the original fetch somewhere. Label it "escape hatch." You'll thank yourself at 2am on a Tuesday.
Fun fact: this entire post is more readable than the code it's criticizing. That's not a flex, that's a feature.