At their best, Single Page Apps (SPAs) can rival and even exceed native mobile and desktop applications for value they provide to users. Modern browsers are incredibly capable, and open-source tools and frameworks promise to put slick web apps within reach of even the smallest teams. However, many product teams struggle to maintain and improve their single page apps. They can be slow, buggy, hard to use and resistant to change. This is bad for business. We'll explore how this happened and suggest some approaches product teams can take to shelter themselves from trouble and develop a healthy relationship with their apps.
How to Survive the Single-Page App-ocalypse








































































Auto-generated transcript - may contain errors. Tap a timestamp to jump the video.
I'm gonna stand here. I've been told I should stand right here because of the camera and the lights. So I'll try and do that. I also realized this morning that I'm up against Scott Berkin in the other room. Who who knows who Scott Berkin is?
Anyone? Oh, that's good. You're all the all the people here are the people who don't know who Scott Berkin is. That's really good. He basically Scott Berkin wrote the book on how to do public speaking, which is a really good book. So, if you're interested in public speaking, you should check it out and maybe give you a couple minutes if want to go and check out his talk.
Okay. So as Rachel said, I'm Jim Newberry. I'm a consultant and coach and I try and help B2B SaaS companies with their UI engineering and to build sustainable web apps. And as part of this work, I've seen a bit of a common pattern that we're going to talk about today, the subject of the talk.
But before we start, I've been asked to give you a little bit of a safety briefing. So I'd like to draw your attention particularly to this last point. A lot of the stuff in this talk is my own opinion and based on my own experiences.
And of course, makes up for anecdotal evidence. But what I've done is actually to provide lots of charts and graphics so it gives you the pattern of wisdom and data that isn't actually there. So one of Scott's bits of advice in public speaking is to start with a controversial premise.
And so my controversial premise is I believe that single page apps damage businesses. Now, course, like a lot of controversial premises, there are plenty of caveats here. And but it's been pretty clear to me over the last couple of years or so that there is single Certain businesses do seem to struggle with the single page apps that they've built because they go into and without kind of realizing the extent of the work that's required to keep them going and actually make them into a quality product.
So when we talk about single page apps, we often use Google Maps as the canonical example. And of course, it's been around for a long time. It has an incredible set of rich dynamic features. It's got a long history. And of course, it's Google, there's a big team behind it, and they've piled a huge amount of investment into it.
And when we talk about single page apps, we usually define them in terms of the characteristics they have, the shared features, if you like. So the main idea being that they provide this application like experience, it's intended to compete with native desktop and mobile applications.
Can move forward, we can do that by dynamically changing parts of the page in place. And we do that by getting data from an API and persisting data back to the API. And we use client side routing and history management so we can retain some of the best features of the web like URLs and deep linking and so on.
This is achieved by bundling up static assets of JavaScript and CSS and delivering those to the browser, at which point the browser parses those, takes over, and runs it as an end to end application all in the browser. We might think Google Maps that single page app products is going look something like this.
This nuclear bunker has got two floors of luxury underground accommodation that go with it. It's got your own private plane and airstrip, and of course, you've got your own personal missile so as in case you need to take part in nuclear warfare yourself.
But unfortunately, the reality of living with a single page app for a lot of businesses can feel a bit more like this. So it doesn't really fulfill that grand it's pretty hard to live with. And despite those appearances, it can be a surprisingly expensive experience and resists our efforts to change it.
Okay. And what's more, most business apps at least are really nothing like Google Maps at all. In fact, they're pretty cruddy. And that's to say that not bad, like buffer here is not a terrible app by any means. But really that the UI is based around creating, reading, updating and destroying data.
And the UI that's built around that is also can be pretty simple. So the question I have is like what's the value that we're really providing for users here with these things? What's the real benefit and why is it that businesses go all in on these things?
So in the name of rigorous research, I asked Twitter about this and specifically tried to call out what are the specific benefits for users. And of course a lot of my followers are developers and people in more on the tech side of things.
So, it's kind of natural that a lot of the responses were more around those characteristics that we talked about. So, fast transitions, optimistic rendering, long sessions, background fetching of data, interactive elements updating on the fly. All of those are kind of the features if you like.
And some focused on the developer benefits or organizational benefits. So in this case because most of the code now runs on the client, hosting costs can be reduced. And this one is a genuine user benefit if you want to call it that even though it's kind of tongue in cheek.
It was actually the only response that highlighted a genuine user benefit. So, think it's worth talking about what these user benefits actually are. And I think we make some assumptions about them. So, first of all, of very broadly, we imagine that we're creating a better user experience.
So, and I think this boils down to the fact that with a single page app, with a rich app, you can really model your user interface and your user experience more to how users think about tasks that they have at hand. You're not constrained by this page and document model that we were maybe in the 90s.
And of course, are some rich and interactive tasks that just aren't possible with any other approach. And secondly, we also imagine that there's better performance that can be had from having a single page app or more accurately better perceived performance. And I think this one's quite interesting because it's actually really hard to compare the performance of a single page app to that of a more traditional server rendered app because really they're very different things in terms of interaction.
That you can't really do a like for like comparison. The comparison is really more between those native apps that we talked about and the single page apps. And finally, of course, it's still the web or it should be. And so we can continue to use the best features of the web.
So we talked about URLs, deep linking, sharing and so on. But of course there's the universal access of being able to provide our applications across any device that has access to the internet. And we can also take advantage of all the modern web technologies that have been made available recently.
Unfortunately, none of these benefits are actually guaranteed, which is a shame. But they depend obviously on our execution as a team. And the truth is the single page apps are pretty difficult to get right. So anyone who's worked on them knows that you can kind of get started quickly but really getting them to that level of quality is actually quite a difficult task.
So we can illustrate that and what can happen with that completely made up data that I talked about. So if you compare the journey of developing a single page app with that of developing a server rendered app, I think it feels sometimes a little bit like this.
So you can plot the effort on the x axis that your team puts into it or really the complexity that you're adding to your system against the value on the y axis that you're providing to users. And early on, feels like you've taken those React tutorials and it seems quite easy to add lots of features, which is great.
But then a few weeks or months down the line as you're adding more and more stuff to this application, it feels there's suddenly a lot of friction that the app is giving you and it's quite difficult to add more value. And you really need to push through that to get to the point where you're really getting those user experience gains and performance gains so that they can compete with native applications.
And unfortunately, for smaller businesses and smaller teams, can be really hard to get to that point because of things happen in your business, the business changes priority, the team gets moved on to other things, or you just hit a deadline. And so that means that you end up kind of stuck in middle period for longer than you would like.
So we're going look at how we kind of get into that mess as well in a bit more detail. And I've chosen three the kind of top three mistakes that organizations make when trying to build single page apps. You you can call them the three horsemen of the apocalypse if you like.
I would have chosen four, but of course, we know that the fourth horseman is death. So that's probably not appropriate. So mistake number one, and I've seen this an awful lot. We tend to under invest in front end skills, JavaScript, CSS and HTML.
You've probably all seen the jokes around full stack development. This one is nice and succinct. Now, think this is a little bit unfair, but there is there does seem to be a pattern of kind of general underinvestment and over optimism that we can hire full stack those full stack developer unicorns, those true, you know, amazing people that somehow can do equally good work across the back end, front end.
And we can look at this kind of in the light of how web apps have changed over time. And there's this law called Tesla's law of the conservation of complexity, which I unearthed not long ago. This date backs dates back to the nineties.
That's not this Tesla or or this Tesla, but this guy. So this is Larry Tesla and he's an interaction designer who's worked pretty much every big tech company going in the West Coast since the eighties. And his law states that every application must have an inherent amounts amount of irreducible complexity.
And the only question is who will have to deal with it? So visually, if you have a box representing your bit of functionality or your entire application and the capabilities that it provides, you can then think about how you would distribute the complexity around the people involved in it or the parts of the system involved in it.
So for early web apps, we really didn't have a lot of choice about this. Browsers weren't particularly capable. They could only do a few things. And as a result, front end development was also fairly straightforward. We took some complexity into the back end in order to be able to deal with data and form submission and stuff like that and databases.
But really the users were taking on quite a lot of this complexity because at the end of the day we could only provide them with a big long fat form and then they had to submit that and then we render something horrendous back to them and then image maps, all that stuff.
We take a little bit of a detour into Flash apps. These really took a lot of complexity into the Flash application itself because the web platform wasn't particularly capable at the time. And so Flash as a plug in provided the ability to provide rich user interfaces, which simplified, theoretically simplified the task for users and really minified the involvement of browser much more.
If you look at kind of web apps from maybe ten, fifteen years ago around the period when Ruby on Rails, things like that started getting really popular, PHP, then again the back end takes on a little bit more responsibility. There's a bit more front end stuff as libraries like jQuery started to emerge.
But again, there's still some complexity that the users are having to take on. Now with single page apps, it's changed again and the front end has become more and more complex over time. Even to the extent where we've started to take features that are inherent in the browser like routing and history management and putting those in our front end applications.
And the problem is that doesn't tend to get reflected in the capabilities and the balance of skill set in the team where we're kind of still stuck in some cases with the balance of skills from ten years ago. And I like to see the term full stack used in the context of teams rather than individuals.
I think that the term full stack developer kind of emphasizes individual contributions. Whereas the team level, I think if you've got a full stack team and there's a nice balance of skills across different people, I think that's a much healthier way of looking at it and makes hiring quite a lot simpler as well.
So mistake number two or horseman number two. We all know this epithet of course. I kind of like the way the meaning of this changes depending on how you say it. So you can When Facebook came up with this, they they were kind of positive about it.
Said you can move fast and break things. It's amazing. But of course, as developers, the experience of this is often we've moved fast and we added loads of tech debt. And of course, with single page apps, they make it quite easy to move fast earlier on and add a lot of tech debt, at which point then you find yourself struggling to move fast as well.
So kind of what I mean by this, again if we look at the distribution of complexity. If we imagine an MVP which is pretty small, so it has kind of an, I should have made a narrow version of this. You might be happy with a single page app MVP that you've built.
And of course now you've got funding, so you can add loads of people to your team and build out loads of new features. And then you end up in this situation where you've added loads of complexity to your system. And this is kind of often at the point where teams start to struggle in this middle period and they kind of wonder what happened here.
And a lot of this problem I think is created by our naive development practices on the front end where we're still to a certain extent catching up with a lot of the software development practices that have been developed over the years on the back end.
And it can be tempting to fall into those collective bad habits as a team. So those include things like poor test coverage, highly coupled code, over engineered solutions resulting in these kind of big monolithic single page applications. And as a result of those giant static asset bundles, which means we're kind of shoving the problem into the user's device and causing lots of issues there.
As all of these things kind of add up to a threat to those three assumptions that we made about what we're actually providing to users, the problem being that we're threatening the user experience, that perceived performance will be threatened by the fact that these giant bundles that take a long time to pause, particularly on mobile on less powered mobile devices, which is a a real problem at the moment.
And even to the extent that we might stop using a lot of those features of the web just to ship some of those features that we're really interested in. What's more, a single page approach can be really overused. So in the context of a single application, if you divide it up into various capabilities or features, The question you might ask yourself is do we really need to use this approach for login and account management?
De facto, what tends to happen is that we choose the same de facto approach across the whole capability of the application which can be quite expensive because we're creating a situation where that complexity compounds. So finally, the third mistake is to kind of build on the first two.
And this is really where we kind of make the situation worse over in more of a long term product development scenario. So there's of course there's plenty of hype around JavaScript application frameworks. Weirdly not so much from the authors of those frameworks, but from the community itself.
So hands up if you recognize all of these logos. Anyone? That's pretty good. I'll buy everyone a beer afterwards so you can recognize all of these ones as well. These are kind of the B series, I guess. Now, as developers, we love to talk about the relative pros and cons in these things.
And this happens day in day out in on Slack channels at work, on Twitter, on Reddit, you name it. It's all over the place. And that's totally fine. And I enjoy kind of taking part in some of this debate myself. But there is a danger that we kind of we you that we get overawed by this debate and we fail to see some of the important characteristics that in some cases more important than the choice of technology or the specific technology.
So when we're trying to deal with an app where we find ourselves in a difficult situation with the application that we've created, it's quite easy to blame the tools because of the volume of this conversation that's going around. And we also have to deal with the Gartner Hype Cycle.
So the Gartner Hype Cycle, if not familiar with it, this plots the stages of a technology's visibility over time. So when new JavaScript framework is released, if it does well, it will reach a peak of inflated expectations. And then as more developers and people actually apply it to various different problems, they may realize that it's not quite quite all it was made up to be initially.
And then over time, the tools will be improved and work will be put into it and people will develop best practices and good and good patterns for using it. And then eventually, it will reach that plateau of productivity where it becomes boring technology.
So things like PHP. And I wonder how many teams get to this point in Gartner hype cycle for a JavaScript application framework just as something else comes along that starts to tempt them away. And so this is we've seen this over and over again, right, in the JavaScript community.
This is kind of what's happening now with with React and Vue. Although I would argue that maybe the timeline is starting to stretch out a bit. And of course, we cry this time it's gonna be different. So, the new framework that we see will save us from this terrible legacy crow base that we've created for ourselves.
And unfortunately, when we look at it and we see look at this new framework, we don't know whether it's we're gonna be pouring petrol or water onto this fire. And in the very worst case scenario, and I'm describing a scenario that I've probably created for myself at least once in the past.
In the very worst case scenario, this is what happens when you optimize for the developer experience. So you if you just keep riding that that wave of developer happiness and hype, then you're gonna be creating a lot of expense for the business. Because what you're doing here of course is really mucking around with the complexity that's already there in the application and kind of replacing it and not doing anything about the user value that's already there.
By the way as well, you might end up quite easily leaving crumbs of the old framework in place. It's quite difficult to replace an entire application and replace the framework if you're doing it in place over time. So it's easy to end up with a situation where you might have all of these things in your code base if your product is big enough.
So of course, we're of forgetting through all this that it's not the frameworks that are making the apps for us. It is of course the team that you have, your product team that is making those apps using the tools that we have. So how do we correct these big three mistakes?
How do we maximize that value whilst minimizing the complexity and the cost that we we already have without completely scorching the earth. So just as a reminder, think if you were here for Maria's talk, I think she was clearly kind of emphasizing of the important things you need to consider in your team before you consider taking big steps to change your technology.
So firstly, has your product vision changed? Is it still something that you when you've originally built your app, has that product vision now moved on to something else? Are you aligned on that product vision as a team? And are you also aligned on good outcomes for users?
So Maria talked about that. Do you have good communication practices in the team and you provide a safe psychological space for people to have differing opinions that you can listen to and take into account. Do you have the right skills and capabilities in the team?
We talked about that a little bit. And do you go about things in your development and coding practices that are sustainable rather than just practices that enable you to get the next feature out of the door? And do you actually know what your product does?
Now, this one's quite surprising if you but if you've learned if you've ever worked on a long term product development, you you probably realized how easy it is to collectively forget what your product does in detail. So that can be caused by things like team turnover, poor documentation, and just time.
So you might forget about all the little bugs that you fixed. You might forget about some of the some of the little bits of user value in there, but but even coming back to an entire feature that you've left alone for two years can mean that you're basically coming in completely new.
So inevitably, once you've hopefully got all of those things in place and you start talking about technology decisions, the very first question that usually comes up is, should we rewrite this thing or should we refactor it, rework it? And this is the number one question that I get asked as a kind of opening gambit without any context.
It's extremely difficult to answer. But I'll try and give you a two minute answer. So first of all, look at the difference between the two as I see it at least. When you rewrite from scratch, you're taking a top down approach. So this is when if the product has changed direction and vision, then this is something you may have to do because you have a fundamental change in direction anyway.
But it involves a branched development practice. So either in a completely new project or a long lived branch off your existing project. And because of that, you have a long release delay so that it takes a long time to actually get in front of users, which in itself is extremely high risk thing to do because it takes a long time to get that feedback and understand if it's the right thing to have done.
But also, there's a potentially high reward here by doing it this way. Rework on the other hand is much more of a bottom up inside out type approach where you're retaining the existing functionality. And usually the work happens on trunk or near trunk and you're incrementally releasing and merging stuff back into trunk as you go along.
And because of that, it's much lower risk. You're getting in front of users and getting feedback. And also potentially because you're working with the existing products, there's potentially a lower reward there as well. So these are the reasons why there's kind of a balance here.
You might even be able to take a decision that's somewhere between the two things. But for me, I like to look at this through lens of lean software development principles and in particular the principle of amplifying learning. So when you rewrite completely with a new framework and start from scratch, really what you're doing is deliberately forgetting all of the learnings that you've made in the course of writing of developing your product in the first place.
Now, hopefully, will be able to pick up those learnings again as you go through and and rewrite existing functionality. But at least in my experience, there's no guarantee of that fact. And sometimes that can come back to bite you later on when you realize that you've not replaced some bit of functionality that users actually found very important.
On the other hand, a rework requires you to learn about your products. So, if you're in that situation where you've come back to something that's been left alone or the team has had some turnover, a rework actually means that you have to go in and do the dirty work of understanding the product from the inside out.
And that is actually extremely valuable. It feels really horrible and painful and it's a lot of hard and tedious work to do it. At the end of it, you'll have a team who has a deep knowledge of the product. The importance of that really can't be understated, I think.
When you're deciding between these two things, hopefully that gives you some feeling for how you might make that decision. Finally, a little bit of tech advice given that we've only got five minutes left and this is an engineering track. Unfortunately, when teams try and rework single page apps, they discover that it's maybe not quite as easy as they would hope depending on on the situation of the application itself.
And I think that's partly because single page apps single page apps up till now really encourage this monolithic approach to things. It's very easy to get into a situation where you have a lot of coupling and it's hard to break out components and parts of your application.
But taking your time to do that and divide it up into much smaller simpler applications is a good investment if you can do it. So, to start with the first thing we need to do is really protect the value that we have in our application.
We can do that by using characterization tests. So, this is something that Michael Feathers talks about in his book called Working with Legacy Code. And the idea here is that you create really dirty loose tests that test the system as a whole. So, tests, but they're really kind of they're intended to be throw away and you're not supposed to keep them around for too long.
The next step is then to start pulling out individual applications from the existing code base. And how you divide this up can depend on the product, but you can do it by individual audiences. So you might have different roles or different audiences in your product.
You might have you might decide to do it by URL route or you might have a a clear series of defined tasks that users have to do with your application. There's various different ways of cutting that. And it all depends on the individual application.
And then finally, hopefully, end up with a situation where you really have these kind of self contained applications and some kind of base layer of like communication layer that means you can still communicate between them when you need to, but they don't depend directly on each other to do that.
That means you can test them individually, all that kind of thing. But it also means that it makes it a lot easier to eliminate waste and focus really on where the waste is in your application. And of course, this is another lean principle.
Really what you're trying to do here is take these regular small steps over time beyond this kind of initial big restructuring if you like. Then you can take a much more long term extended approach to eliminating the complexity in your application. So, saw before how choosing the same approach everywhere can be a bit overkill.
If you've taken this approach, you can kind of modify some of the complexity balance a little bit. So, you can really double down on that on those features that really get the best benefit from having a complex JavaScript application behind them. But things like login and account management, maybe you can simplify a bit and accept that it doesn't have to be super busy in the same way.
So, the question that you can ask as you go through this in your team, as you're planning work and as you're planning some restructuring work like this is to think about what's the simplest way to sustainably add and maintain user value. And I think this question like answering this question well is vital for long term product survival and sustainability.
So the aim really is here for you and your team to learn together how to live with your products not just to keep piling on new user value and not think about your long term ability to sustain that. So, like all relationships, you need to invest in nurturing to keep it healthy.
And finally, if you are I've described a situation where you have an existing product. If you are just about to embark on something brand new, then please remember it is totally okay to use single page apps, but it's also okay not to. And it's also okay to mix them to mix and match them together.
The tooling now on the front end is amazing with things like build build tools, code splitting, things like that. It makes it much more flexible these days to to make individual decisions in different parts of your application. Single page apps didn't replace other approaches to building apps, and they can certainly coexist in the same product.
So, good luck if this is you and you need to do this, and good luck. I'm not seeing the slide there, that's weird. I have a final slide and it says good luck. If you do want to contact me on Twitter, then please do and ask me any questions about this.
Thanks very much.