With the ever-growing popularity of full-stack engineering
it is time to give some thoughtful critique to the hype around it - at least to lower expectations back to realistic levels.
First let's start with an analogy!
The full-stack doctor at the most productive hospital
Imagine you have been experiencing double vision for weeks, and your anxiety grows when the MRI confirms that you have a benign growth in your brain that must be removed. The local hospital where your surgery will take place boasts about its productivity, claiming to have served many patients with few staff members. You meet your surgeon, who explains what they mean by "full-stack doctors":
Back in the day, when the anesthesiologist was on vacation, we could not do surgeries, or when the nurses got sick. Now we only hire doctors who do everything by themselves - no room for bottleneck people!
You ask if they have considered hiring a second anesthesiologist, but the doctor does not even hear you and continues:
While brain surgery is not my primary area of expertise, I am fairly confident that with our recent tools, I will excel at it! I have also just consulted DoctorGPT, the AI surgeon, and it gave me excellent tips.
At this point your heart-rate goes through the roof.
Language Fragmentation
Let's say you use Java
for backend and JS
for frontend. You immediately fire up a class
in JS and implement the good ole Strategy Pattern. You are proud of yourself, but "oh, no!", you could have solved the problem with a simple pure function you can totally write in JS
.
And this is not the only problem when you have language fragmentation: each has wildly different ecosystems, different ways of dealing packages/modules, each has wildly different coding philosophy: should you use object-oriented programming or should you use functional programming (light - real FP in JS is quite painful; the language was neither designed for OOP nor for FP)?
IDEs, debugging tools, CLI tools, setup etc. are all going to be very different from each other. Basically, if you have 2 languages you have to be up-to-date with twice as many of these as if you were focusing only on one language.
You might know my pain if you ever tried to install a different version of python
compared to the "fire and forget" nodejs
installation.
The elements in a stack are not just programming languages
Even with the same language you will have problem with libraries, platforms and frameworks. Each element in the stack is different and have its very own gotchas. Browser and backend server have very different limitations for example.
Here's another analogy: imagine someone hands you an alien spaceship with a robot to assist you. The robot tells you how to operate the controls and with that knowledge you successfully do a New York-Tokyo trip in just 30 minutes. You are blown away. Then the damn spaceship slows down. The robot tells you to "simply change the old antimatter to new one".
However, you have no idea how to service the spaceship, obtain anti-matter, or dispose of the old one. The easy abstractions ended there for you, and you realize how much you don't know.
Returning to backend coding, you're not just writing features in, say, Javascript, but you also have to deal with a lot of issues that only happen on the backend, such as:
- Memory-leaky code that worked perfectly in browser sessions now creates random "Out of memory" crashes and restarts every second, causing inconsistent data in the database.
- As you try to fix the issue, you realize that backend memory forensics is a beast on its own, and the tools you were familiar with on the frontend are not helpful. You have to learn new tools and paradigms.
- While investigating how to mitigate the data inconsistency issues, you realize that skipping proper SQL learning and going with
Prisma
or another ORM now bites you. Since you don't know you need transactions, you don't even know how to search for it.
Okay, you might say, of course, everybody knows about transactions, and I'm just catastrophizing. Yes, here, I think I have sacrificed some realism to keep this article short and memorable.
Scaling of a product shows blind spots
There is a point when naive ORM-based queries are just not performant enough and the costs and waiting times skyrocket. There is a point when people complain about how slowly your frontend loads because of the size of a badly architected CSS
bundle. There is a point when you don't even know you've been hacked until you read about it in the news because you thought "the library we used was safe".
The most dangerous aspect of
full-stack engineering
is giving false confidence that by being able to write business logic on both frontend and backend you are actually both a frontend and a backend developer.
Let's say you have 3 responsibilities as a full-stack developer
: creating UI code in TypeScript/CSS
, writing backend code in Java
and security. You only do all of these part-time (while you are working on the frontend you don't work on backend), and now you have to split your learning time among 3 responsibilities, not one. Compare it to a hacker who only focuses on how to penetrate systems, full-time, and nothing else.
The more responsibilities your tech stack have the less capable you are going to be to tackle them.
Even with a really great ORM like Prisma
that hide a lot of the underlying complexity you will arrive to real world problems where you are better off writing a complex raw SQL
query to minimize the number of turnarounds. Or we also had multiple cases where we had to write very custom SQL
as part of the "automated migration".
Every one item in your stack has slightly or wildly different programming paradigms. The abstractions provided by great libraries eventually run out juice at one point and then you are either a master of each domain's paradigm or you will run into problems.
As a summary I encourage you, the reader, to think about all the platform-specific gotchas you ran into, the ones that made you stop your work for days or week.
It is our responsibility to set realistic goals to ourselves and to our managers. Hiring or organizational problems cannot be solved by pushing all responsibilities to the developers at hand.