18 ms·
SPAs are harder and always will be (2013)
- sillysaurus3 9y agoI'm pretty convinced that rather than shying away from SPAs (which is totally fine), we could solve this with an extra layer of abstraction. Consider the Unreal network architecture: https://docs.unrealengine.com/udk/Three/NetworkingOverview.html https://docs.unrealengine.com/udk/Three/NetworkingOverview.h... When Tim Sweeney needed to make an engine, he didn't simply hardcode each of the tasks: Update position, update velocity, play animation... Instead, he created a system that allowed those things to become implicit. They synchronize themselves across the network by default. There's no special logic required. So when I look at SPAs, I see a similar sort of situation. Rather than hardcoding each of our endpoints, why don't we come up with a system where we can synchronize some variables from the server to the client? Then adding some new data is as simple as declaring a new variable. No need to create an endpoint for every single thing. This is vague and handwavey, but there's an underlying idea here worth examining. It seems like we could leverage abstraction in a way that unifies these systems (as opposed to simply shoveling another layer of abstraction on top of the current pile). Has anyone been working on anything like this?
- faitswulff 9y agoLike Firebase? https://firebase.google.com/ https://firebase.google.com/
- sillysaurus3 9y agoI meant aimed specifically at SPAs. Firebase is nice, but it doesn't really help reduce code bloat on the front end. E.g. if you're making a react app, your instinct is to reach for redux + reducers, even though that means dozens or hundreds of lines of boilerplate code.
- gieksosz 9y agoIn my experience you can/should skip redux if you use firebase-firestore. One good reason is that if you try to use them both, you will end up writing a lot of "mee too" action and reducers that will just wrap firebase update events. It is really not necessary to always use Redux.
- everdev 9y agoGraphQL is a single endpoint API
- intrasight 9y agoYes. GraphQL combined with Relay Modern. Even better, add a GraphQL proxy/ORM onto your RDBMS.
- vvanders 9y agoAs someone who's worked with the unreal 3 engine in a professional capacity I can tell you that there's a fair bit about those systems that are hard-coded. They just look very nice from a 1000ft perspective. There are parts of UE(like the material editor) which are very modular but the networking stack is not one of them. This is not a knock against UE3, more that things are more complex then they first look.
- m_fayer 9y agoSounds like MeteorJS.
- jstimpfle 9y agoI don't really want to contribute to the vague-ness of the discussion, and one failed SPA project is all that I can pride myself of: I'm sceptical this can be done. The synchronisation unit is the transaction: What subsets of data must be updated atomically, which business rules apply before the data can be committed, what chunks of data in the UI should be as updated as possible when an editing form is presented to the user. This requires thought and specialized code (structure). Not saying that every form must be coded ad-hoc, but I doubt that a well-engineered SPA can be written by anyone without solid domain experience by just grabbing the next framework.
- hungerstrike 9y agoI'm building an SPA with React and instead of hard-coding each and every form I have a few high level components that take some data and render my forms complete with validation and rules for transforming input back into the store. The web server is configured to respond with the main `index.html` file for any path that is requested. So, using the browser history with JavaScript I'm able to show the user any URL and dynamically render the page for it. The only endpoints that I need to define are for the API server. If I wanted to, I could make the client completely dynamic. Although I don't have time for that right now, it's not a far leap. So, I expect systems like this are coming.
- bpicolo 9y agoIt's quite different in games where what you want to sync to users is just the global state of everything at a hard-defined frequency (10, 20hz, whatever), with well-defined heuristics like planar distance from a character. That's not what you want or what you get in web apps.
- tfb 9y agoWhat you're describing is called "replication" in Unreal Engine. It helps tremendously with writing declarative code, and I've found it to be exceptionally powerful and predictable. I love this architecture so much that I brought it into the world of React and Redux a couple years ago (see https://github.com/loggur/react-redux-provide https://github.com/loggur/react-redux-provide and https://github.com/loggur/redux-replicate https://github.com/loggur/redux-replicate). Dan Abramov and the ReactTraining guys immediately shit on it for some odd reason (I probably did a horrible job of explaining it), saying it wouldn't work in the real world, but I (and my team) have been using it very successfully... in the real world. With that said, I do need to update the docs and improve some internals (and remove some unnecessary stuff like query handling), but there's only so much time in a day. :)
- ljoshua 9y agoThese are fantastic technical reasons when considering a SPA vs. a traditional server-side app, but to me the largest consideration, outweighing other technical decisions, is the overall experience the end customer is going to need and expect. Migrating from a desktop-based application to a web version? That desktop version was likely extremely responsive, and full page loads may feel like a step backward. Does the application require constant, fast interaction, such as data analysis, frequent order entry, or highly dynamic UX? That's the domain of the SPA. But if the situation is more of a request/response scenario, then a traditional server-side set up works wonders. The technical difficulties surrounding SPAs vs traditional are for the most part solved. It does require more overall work, but that gap is shrinking. Therefore, IMO the largest deciding factor should be user expectations, and that can go either way.
- purerandomness 9y agoThe problem is that most SPAs today are cargo-culting. They break middle mouse button (or Ctrl-Click or whatever your favourite "open link in new tab" shortcut is on your Apple computer), at the same time break browser history, and at the same time make you wait for any single interaction you're doing (show spinning wheel for 6 seconds before opening a confirmation modal) The ideal solution is a) minimize server roundtrips (<100ms) and b) reload parts of the site via AJAX where it makes sense. No need to shovel 7MB of JavaScript to the user.
- bastawhiz 9y ago> They break middle mouse button (or Ctrl-Click or whatever your favourite "open link in new tab" shortcut is on your Apple computer), at the same time break browser history, and at the same time make you wait for any single interaction you're doing (show spinning wheel for 6 seconds before opening a confirmation modal) I am not defending SPAs, but the points you've made are not indicative of SPAs, they're indicative of bad software. This problem existed before SPAs were a thing. Remember ASP.Net pages where the whole page is wrapped in a giant <form> and you couldn't use the back button most of the time? This problem also doesn't exist with properly built SPAs (e.g., by using <a> for links, using the history API correctly, and designing a sensible UX). And certainly, if your app is sending 7MB of JavaScript over the wire and it's not a video game, something is very wrong--SPA or not.
- rb808 9y agoCertainly though SPAs are overprescribed and old fashioned template based sites work great for many projects. But I think for many enterprisey platforms its likely the opposite, front end design logic is likely done by a different team to back end data provider so its a natural split that is more effective than a server generated page. Not to mention most back end devs suck at design.
- wvenable 9y agoNothing gives you a more cohesive design than splitting a project right in the middle and giving it to two different teams. /s
- reaperducer 9y agoAs they say, an elephant is a mouse designed by a committee. An appropriate aphorism, considering most ASPs are full of javascript bloat.
- nawitus 9y ago"But if you're building an app that honestly is only going to serve 10 people, or 100---or 1000---do you really want to incur higher development and maintenance costs just for the sake of pushing the user-experience envelope?" Yes, because modern tooling makes it pretty much as easy.
- Sujan 9y ago(2013)
- deleted 9y ago[deleted]
- sctb 9y agoThank you! We've updated the headline.
- matte_black 9y agoDisagree, but if you can’t take the heat get out of the SPA business. *Ah, I see this was from 2013, makes sense. I wonder if they still hold the same opinion today?
- atoko 9y agoIt's not that there's an additional layer, the rendering of the view was always there, just tightly coupled to fetching data from the DB. It is now a better practice to create a BFF that can serve more clients than just browsers.
- weberc2 9y agoIt's not tightly coupled to the database, it's just not on the browser. And because they aren't tightly coupled, you can still make the renderer the client of your REST/gRPC API just as you would the browser. Or it may be more practical to have your non-browser clients talking to your API while your renderer talks directly to the database.
- atoko 9y agoYour second choice is just coupling it again. I've only seen few frameworks that let you render both HTML and json (Ruby on Rails). You still have to map a model to HTML, regardless.
- weberc2 9y agoYes, that's my point. Decoupling it for the purpose of supporting multiple frontends may not be more practical than leaving it coupled and providing an API for other frontends.
- shams93 9y agoFor webrtc apps you really need a SPA, currently I use vue2. If you leave the page you lose the session. There are other html5 APIs that are also much happier within an SPA, like webmidi and webgl. But for text based crud apps rails is still the best way to go. Or express and ejs. If you're not using advanced APIs turbolinks is often a better way to make your app spa like within incurring spa pain.
- Daycrawler 9y agoThe answers to the first difficulty are called "Universal Rendering" and "Isomorphic Rendering". Universal Rendering will render the page at any URL server-side, then the client will render other pages from there. Isomorphic Rendering is a special case of Universal Rendering in Node.js apps where the same JavaScript code is used to render pages in the client and the server. Anyway, the article is right. Of course presenting users the current state of things in real time and allowing them to mutate this state in real time will always be harder than issuing requests to query the current state and requests to mutate the current state. It'll always be harder because it's way more complex and powerful from a user perspective.
- bpicolo 9y agoThis is why I'm a fan of having both - no need to limit yourself to one or the other Data heavy pages with little or no interaction? Statically render it. Admin pages, terms of service, etc. Writing endpoints and serialization to move the data is a waste of time. Sure, you might have to maintain two separate sets of minor components (header nav and such) but it's well worth it the lessen the development cost of non-impactive pages. Can also get away with loading HTML partials from the backend and throwing them into the dom whole - the perfect case for __dangerouslySetInnerHTML or whatever, then you can reuse your nav and such
- throwaway2016a 9y agoThe article had me confused until I realized this was 2013. Even then it is out of date. Muli-Page applications have had business logic on the client-side for years as a technique to reduce the feeling of latency since at least 2005. If by "Traditional" web apps you mean web apps from the mid to late 90's, sure it was done entirely with POST and no business logic at all client side. At the very least data validation has been being done client side for s long as Javascript has existed. (and also server side as a second level of checks if you care about data integrity and security) SPAs did not appear overnight. They are a logic evolution of what has been happening for years.
- Udik 9y ago> sure it was done entirely with POST and no business logic at all client side Even if you don't have business logic on the client side, you still have a state: tab position, state of controls, etc. These are not part of the data you really care to store on the server, and yet they have to be sent there at each and every page reload, as they might be needed in order to build the response.
- gedy 9y ago...but much easier and maintainable than a "server-side" webapp that is a mess of jQuery, etc layered on top to make the experience "interactive". Not to mention the ease of unit testing user interface code in SPA.
- brightball 9y agoIf people could get to a point of saying: This system benefits from being an SPA... This one does not... 99% of the problem goes away
- tomca32 9y agoYes. So much wisdom is so simple. There are apps that benefit from being SPAs, your google maps, and the like. Our CRUD app is not one of them, but here we are still with React, and Redux, and Mobx, and ...
- jorgeleo 9y agoAnd... nope! 1) Hard and easy are relative terms, You feel it hard because it is foreign to 'you', not because it is intrinsically hard. If it seems hard to you then get comfortable with the new pattern, or create a pattern that is more familiar to you, but please don't tell me this is hard because I have to write more code or because there is one more thing that you have to know and maintain. That is not hard, that is been laaaaazy. 2) The 2 points become irrelevant if you do SPA using server rendering. To give an example using C# and MVC: I have 1 javascript function with 0, I repeat: 0 business logic. All my MVC methods return a partial view with a tag saying where it goes. The javascript function does an AJAX call to the controller and on successful return it looks for the tag, and do a $('#' + tagvalue).html(partialView). All the business logic is on the server, all the drawing is on the server, all the validation is on the server. The only UI validation logic is the same one that you would write in the case of non-SPA. There is no data synchronization because the server manages the data. The browser gets reduced to a pretty HTML document display, which is all that it is. SPAs are not harder, they never were.
- seekbeak 9y agoI need to get into server rendering more. I find myself doing double validation these days and server rendering could solve some of that. I validate client side, then again server side to make sure people aren't throwing garbage at my API.
- brucephillips 9y agoYou don't need server rendering to avoid double validation, right? Just validate on the server, and return error codes that the client can render.
- neosavvy 9y agoI'll agree that SPAs are a bit of a departure for folks who have been building legacy ASP.NET or JSP / Java Request / Response apps. There are some new things they must learn, so they may have a higher learning curve. Additionally the technology is really unstable. The build tools for example (webpack, babel, gulp, grunt) have changed tremendously and in breaking fashion now drastically over the past 4-5 years. Lots of legacy technology has stable tooling and so a more "seasoned" programmer may be a bit put off by that. Maybe that's this guys's problem. He should Green Egg's and Ham this mofo and just "try it" earnestly before writing a total dump of a blog post and sharing it on Hacker news.
- JepZ 9y agoWell, I think that many people are not aways that SPA != SPA. Actually, SPA means that the site never does a full page reload, but apart from that there is very little defined about SPAs. You can build them with fluid 60 fps interfaces or with server side HTML rendering causing huge delays. You can add aria attributes or render everything within a big canvas. Its still a SPA. So no wonder there is so much disagreement about SPAs. A first step towards a more defined and reasonable term is PWA as the term requires the use of some specific technologies (HTTPS, ServiceWorker, etc.). Nevertheless, it is still very broad. For example what happens to an PWA when the server is not available anymore? Does it keep running forever? Not defined, so some do others don't. I really like well made PWAs, but in general most of them have a too strong server dependency (in my opinion). I would like to download a PWA on day X and install it on my PC 5 years later and it should still work (as other software does). As the old server might not be available anymore, I would also like to enter a new server in the settings. The technology behind PWAs would allow such use-cases, it is just not that simple to use nowadays.
- dane-pgp 9y agoThe article helpfully considers the issue of logic being duplicated across layers, and questions the choice of potentially unnecessary layers of business logic being in the architecture at all. I wonder, though, how this changes in a modern world of web services like Amazon's, where your web host provides REST APIs to talk to your database (e.g. DynamoDB), and you can serve your SPA as static files out of an S3 bucket, not needing to worry about server-side code at all. Taking out the server layer altogether may not work if you need a specific user auth model which your web services provider doesn't support, but this simplified serverless model has the advantage that attackers can't hack your server code if you don't have any server code.
- Udik 9y agoFrankly I think both reasons given for the supposed greater difficulty of building SPAs are wrong- and that SPAs have been successful exactly because they're much easier to develop. Additional logic tier: exactly the opposite is true. A SPA allows to get rid (almost) completely of the logic on the server, leaving there only a shallow layer of services. While traditional web applications always had the problem of a complex logic layer on the backend, with in addition the need to manage complicated interactions happening only client side (because even traditional web applications couldn't afford an entire page reload for simple things like reordering a table, displaying an error message, etc.). Part of the logic had to be replicated on both sides, with all the problems that it creates. Data synchronization- again, given the fact that the entire state of the application resides only on the client and is rendered only by the client, data synchronization becomes trivial- it's just a matter of calling some backend service to store or retrieve the full state. In short, the problem with traditional web apps is that they've always had the need to manage a state on the client as well as on the server; and the client's state was lost at every page reload, or either had to be sent to the server with some hack to be restored after the page reload. A nightmare.
- jondubois 9y agoThe frameworks that are popular at the moment make it harder. I put together a simple set of frameworks, engines and libraries that let me build real-time SPAs really quickly and easily. I've built a complex production app with it in a couple of weeks and it works really well. I tried to promote it a while ago and those who tried it seemed to really like it but it never became popular. Promoting technical solutions these days is literally impossible if you're not a rock star developer. I don't even care about promoting it anymore. It's my own secret toolkit now. If people want to believe that SPAs are harder to build, that's fine. But I'm going to keep building them because for me with my tooling of choice it's much much easier.
- betageek 9y agoIf it only took you a couple of weeks to build it isn't a complex production app.
- jondubois 9y agoComplexity is a relative term. The app I built has sign up, sign in, password reset, subscription-based payment processing, usage quota tracking, email verification, GitHub integration and supports different account permission levels and it can scale out indefinitely to pretty much any number of machines. I built it from scratch. Also it has fade in and fade out transitions when navigating between pages and all data throughout the app updates in real time... So for example if you do email verification in a different tab, your main dashboard will update in real time. And it only receives real-time updates for pages that you're actually looking out so it doesn't over-fetch.
- _mhr_ 9y agoWould you enumerate the libraries/frameworks/engines in your toolkit? I'm always interested in alternative approaches. Is it https://github.com/jondubois/nombo https://github.com/jondubois/nombo ?
- slackwalker 9y ago> If you need to restrict access to a field (e.g. social security number) such that only certain users can see it, you need the authorization check twice, once when writing the JSON and again when building the HTML. I think the article may have some points worth considering, but in what world should security code for restricting access to display a social security number ever be in the browser? The browser should never get data that it would be dangerous for the user to have access to.
- jrs95 9y agoThis whole extra logic tier comparison doesn’t make much sense to me. The same logic exists on the server side anyways, you’re just moving it to the client. It’s not like making a site without substantial amounts of JS is really an alternative. You generally can’t just do everything with form submissions.
- t_fatus 9y agoOne thing I learnt to love about SPAs is how they distribute responsibilities: obv you get 3 layers: - your DB which stores your data - your backend which access your data, retrieve it safely, and delivers it without having to know anything about the client it serves. - your frontend which handle how / when it needs data, which data it needs, how it caches it. Separation is good, since you can test your API without needing your client, you can test your client code with mock data, you can build different clients (web, native apps, ..) over the same API (and even do not need to build an API if you're using things like graphql)
- cmont128 9y ago1000x this. People seem to ignore this fact, that a lot of times you will need an API anyway (multiple clients), so really adding in the SPA isn't any extra work at all.
- xya3453 9y agoYou created this account to praise your own comment?
- kingdomcome50 9y agoTo be clear, SPAs do not distribute responsibilities any differently a traditional 3-layer MVC web application. You still have: - an infrastructure layer for managing data - a domain layer for enforcing rules and encapsulating data access/management (completely independent of the view) - (optional) an application/service layer between your domain and presentation to provide a common interface for convenience - a presentation layer for handling view semantics a service layer can be very useful if migrating from a traditional app to a SPA because it makes creating your API almost trivial. There is nothing about creating a SPA that makes a 3-layer architecture any simpler or cleaner. In fact, these days it is quite the opposite. You have all of the above systems in your application PLUS another MVC (or MVVM) framework on the client. The entire point of the MVC architecture is to allow for the switching/replacement of the "V".
- jnsaff2 9y agoYea, there's this guy telling us about the biggest SPA in the world (spoiler it's azure) here: https://vimeo.com/156417164 https://vimeo.com/156417164 It just so happens to be the worst UI whenever I need to use it. Just awful.
- nickjj 9y agoMy work flow for a new app is: 1. Use whatever back end framework I know 2. Use server side templates 3. Slap on Turbolinks (because it works super easily with any back end framework) 4. Sprinkle in JS as needed This results in very fast development, very fast page loads and no duplication of things like validations / schemas. The best part is you can use whatever you want on the back end too. I've followed this pattern successfully with Rails, Flask and Phoenix. Screw SPAs (for most document heavy web apps).
- ryanthedev 9y agoconsidering this was written 5 years ago, these points are invalid with today's frameworks.
- cultofmetatron 9y agothats my feeling. nuxt renders a lot of these difficulties moot
- z3t4 9y agoI have a simple rule: If the app requires real time updates and push, then SPA it is, but you can also mix server side rendering with SPA's aka micro services, eg the "chat" can be it's own component. The argument for SPA's is that they perform better, but I don't find that to be the case with all the bloat on real world "apps". Browsers are good at rendering static content, and a server rendered site will perform well even on low end mobile devices. With todays hardware the server can render even the most complexed site in less then a millisecond, and with todays networks the latency, often as low as a few milliseconds is imperceivable and even faster then clicking around in something using a JS framework.
- edmundhuber 9y agoMy takeaway from having worked on both traditional webapps, and SPAs (2 with homegrown frameworks built on backbone.js, and 1 with ember.js): SPAs, being more complex, demand a higher standard of coding and code review to not have eisenbugs. I have seen a lot of effort wasted on making SPAs work, when the customer would have been happier to have a more reliable traditional webapp. In one of these companies, SPA architecture was chosen because the backend was unacceptably slow. Instead of fixing that problem, we adopted more complexity by transitioning to SPA. When I left, the backend was still slow, and the SPA was breaking all the time. It felt like a waste of effort and I would never do an SPA by choice again.
- tarikjn 9y agoAn easier way to reason about the modern web, and port this knowledge from and to native platforms at a minimal cognitive cost, is to think about a web application as consuming from an API or database layer which already enforces authorization and provides authentication, instead of mixing all these things in a single request. Once you do this, the idea of duplicated authorization goes away, as the only thing you are doing on the front-end is error representation (and focusing on the design). Then, you pre-build, or run+cache this same application on the server side to pre-render pages for search engines, first page load, accessibility etc. so that you are actually delivering an application for the semantic Web. Viewed from this angle, it does not really involve more steps, but it does create more separation of concern. This in turn allows more specialization, scaling, and is more secure. You can apply this approach to build very simple pages (e.g. blog consuming data from Markdown files), which are not SPAs, but are very easy to turn into SPAs. So it's not really that SPAs are this hard, it's that the "do everything in one request" thinking is still very pervasive and making it harder to reason about building modern websites in a simple manner.
- throwanem 9y agoI don't want to beat up too hard on a five-year-old article. But in case anyone reading it now might not know better, I want to mention that a lot of the reasoning here is plain bogus. You don't do complex authorization on the client. If your backend is serving SSNs to a user who isn't authorized to see them, you've already lost. Trying to hide them in the UI avails you nothing beyond a false sense of security. Cache invalidation is trivial. HTTP provides, in entity tags, a very friendly mechanism for checking whether a resource is stale without incurring an expensive refetch unless one is needed. Use it. Resolving write conflicts is more complicated, sure - exactly as complicated as it is to do on the backend. It's true that SPAs are differently complex. You're doing work on the client that'd traditionally be done on the server, and with different tooling and not all the same paradigms. But more complex? Not once you understand it.
- autarch 9y agoI agree that SPAs are always harder. For me, there are two main reasons to consider an SPA. 1. It _can_ let you build a much nicer UI/UX. That said, it's probably easier to build an _okay_ UI/UX with a traditional webapp, and it's also easier to build a _terrible_ UI/UX with an SPA. But the upper limit for excellent UI/UX is higher with an SPA. 2. If you are planning to build a REST API for your system, then the best way to do this is to build a REST API from the start and dog food it with an SPA. Otherwise you end up doing a lot of the server side work twice, once for the HTML app and again for the REST API. It's better to bite the bullet and _just_ build the REST API server side.
- sova 9y agoYour first point is dead on but your second point is way off and I would actually say the harder point is SEO. My clojurescript app is excellent at keeping front end and back end perfectly synchronized across many clients. However, my ability to generate pages that can be SEO'd is not as easy.
- linkmotif 9y agoBeen watching this thread all day and I’m dumbfounded no one has spoken up for React with a modern router like found[0]. Once you learn to use these things, making an SPA is really nice, and you can easily introduce universal rendering which takes your SPA to the next level by rendering it on the server. I find it strange that people talk like server rendered pages with progressive enchancent a la 2013 aka Stack Overflow aka GitHub are easy to make and maintain. It’s 2018 and when you close an issue on GitHub the count doesn’t change until you refresh the page. It’s 2018 and when you go back on Stack Overflow the alerts you just dismissed are suddenly unread again. These are companies capitalized with hundreds of millions of dollars yet they are incapable of making server rendering with progressive enchancement work. It’s not their fault, it’s the technology, it’s busted. Yet for some reason people are lauding server rendering as effective and desirable and capable of producing rich UI that’s sane to build and maintain. It’s not. It’s unmanagable at any scale. With React etc in 2018 all of these problems have been solved, and as I said above, the SPA is not even something to argue about anymore because you can render your app on the client or the server. This whole article is moot. All these problems have been solved and the solutions are free for anyone who has the interest and bandwidth to build products like it’s 2018. [0] https://github.com/4Catalyzer/found https://github.com/4Catalyzer/found
- subsection1h 9y ago> I’m dumbfounded no one has spoken up for React with a modern router like found. You're dumbfounded that developers aren't powering their companies' multi-million dollar websites with tools that have a bus factor of roughly one[1][2]? A couple years ago I was handed a web app built by a team that had used tools with low bus factors. Many of these tools had been abandoned only months after the team starting using them! [1] https://github.com/4Catalyzer/found/graphs/contributors https://github.com/4Catalyzer/found/graphs/contributors [2] https://github.com/4Catalyzer/farce/graphs/contributors https://github.com/4Catalyzer/farce/graphs/contributors
- tendencydriven 9y agoWhat do you mean by a "bus factor"? I'm assuming its related to the number of contributors / contributions over time, but I've never heard the term before. Edit ---- Oh! I get it now https://en.wikipedia.org/wiki/Bus_factor https://en.wikipedia.org/wiki/Bus_factor
- tpkj 9y agoSingle Page Applications? Bah Humbug! https://wildermuth.com/2014/9/1/Single_Page_Applications_Bah_Humbug https://wildermuth.com/2014/9/1/Single_Page_Applications_Bah...!