I gotta say, I sympathize with their "goes against every instinct" plight. If I had joined a team 2 months ago, and they'd been working on something for a year, and I was thinking "we should scrap this and start it over from scratch," I'd be really, really suspicious of my own thinking. Scrap and start over is such a tantalizing programmer thought for something that seems complicated and broken, and you'll almost always want to do it, and it's almost always the wrong call. Glad it was the right call here.
You see both sides of the coin often-- people are often too quick to go for a rewrite. But then you also often see the "rewrites are almost never a good idea" camp that dismisses the benefits too quickly.
The reality is rewrites are often appropriate but they need to:
1. Have a clear tangible benefit (or ideally many benefits)
2. Be as tightly scoped as possible to achieve the above benefits. Rewriting everything at once is a horrible idea in all but the most egregious cases.
3. Be as incrementalized as possible.
The best systems I've created came from iteratively experimenting with the language / API / whatever. Build something for the sake of learning, throw it away, build another experiment to learn, throw it away, take a shot at the real thing, throw it away, etc. It starts to feel like if you rewrite and think about the problem enough you'll eventually reach a point where you can write or rewrite the whole system in a week. Which leads me to conclude:
Systems that can be rewritten should not be rewritten. Systems that cannot be rewritten should be rewritten.
It's not quite true (not in all circumstances), but it's close. I think most enterprise / pile-of-business-rules software falls into the latter category, those systems cannot be rewritten, but they should be.
Expanding on your first criteria. The technology stack is fundamentally wrong is a good reason for a re-write. Language too slow. Doesn't handle the workload well. Other stacks have a better ecosystem.
Re-writes are also needed when the architecture doesn't match the problem space well. This can be incrementally done. Single threaded loops instead of using parallel-safe constructs like tasks and jobs.
Expanding on your point, rewrites can work if they can be accomplished in finite time.
It's one thing to rewrite a website, where the project timeline is measured in weeks.
It's another to rewrite large project where the -estimate- time is years.
We have mature desktop systems that have been in continuous development for 25 years. That might blow your mind, but its the same timescale as say Excel of Word. The question of rewriting, regardless of the tech stack, is moot. It would take years of effort (optimists think 5, more likely 10) and would cost a fortune. With negligible benefits beyond "now written in a language with a bigger developer pool".
I'm the first to admit that there are disadvantages to the stack. On the other hand we are where we are (doing well) thanks to that stack, so it's not all bad. We're still using code laid down in 1996, while being a modern desktop app. We're still the leaders in our field.
The time (aka cost) to rewrite is the major hindrance, and far outweighs any issues using an uncommon stack.
Spot on. Inexperienced people want to rewrite because they may not know the problem domain. Experienced people do rewrite because they know what they want to achieve.
And there's many ways to rewrite and migration strategy other than full rewrite.
A rewrite makes sense for two reasons. 1: No two people on your team understand the code from start to finish, or 2: (as in this case) the current stack cannot perform to the standards required, and another stack can.
Too many people just want to remix code or rehome it, taking the papers out of the old book and putting them into a new cover. At the very least, take the time to make sure you fully understand the system before you replace it.
Was it though? I mean, the goal was SSR, but if they had a fully functioning site sans SSR, why not ship now, then deploy SSR whenever it gets baked into Angular?
They were using Angular's dependency block them when I don't think they really needed to be blocked to ship a product.
> The relaunch of our ecommerce website had one goal: deliver blazing fast performance with Server-Side Rendering.
you’re suggesting they ship a rewrite that doesn’t do the one thing they’re rewriting for? at the time they also didn’t know when ssr support would be available.
they switched and shipped ssr support faster than it would have been available otherwise.
This is so bad. The worst of us all, but fun to read about the brinksmanship. The worst line for me was:
“From the founders' perspective, they had a clear stop-loss in place if things didn't work out” with the “stop-loss” being that “[t]he React site would be functional and performant in 6 weeks, and ship in 10. If it didn't, I would step down and recruit a replacement.” It’s just such a horrible thing to put on people, and is in no way a real stop loss.
So things failed, and now we lost our chief engineer, and who knows if they will “recruit a replacement” when they are either gone or on their way out, and recruiting leadership can take so long it’s such a crapshoot. THAT is a “clear stop-loss” to this person? Big oof.
It’s just such bad framing and bad ultimatums and bad people all around that I feel like I’m watching trash tv — and I love it.
Author here. It was a gamble, but I was fighting against a very strong sunk cost fallacy in leadership at the company at the time, and there was a general lack of trust in the entire technical team. I *would not* recommend this approach as a typical way of doing business, and maybe I didn’t do a good enough job at communicating that in the post. This is the only time in my career I’ve delivered this kind of ultimatum.
Everything about this particular situation was exceptional. I focused on the decision to do a rewrite in the post because I thought it was the more interesting part of the story. In hindsight I might have gotten that wrong.
I don't think it's really that wrong-headed. What are the choices: (1) march ahead trying to salvage the current design with no clear path forward (other than waiting for the SSR solution), (2) quit right now, or (3) quit in 6-8 weeks if the proposed solution doesn't work (or is not delivered fast enough). The last option is not that bad if the author is hoping to figure it out, especially that the timeline is short and with a quick prototype (which the author did) it's going to be clear much sooner if the new approach is workable or not.
That was the most ridiculous part. So in 10 weeks you would have no Angular site. You would potentially have no React site. You would lose your engineering lead. And the management signed off on this suicide pact?
By how the article is written it sounds like the ultimatum was the author's idea, as their way of securing the founders' buy-in. The ultimatum wasn't the stop-loss, it was the fact that the Angular project would ship if the angular team shipped SSR.
I think the primary reason the management team went along with the re-write is the thing that they had been struggling on for months could be working well in 6 weeks and complete in 10. This must have been a pretty small project - but kudos to the author and team for pulling it off.
To be fair the original also had a 12 week projection. So this 10 week 'estimate' was at that point just that. From a management point of view I would read this as an implicit 'we do this or I quit now'.
I guess if you have been working on something for 10 months, have most of the major pieces together, the team is stable and has a good understanding of the problems, then perhaps it is reasonable to expect that a complete re-write can be done in 10 weeks.
I think when most people say "don't do big bang re-writes", the reason behind it is the current development team unlikely has a complete understanding of the codebase. Once you have a million+ lines, no single person has a complete understanding of how everything works. People leave and new hires come up to speed, people forget how things work, etc., so the understanding of the system from an organizational perspective is rather fuzzy. Starting over in this situation is risky because the organization will inevitably have to re-learn forgotten things, re-implement and re-forget them to get to the same state that it was originally in. Much better to do one piece at a time in this situation.
While the 168mb is ridiculous, I'm more facinated by the choice to depend on an unimplemented feature from a group/company they had no control over or contracts with. I would hesitate to depend on things which haven't been released for a few months/years.
I realize the web moves fast and some might prefer working with new technology, but this sounds so weird to me.
I’m really curious what this article would look like if it was written from the perspective of one of the “boots on the ground” developers that spent 8 months on the original PoC, rewrote it in the 7 weeks, and is still maintaining it today.
Other commenters here are focusing on the bundle size or the choice of framework, but I'm really surprised by the stack: It's an ecommerce app, why do you need a SPA for it? I really think people have just forgotten how quick and easy it was to write SSR code that has a bit of interactivity on the frontend as-needed, and has gone full in on SPA all the things.
I wonder how long it would have taken them to write with plain HTML served by simple views.
Yeah, I did get a bit dismayed at "so we rewrote it and kept all the complexity, but used a framework that had the critical feature the old one didn't".
Sometimes I think the best thing an eCommerce Company could do is move their home-rolled eCommerce app to Shopify / BigCommerce / some other eCommerce SaaS. I imagine that 8 months of getting to know a true eCommerce platform and purpose-building plugins would result in a pretty reliable eCommerce app. Especially if you never have to worry about if your Cart, Check-Out page, or PayPal/Google Pay/Apple Pay plugin is going to break on every update.
> *"We delivered the new version of the site after 7 weeks"
I know everyone is focusing on 168MB, but ...
The bigger issue that needs to be addressed for this leader is - why did the previous project take 10-months, when that same team was able to deliver an entirely new rewrite version in just 7-weeks (without all the code bloat as well).
a large part of why it took 7 weeks was the work they had done over the last 10 months to gather requirements and translate them to code. the exact form of the code is merely the last stage in the process - i wager it would have taken them considerably longer than 7 weeks if they were starting the react site from scratch.
you are certainly correct. But there is a sentence that stood out to me, one where he said that devs needed to wait up to a minute to see their changes. I’ve personally felt the slog of writing code that takes easily 2 minutes to see changes, compile, flash unit, connect via bluetooth see if change shows what’s expected in some blackbox app. It’s maddening, and slows things way down, trying to keep the thought of what you were trying to do for that long is difficult and leads to lots of wasted tests. I largely suspect it’s an exponential function and the longer the feedback the exponentially longer the code takes to write.
1 minute is a long time, and I could see if you could get that loop under 10 seconds you could shave off months of dev time. Hell, I just recently changed a test timeout I was working with from 2 seconds to 1 second, and my morale improved in ways that surprised me even knowing all this.
Its not surprising honestly. There's a point in a codebase's life where it grows to this size that's hard to put all the moving parts into your head. Bloated, corrupted, every change takes careful caution to make sure it doesn't affect some other part downstream. You might know certain parts are not optimal or efficient, but you don't have the time to stop iterating on other tasks and fix these inefficiencies, let alone revise all the other built on parts that depend on this sub optimal component.
A clean slate on the other hand is a lot easier. There's no vestigial pieces. No dependencies on hastily written functions you never got the time to rewrite the right way. You aren't locked into some version of a library from three years ago, you can use all the latest tooling.The shorter the codebase is in total, the easier it is to grasp the scope of how it all works together and move faster, knowing where other things should fit in a much simpler mental model.
In fairness, rewrites can be quite a bit faster than an earlier incarnation. By that point you've identified key gotchas, can simplify quite a few things, etc.
I don’t have much experience with frontend frameworks / libraries, but I really dislike the way this article presents React as the silver bullet.
Maybe it is factually accurate that Angular was the wrong choice for e-commerce (at the time?). I don’t know. Without SSR, was there really nothing feasible they could do to reduce the page load time? Did Angular make tradeoffs that are better for a large, interactive web application; and you want a different set of tradeoffs for ecomm use cases? Or were they just stuck with the wrong tech at the wrong time: complicated enough that it’s too slow in Angular, and the project hadn’t caught up to them yet?
That JS bundle was doing _something_ (probably lots of somethings). How many features did the React rewrite drop? Could you have removed those features from the old codebase, or would that have been politically infeasible at the company? (“no, don’t delete that” vs “yeah, we can live without that, you don’t need to implement it” -> author gets to add a Loss Aversion sidebar). Are there still items in the backlog to re-implement missing features (that the team intends to complete)?
Development effort compared between stop-the-world rewrites (in order to hit their 7 week “really big shopping event”) vs rewrite following ongoing feature development and the painful merges mentioned in the article. Obviously business appetite changed for a stop-the-world rewrite, but could that have been identified earlier?
Changing requirements: did the Angular upgrade start with “we need SSR” as a top requirement? It seems more likely that there were a bunch of benefits / requirements for a technology upgrade, and over the previous 10 months they’d discovered SSR as a blocker. Erasing the other improvements makes the 10 months vs 7 weeks sound very impressive, but seems disingenuous.
Maybe my expectations are off for a blog post format.
> I really dislike the way this article presents React as the silver bullet.
It didn't read like that to me, I thought the point was they went for a rewrite on the new breaking changes major version, expecting specific features to eventually land, were waiting for them, and React had them already.
So it's more (to me) like 1) don't do that; 2) if you're going to do that maybe take a step back and there's something else out there already or that's a better fit.
It could have been any technology. The silver bullet is choosing the right tool for the job.
I don’t have an attachment to any particular tech. At the time React was what I knew, and I was coming off the back of building a server side rendered React site when I joined this company. I had a team of JavaScript-focused engineers to work with.
Spoken like someone who doesn't need and/or understand SPA-style features. Look I get it, I've been developing with PHP for close to 2 decades but let's not pretend that PHP+jQuery (or whatever you are using for frontend interaction) is anywhere near as powerful as a SPA+SSR. And yes, not every site needs to be a SPA but there are some sites where that absolutely is the right call and pairing it with SSR can get you "the best of both worlds".
People/stakeholders who want use the browser as an application platform.
Think data analysis tools, Intranet tools, e-commerce, and a host of B2B stuff?
I know, it all starts with a filterable list or a shopping basket, where page reloads or ajax "sprinkles" (regardless of what they're loading, HTML or JSON) are absolutely OK.
Especially the fully old-school approach with the page reloads - it can work and scale for simple and predictable requirements.
Until it doesn't - the first page with 5 interdependent autocomplete inputs takes weeks to develop and fix, the modals can't have routes without piles of jQuery hacks, and so on and ao forth
everything i built in the past few years only needed a generic CRUD backend, if it needed a backend at all. there is no application specific code in the backend, and the latest app i am working on is completely static as far as the backend is concerned. it could even be served locally via file://
all the application and interface logic is in the browser.
this is only possible thanks to SPA.
with a backend, data persistence is simply CRUD. for the backendless app, it's all in localstorage, and it can be downloaded into a file as backup. all the logic is in the browser, just like any desktop application. you should not need a server to manage personal data that is stored on your computer.
of course it is a tradeoff. if the user wanted to save their data outside the browser every few minutes then that would not be practical or if there is to much new data being generated so it doesn't fit into localstorage. i'd either need a server (even if running locally) that can save that data without user intervention or i should not use the browser as a development platform. in such cases a browser based SPA would have been the wrong choice. maybe electron, or a traditional desktop framework
My company does. It is a desktop level app written for the browser. And it is mostly done in Vanilla JS. No SSR since time to first load is irrelevant. They are about to sit down for an hour of solid work on a trusted platform, not buy a pair of shoes from an unknown site where waiting 500ms might make them change their mind.
Well, not long ago I made an in-browser WYSIWYG mouse-based diagram designer. I redefined a huge share of the default browser behavior.
It was also the first SPA I made, in a career of decades. I also think I do not regularly use anything that benefits from being an SPA (I don't regularly use that diagram designer either).
No. From what I can tell the whole reason for a SPA is so that people don't leave your site. You throw away a lot of good things (like urls to content) so that you can push more ads at people.
Ah, I see your argument; SPAs are a preferred way to 'suck folks in' to a page and just have them stay there since they can't navigate in and out to the specific piece of content they want with URLs.
That about sums up everything wrong with our industry. Engagement over usefulness.
yes but none of that has anything to do with SPA as a technology.
the point of an SPA is so that i can share code and data for different pages in the browser without having to get it from the server for each new page.
it does not at all prevent me from using links to the outside or even within the site. (i just built an SPA where all navigation is done via regular links, each view has a different url, they all can be bookmarked, and history works too so you can go back and forth using the standard browser buttons, and links to certain resources take you out of the app)
> the point of an SPA is so that i can share code and data for different pages in the browser without having to get it from the server for each new page.
You still have to get it from the server for each new page, you just do it in the background.
i don't need to get the code. nor the markup. that's already loaded in the browser. if i need to get anything, it's raw data. i also don't need to send anything back so i can manage state. being able to load data in the background can also improve the user experience. and for those apps that don't need a backend, i won't need to get anything ever after the first load. SPAs can, if written right, function completely offline, once loaded.
Main side project of mine is a Strava-like web app to upload bike rides. It’s intended for personal use, so I don’t care how long it takes to load for random visitors arriving for the first time. I don’t care if search engines can properly load the page for content previews. I don’t care if someone’s ten year old Android device chugs on the JavaScript. I don’t care about dealing with the headache of making whatever JS library I’m using work with hydration.
My own website is a kind of hybrid SSR/SPA in PHP. Navigating pages with JS enabled (JS is entirely optional) seamlessly updates the relevant DOM nodes with an AJAX call (and uses the history API etc), but going to a page fresh is entirely PHP.
I actually uncovered a niche bug across multiple browsers with this PHP code. In at least Firefox and Edge, if a page is cached with a fetch using accept:text/json, the response will be shown from view-source of the html page you have open, even if the content is different when you fetch the page with accept:text/html
SSR usually means doing the front end JS browser render on the server, not just the more generic task of producing an initial HTML from a server.
The idea is the same code can work on front end and backend. On NextJS it will run your React on the backend but useEffects will not be called. Just the initial render is saved and piped to the browser.
I never said it either/or, in fact I’m using PHP to power an SPA right now. I was saying that pretending that PHP alone was sufficient (for both customers or dev speed) was silly.
15 years ago a frontend build was not a thing. You managed what few javascript and CSS dependencies you had via the order of the script and style tags in the header. Now a frontend build is a baked in requirement of any user-facing application, so whatever you end up doing in whatever language, you already have that one build to manage. If you choose to build your application in anything other than JS/TS, you are effectively adding an additional build to the project, with all of the associate overhead. If you stick with one language and one build, you are eliminating large swaths of unnecessary complexity right off the bat. Not to mention that you don't have to hire for the additional language for the dev team.
Unless there is a legacy system driving the requirements in a different direction, my default application architecture is always going to be server-side React at this point.
Using facing meaning they have a UI. Even the simplest of which has some degree of CSS and generally a bit of JS. Unless you want to go back to the jquery and vanilla CSS days, which I can promise you none of the your developers will thank you for, you need a frontend build of some kind.
I feel sometimes that we are running in circles in front end development. We had a good thing: Then we burned, step on it, and then recreated it because it was the best way to do things in the end of the day. :(
But it’s not a circle, it’s an arc. If it were a circle, running as fast as you can in one direction would bring you back around to the former. Instead we hit the end of the swing and backpedal until we remember why we were going this direction in the first place.
I feel like this is the inevitability of more and more tooling being released. Eventually there will be so much tooling that its hard to even work effectively as the signal to noise ratio plummets over time.
You should really try something like NextJs, all the nightmarish parts of FE development are abstracted away. It makes me hopeful for a future where all the config files and tools are invisible and you just develop applications. All the TS, HMR, SSR, etc. is invisible to you and managing it is the responsibility of the people developing the frameworks.
front end is such a shit show these days endless and then stuff runs for 1 month stable and instead of adresing real issues they come up with another rewrite.
Why do you need isomorphic SSR for ecommerce? Why not use a backend templating tech to render the initial layout? Yes it is a bit W.E.T. but it is what you would traditionally do and for ecommerce would be good enough I reckon. I think SSR, Microservices and other buzzwords gets us in trouble.
As a mid-seniority developer, I'm just now starting to grasp the harsh reality of a full refactor. We always think we can improve the speed and code of a website but, man, that's really though.
I always remember the "let's throw away Windows ME codebase for NT" scenario. Sometimes giving up is better I suppose.
Well the Windows 9x codebase was always mean to be , eventually, thrown away. It existed only to be able to run the OS on very low hardware (eg Win95 run even on 4 MB of RAM).
Certain websites are so overbuilt though that theres plenty of low hanging fruit. I’d say a very healthy majority of the websites I visit could replace whatever bulky mess they have with static html and still serve me their content and ads. Then the website would probably be orders of magnitude more performant refactored in html.
One of our teams rewrote their legacy cloud product in an interesting way. Instead of gradually replacing components of the existing product, they forked it, rewrote most stuff from scratch in a different branch using a different stack (different UI/UX also) and called it version 2.0. The old version was still maintained (bugfixes, tech support etc.) but they stopped selling it. Instead, they started selling version 2.0 (new clients were unaware of the difference). Version 2.0 did not have full feature parity with version 1.0 at the start because it would take years to reimplement everything. What they did was gradually migrate clients from 1.0 and 2.0. Most clients did not need all the features so they were OK with version 2.0. Those clients who refused, stayed on version 1.0 for a few years. Then the team was slowly adding more and more features to 2.0 for the next few years, and more and more clients were willing to migrate, and this year the last client migrated to version 2.0. It took 4 years overall. The new version was designed to be more stable, more scalable and more maintainable, so it's a net win in the end. Also, since it was basically a new product, they were able to experiment with new ideas without the constraints of the old product.
There's usually a subset of any given codebase that gets changed substantially on a regular basis, and the rest mostly stays mostly the same. If you can get the parts in the former category replaced with something better to work with, that often gives you most of the advantages and you can migrate any remaining bits as and when you can be bothered.
>We always think we can improve the speed and code of a website
You're not wrong, but the moment you speed up your site to being usable then the stakeholders above you are going to add 50 more (conflicting?) requirements until the site is slow as the old one.
> The React site would be functional and performant in 6 weeks, and ship in 10. If it didn't, I would step down and recruit a replacement.
I lost at lot of faith in the author's judgment at this point. I know this thing worked out and it was the right decision to port things over to React (and correct the bad decision to count on the Angular team to deliver SSR on their timelines). But you need to be able to explain things to the business without this sort of nonsense. I would be really concerned if I heard a manager saying something like that. It's not an argument, it's just a "trust me" that raises the stakes and pressure around the project.
That part worried me, too. The inherited situation was not good, but I think it may have set the stage for some reactionary heroics that were also somewhat unhealthy.
Jumping from one extreme (completely broken development process) to another (threatening to voluntarily resign if arbitrary deadlines aren’t hit) just feels like a sequence of unhealthy extremes driven more by ideology than practicality.
It’s great that the process worked out, but I’d not be happy to work under either team to be honest. Plenty of teams manage to ship working code without either of these problems.
> Plenty of teams manage to ship working code without either of these problems.
The key point is that the team in this story didn’t. They needed something extreme to make progress.
And remember that nearly all deadlines are arbitrary. Somebody needs to pick some date to see if something gets done by that date. There’s nothing wrong with an “arbitrary” deadline like the one described in the article.
I don’t agree at all that they needed the extreme behavior to make progress. They did need to bail on their bad plan and implement a better one.
> Somebody needs to pick some date to see if something gets done by that date.
Right. What you don’t need to do is say “I am going to hold my team to the arbitrary date I ballparked because I staked my reputation on hitting it no matter what”. That’s a miserable way to work.
I clicked into the author's profile and it says "Osaka, Japan" -- if that's the working environment, I wouldn't be surprised if that's the only approach that made sense given the intense work culture in Japan (from what I've heard)
I think you're taking things without knowing the details of his context. You speak to business in the language business understands. Sometimes business is not interested in your logical explanations. They're seen as excuses. Business dumps the responsibilities on your lap, gives you a budget, and starts pressuring you to deliver. The only conversations you then have are about time and money. Give me some time, give me some money, I'll save you more, etc. So those are the bottom lines of any arguments. Maybe in his specific case this (second) argument, of putting his job on the line to buy himself 10 weeks of work, combined with the first (staying aware of how the angular project is evolving and picking whichever comes first) was something that business felt comfortable risking. You would go in with all your React technobabble and be surprised when they roll their eyes and say "how long, how much".
“Don't build production applications with experimental tech.”
And
“Don't do "big bang" rewrites.”
Cannot be oversold.
Seen massive projects flounder under the delusion they could do a full rewrite and base the entire stack on some v0 core service/library/whatever the architect saw at the latest AWS reInvent or whatever.
At my previous job, my assignment was to rebuild a front-end 10 years in the making; the company had lost (idk if they fired him or he moved on, I suspect the latter as he was one of the founders) their previous developer, who was both not a very good developer and very productive.
But yeah, when I joined that software had been built for over 8 years, using technology and practices from the 2000s (think AJAX where X is XML, a PHP back-end that concatenaded XML tags, and a Dojo front-end), and my goal was to rebuild it.
I spent 2.5 years there, using Go as back-end so it's all integrated (one issue was that the PHP runtime they had at customers couldn't be updated because RHEL didn't have a newer version in the repos), React as front-end, etc etc. But there was just too much functionality to rebuild, and they didn't / couldn't find other people to hire (until I quit, because of course).
In hindsight, while PHP wasn't really my thing, I should've focused on improving the existing codebase and then only incrementally improve and replace things in-place. I mean at the same time, I knew a full rebuild of that was a Bad Idea, but that's what they wanted and I wanted to do stuff in Go as well so I didn't challenge it too hard.
But yeah, I could've easily made the back-end twice as fast with at worst a week or two of work; half the back-end's processing time and memory usage was because they took that concatenated XML, parsed it, and converted it into JSON. Because at some point the previous author realized JSON is the new cool kid on the block.
Well, I wrote both the backend (PHP), and the frontend (Swift).
The backend is too complicated, because I originally wrote it as a general-purpose server, and it is now specific, but it works fine. No need to rewrite, although I’d love to.
The frontend had been “accreting” features, because it was really a high-quality prototype.
When we had nailed down the functionality, I knew this was a ball of mud that I didn’t want to maintain, so I factored the business logic into a standalone library, and most of the work has been on the “chrome” for the app. It’s not-simple, but much more straightforward than the previous version.
Also, this time, we brought in a professional designer, and have been applying style from the beginning.
I once led a project that had an android app years ago. Someone on the team brought in guava for a small number of helper utilities. This made our apk exceed the method limit which required some partitioning (forget the details) that increased the time to push the app from like 15 seconds (which was still way too long) to a minute (which I found unbearable).
One day I ripped out guava, handwrote the parts we were using and got our apk size safely within the method count limit. The project still failed horribly though but for other reasons :)
I consulted on a project suffering from similar problems. I came in after they'd been working on it for about 10 months, maybe a bit more. It took me less than 2 months to figure the team knew fuckall about the technology stack they chose. I had been told coming in that the team lacked experience. No one on the team had used the chosen technology stack at all before it was chosen for this project, and it showed. It took me a bit of digging and asking questions to find out the full truth.
On the down side, the technologies the team did know were all outside of my expertise. I could sort of muddle through understanding but I was by no means experienced enough to be making any recommendations about it.
The system did need a total reset. If they wanted to stick with the technology they had chosen, they needed a different team, or at very least a different team structure with a couple of genuine experts setting direction and the inexperienced people given tasks appropriate to their abilities. If they wanted to keep the team, they'd need to start over with different technologies.
In the end I wrote up a document of recommendations for the leaders, with a list of problem areas and suggested direction. I never said explicitly to throw it out and start over, but left it to management to figure out the implications.
Been working on a mobile app for ~3 years and seriously considering rewriting.
The custom UI/UX design is bad, would like to replace with default design based on OS. For a lot if the code I’ve written I also know better approaches now. Finally app is written using Xamarin Forms but I feel moving to MAUI will be a net benefit, even if I will encounter hurdles.
Now I know my client will not support me re-writing the app. So I might have to do this work in my own free time and once finished, show the client and then they can choose to buy the source code from me, or not.
I am sure the app will become much more stable and enjoyable for end users, so I believe I can convince the client to switch. There’s a long term task in backlog anyway to move to MAUI.
I think in “The Mythical Man-Month” [0] the author wrote a topic that discuses the idea of writing the first version of a project to throw away. As a learning exercise of sorts. There’s value in this idea.
Another idea presented in the book is the second system effect, meaning the first re-write risks being over-engineered, so that’s something to be aware of.
Yeah I hear you on this. I worked on a mobile app for a few years at a company. Lots of interesting, custom animations and ux. But a huge pain in the ass to deal with issues when they arose.
Personally, I think you should wait until there's buy in from the customer before doing the rewrite. Or at least that's what I'd do.
A friend of mine just delivered a MAUI project and his opinion is that it is not production ready. He said that fundamental things like correct back button behavior is broken. I don't know any more specifics, but do serious critical research before choosing MAUI.
Yeah I kinda now MAUI still has many issues. I am actually about to deliver a Nuget library in the coming month or so. And during the development of the library also encountered various issues with MAUI.
Maybe Avalonia would be a better idea, not sure how hard the switch would be.
to be fair, it's e-commerce. an MVP of a _working_ e-commerce site still needs a shitton of functionality (cart management, product management, sku management, backend data, tax calculations, etc etc). i'm not surprised at all that it took this long. he didn't mention using any frameworks, so i'm guessing they made some bespoke thing.
I would argue that the stop loss (ship react in 10 weeks and step down if not) is misleading. What it really means is it becomes someone else’s problem. That someone else is management and the team, and simply put, no longer yours.
> The company's first website was an AngularJS single-page application. AngularJS didn't support server-side rendering, so the website was slow to render on first load, but snappy once everything had downloaded.
That sounds like a pretty decent concession. I wonder if it was ever even a real problem. I'll bet the real problem is that nobody was willing to call it done.
He mentions that this is not a good UX in ecommerce space.
I think I agree.
If I have a choice between buying stuff on Amazon.com and Walmart.com -- and if one of the two gives me sluggish UX everytime I start my user journey. The other competitor site would eventually become my default go to and get all my money (everything lese being equal).
Brands are built at touchpoints -- according to my marketing prof -- and I believe it rings true.
The js ecosystem is frustrating. I’m a backend/DevOps/platform engineer so I don’t write frontends, but I’ve spent many hours working with and optimizing the compiled JavaScript in CI/CD pipelines, deployment systems, and homebrew bespoke SSR Rube Goldberg micro services that a backend calls out to, waits for the js to comeback, throws in a redis cache, then sends down the pipe to the user. The frustrating part is that often times the clusterfuck required to spit out some scripts that make Ajax calls to a backend, shuffle divs around, bind dom events, and push browser state, is so much more complicated than the backend systems that are actually doing the core work for the app.
SSR was a solved problem before SPA/huge frameworks became the often unnecessary de facto, standard. Why am I dealing with a backend app server that is deadlocked and exhausted its connection pool causing cascading failure because its (wrongly) making in-band calls to a micro service someone wrote which is a single threaded node app running a virtual dom and spitting out js that shouldn’t be required to serve up the app’s presentation layer, yet now is queuing up an ever increasing buffer of connections from the backend trying to get the page assembled to send to the user who does not care about any of the js so long as when they click shit, it clicks.
Js is a simple and small language. The runtime it executes in is designed for a very specific deployment target and even there it’s at its limits. Why did we let a tiny scripting language become this beast of complexity and obnoxiousness? Why can I put bundle optimization and tree shaking on my resume? Or that I inherited and maintained a not invented here fueled SSR system that would rehydrate Apollo stores and glamorous styles, for a site that would have looked the same and provided the same FE functionality using bootstrap css and js? Why am I adding extra headers to response bodies to debug if SSR is being cached by the backend properly, or if the caches are being busted properly and sweeping down the Russian doll layers at the react component level? Why, if it was known from the start that search crawlers wouldn’t render JavaScript, and as a result wouldn’t render the content you want indexed, did you not use a friggin backend templating engine that every MVC framework has a million options for, and include a damn partial that adds your js for a signup modal and some Apollo gql queries? All this complexity is for what? Bash is a tiny scripting language with very specific deployment targets and handles mostly presentation and in the what, 60 years it’s existed, shipping a shell script has been as simple as scp’ing a file to a server, which is how easily you used to be able to “build” and ship js. If the Linux OS devs didn’t need that kind of complexity, your hot or not site doesn’t either (: Is your job as a front end developer significantly improved from the days of using jquery or some other tiny no nonsense utility lib? I see the js being written and I don’t see a huge quality of life improvement to justify the chaos these systems introduced to the entire stack, build system, CI system, deployment orchestration, bundle optimization, library bloat and security upkeep, dependency hell for package upgrades, CVE shit show and supply chain security. What is your app doing that all of this is needed, for presentation? Modern web apps are enormous, render slow as hell, and often break expectations set in stone 20+ years ago, like the back button doing what it says on the tin, or inspecting a dom element and being able to actually see the content, not off in some store somewhere and bound to some property event that injects it and removes it as needed.
People have just accepted that this is how FE dev is done now, with jr devs knowing only this insanity and not anything else. I try to delude myself to think that this is fine, it’s better, somehow, and yes I realize that modern frameworks are in some ways better, react components are modular, reusable, transpilers are able to do chunking, lazy loading, tree shaking, gzipping, and compile time performance optimization as it writes the file, but why is this needed for a single threaded language primarily doing network IO and string replaces? Nobody on the FE team at that place with this insanity could grok how it worked, and didn’t understand when things rendered with SSR would be different, or how to debug any of at all. They didn’t run SSR locally to confirm, they didn’t use any tests, and trying to force them to model the request flow between backend micro services, the added complexity of any caching solution, to constantly be mindful of not having access to the window element when running in node server side without special consideration for shims or null objects, is not fair to them, but it’s not fair for people familiar with deploying complex backend SOA systems to be force fed a maintenance and stability nightmare either. There has to be a common ground.
I know my rant is exaggerated and overly critical, but god damn y’all, reel it in a bit, will you? I’m hopeful that things get slimmed down and less complex as the JS community corrects for the over correction that caused all of this and got us here, and I see things that tell me it is happening, so hopefully soon my job won’t have to mentally model and reason about these moving pieces that result in static files on a cdn.
If I can ever finish it, my solution to end the need for SSR at the lib level, which isn’t original by any means, was a background queue, and a pool of headless chrome docker containers that handled it all. Send it a url, the page is rendered in real chrome, guaranteeing runtime compatibility, dev tools api calls will execute some js in chrome console to inline styles and prepare the js, and finally spit out a full html page complete with bundled inline styles and JavaScript, along with any rehydration on load events. No need to have special js packages or servers. No need to think about it at all as a FE dev. If it works locally in chrome for you, it’ll be the same thing from SSR. Some middleware in the backend app to route crawler/logged out/whatever you want requests back to the SSR system if not in cache, serve from cache if in cache, or pass down the call chain and let the backend serve up html with client rendered js if it’s a request you don’t want SSR’d. Still complex but the core of it works for any and all websites, not just one with a special SSR js package and config. For shops with many apps and frontends, it could all run through the same chrome ssr render pool, because it’s just a bunch of sandboxes chrome instances.
Note: it’s been a minute since I’ve been in engineering at all (out of work) so things may be much better now. I also am fully aware that the SSR system of insanity I described above was overly complex from the day it was built, and nowadays many frameworks ship with bundled SSR functionality.
As someone who has been doing frontend, backend, systems administration and general black magic since before the jquery days, I can tell you that managing frontend requirements was absolute hell back then. You literally had to put the script and style tags in the right order in your header or footer and just kind of hope the timing worked out. People how work exclusively on the backend tend to underestimate the complexity of frontend builds in the same way that non-technical people underestimate the complexity of all software engineering. The truth is, something as common as an autocomplete input is an application unto itself, with multiple dependencies all with load priorities. I don't have to imagine what this was like back in the jquery era, because I experienced it and it sucked.
I noted this earlier in the thread, but the fact is that any user-facing application with a UI is going to include JS/TS and CSS, and therefore is going to include a frontend build of some kind. Any build included in an application comes with the requisite build orchestration for all environments, so Docker config, build specific config, CI config, etc. If you add a second language to an application, you add a second build, and the cost of setup and maintenance of your application basically doubles. Not only that, you now have to have engineers proficient in multiple languages on your build. Most engineers are really haughty about the language they write and the part of the codebase they prefer to work on, so finding someone who is equally comfortable AND proficient writing python applications and frontend code is extremely hard. Most likely you'll get a Python engineer who will reluctantly write some awful React and complain about the entire time, or vice versa.
So if you come to me and try to add some Python or Ruby or god help you PHP to my single build Node/React application because you think its somehow going to make things simpler, I will simply eject you into the sun.
I'll write an API in any language that makes sense for the performance requirements. But if the app has a UI, absent any legacy requirements that force you to do otherwise, it 100% absolutely has to be entirely in JS or TS or you are shooting yourself in the foot.
I love Joel's advice usually, but I don't think that piece of advice aged particularly well, for a couple reasons:
1. I think there is lot of good evidence in the past two decades where companies got killed by competitors because the competitors had the luxury of starting from scratch with better, fresh ideas. Think all of the innovations in Google Chrome when it first came on the scene, e.g. V8 and it's process model.
2. There have been examples of companies that have essentially "ripped out their guts and gone with something new" over the years - think Apple and all their chip architecture migrations over the years.
3. I've come to the conclusions that some old code bases are really just like quick sand, and they need to be scrapped. The hard question is how to do it. I think the biggest mistake is planning a major "big bang" release. While in some cases that is inevitable, the cases where a big bang is truly required are a lot rarer than one might think. From the description in the article I think there is probably a lot that could have been done beyond "we need to do a complete architectural change to get SSR". The primary problem is page load time. I've seen companies have success by putting up landing pages, which still have valuable info, but also start the download of the large bundle (the whole "it's not the wait time, it's the perceived wait time" that's the problem). Point being I think there are ways to do some gradual improvements while a larger rewrite takes place simultaneously behind the scenes. The worst thing to do is tell the business (or even worse, the public) that our current product is dead-ended but a great new thing is coming out a year later, fingers crossed, which in fairness was a big part of Joel's point.
So there was a measurable problem (large bundle size) that they sought out to fix (in addition to upfront loading time). The first thing to do would have been to _not_ engage in SSR, or Angular 2, or any other big architectural change without first checking if actually properly slimming the bundle would have helped first. Next, how do you proceed till almost ship without actually solving one of the core initial problems you set out to fix? Before porting the universe, it seems like you should at least remove that risk or convince yourself you know how to do it. I'm going to go on a limb and also completely disagree with the conclusion that a React rewrite was the right thing to do. My experience is that engineer morale isn't maintained by staying in framework and rework hell - instead, morale increases when engineers have opportunities to deliver high-value experiences to users. Not shipping is a common and understandable reason for engineers to leave, and if your employees are hankering to leave because the tech they use isn't the current flavor-of-the-month, you may need to reassess your cultural values screened during the hiring process.
I've seen projects devolve like this when everyone is tasked with a part of app logic (the checkout page, the cart, etc..) but no-one is responsible or accountable for the sum of the parts.
Oh you want to rework on the routing or tooling or anything like that impacts other parts of the app? Good luck getting 5 teams to sit down and agree.
I think the difference might be that you knew what you wanted to build. That's usually the bigger issue in projects like this.
The other thing I can think of is that small teams or individuals can often outpace larger teams, at least when it comes to pure software development - in practice, a team handles things like 3rd party integrations, customer feedback, stakeholder management, demos, etc as well.
What to do when your 3 years of work is already written in Shitty React™?
I've been suggesting codebases cleanups but we only do it when the clients complains about severe bugs (which, hear hear, are due to our known core issues)
if this was just to improve SEO, why not just slap in pre-rendering middleware and forgo SSR? like prerender.io or some headless chrome variant w/ cache? honest question, I’m not as experienced with the nuances of frontend dev
168 mb of bundled js? they must've written a fully functioning unix-like kernel too, yeah? or embedded Taylor Swift's 7th album. otherwise, I don't know how the number is as high as that.
This stinks of no-one-knows-what-the-fuck-they-are-doing-itis, a common problem in the software engineering community. When mixed with a deadly dose of sunk-cost-fallacy-itis and project-death-march-itis, the only way out is adding more JavaScript until it creates a singularity from the accumulated mas and sucks the project into oblivion.
Trying to fight one of these off now. We don't need a fancy shit ass UI. We just need stuff that works and is simple. But plenty of one-trick pony developers and architects who build complicated mechanisms out of piles of nodejs and microservices which merely consume time, energy and attention and delivery sweet fuck all ROI.
I think it smells of the common trend in javascript to grab any old package and use it if it scratches an itch. look at lpad(and that debacle). back when i was doing compiled stuff (well even now in scripted land) you'd look hard at whether or not you needed that dependency since every dependency is a liability. and of course you'd manage the dependencies by hand.
That's most modern software development though. Drag any old shit off the internet, dependencies, malware and incompetence included, then execute it as some arbitrary user with full access to your mission critical data and an outbound network connection. Maybe if you're big enough to have a security or compliance guy they will at most want you to buy in something that does a half assed attempt at tracking dependencies after it's too late or intercepts traffic pointlessly on the way out crippling your business inconveniently sometimes.
I tend to just use whatever Debian ships with package-wise when I'm doing something for my own purposes. People laugh at me. Their funeral.
Heh, it's fun doing SCA and SBOM these days and having the report generation break because the servers run out of ram building the list of everything the devs included. Then the dev team comes back and says it's impossible to run the application out of ram, they'd have to include thousands of modules and there is no way in hell you could keep that application working over time and manage to audit it. Then you show the devs the trace logs for the error and they shudder in terror.
This is due to a long time of the standard library being seriously lacking. Even today, group / groupToMap still aren't standardized, nor are iterator methods. It used to be even worse though.
Very true. This is one thing I like about Go. The standard library is very complete. I can do most things I need to do without having to pull in any external dependencies.
This is so funny. I feel like in the old days it would be called out without remorse, like an old hand putting down a maimed horse. Nowadays you have to tapdance around the issue to such a degree that you look insane to try, people will just spout jargon longer than a ducks dick and your manager will sucker down.
Good luck with that. I'm one of a handful of people on a team that maintains a native iOS app and the powers that be want to transition it to be a minimalistic container for a React web app so they can "just design it once and push changes without needing a separate App Store submission". I can fight that only so long, and then we need to let them do it and prove to themselves and every user that the UX will suck. The best they can hope for is mediocrity.
Probably bundling the server side dependencies into the client. I’ve also seen this happen when people add uncompressed 4k png images and the build tool is configured to inline all static assets. Obviously there was a lack of domain knowledge in the company or this wouldn’t have happened.
What I understood from the post was that it was only 168mb because tree-shaking didn't work on whatever version had support for server-side rendering. With working tree-shaking the bundle these developers were working with during development would be considerably smaller.
Wouldn’t be at all surprised if no one was paying attention. Chrome on a top spec MacBook can chew through 100MB of JS without thinking about it. Someone on an old machine is screwed but hey, “works on my machine”…
Author here. At the time, Angular relied a lot on the AOT compiler and tree shaking to keep bundle sizes down. No idea if this is still the case.
If we built the app with the stable branch the bundle size was orders of magnitude smaller: less than 200kb. Still a bit of a chonker, but more reasonable than the ridiculousness the experimental SSR branch spat out.
If it's not like... large language bundles or images or whatnot, I suspect it might be a lack of technical oversight and everyone just adding their favorite library.
It was Angular. It may have been served by Node, but Node wouldn't have been included in the bundle (unless something had gone terribly wrong, which...I guess is possible, given the article?)
Because they're not a multi billion dollar company that can pay for legions of developer to make sure it works both with and without JavaScript? I'm all for supporting the JavaScript disabled, but it shouldn't need to be explained that developer time is a limited resource.