Why You May Not Need A Framework
This was a talk given at the 2017 Des Moines Web Geeks Social Event.
Recorded video of the event: facebook.com/DSMWebGeeks/videos/1423410991065489. My talk starts at around 2:14:30.
Slides
The talk’s slides are embedded below. Use the left/right arrow keys to navigate.
The slides can also be viewed at eheikes.github.io/use-the-platform-talk. Its code repository is available at github.com/eheikes/use-the-platform-talk.
Edited Transcript
I’m going to talk about why you may not need a front-end framework for your next project.
To start with, I’d like to give a little bit of perspective about how we got to where we are now, so I’m going to put on my gray beard here, and go back in time to explain just how terrible Javascript development was back in the day.
Back when Javascript was created, in the 90s, for Netscape, there’s actually a few other options out there. Microsoft created its own version of Javascript called JScript for Internet Explorer. They also created a flavor of Visual Basic called VBScript to work with Internet Explorer. So, the first decade of web development didn’t create really great websites by today’s standards. They were mainly informative, not a lot of interaction except maybe through forms and imagemaps. That was because Javascript was very much in its nascent phase. I dug up this old code, from the late 90s I think. Back then you had to specify the actual language you were using in your script, whether it was Javascript or JScript — maybe even the actual version you’d be using. You actually also had to put HTML comments around your code, for browsers that didn’t understand the script tag and would actually print your code to the screen. And it was very difficult to work with interaction inside the browser, so you had a lot of terrible code like this. So it was very frustrating to try to build rich applications on the web.
Around 2004/2005, this started to change. Firefox was released to challenge Internet Explorer in the browser market. Google started creating some rich apps like Gmail and Google Maps. And then libraries like Prototype and jQuery came out to help smooth over these inconsistencies across the browsers. And so that helped bring us to the present day, which I’m calling the “Age of Frameworks,” where we have these application frameworks like Angular, React, and Vue. This slide kind of shows some of the libraries out there. It’s from a survey of web developers that was made recently. The far left bar is jQuery; 3 out of 4 developers have used jQuery in a project, and many other developers have used Angular or React or some type of library for their application. The far right bar shows that less than 3% of developers do not use any framework at all for their apps.
So we have these powerful application frameworks. They give us all this stuff; CLIs and boilerplates are out there to allow us to quickly build our rich apps very easily and very quickly. These are just 5 right here, but of course there are many more. These are just a few of them… There’s the joke that a new Javascript framework comes out every week, so the phrase “framework fatigue” has been coined because it’s very hard to try and stay on top of all these new libraries that keep coming out.
Another problem is that we have these compartmentalized ecosystems. This is a snippet from an email newsletter, that I received a couple weeks ago, that has links to these great tools and libraries that you can use for your apps. But if you look closely, you’ll notice that most of these are tied to specific frameworks. They’re designed to be used in these frameworks; they’re not really made to be used in a different framework. For example, if you’re using React, you can use these React libraries, but you can’t use the Angular ones really.
Where I work, at Jack Henry, we have a suite of enterprise apps designed for our financial institution customers. These were created about 3 to 4 years ago, and they’re written in Angular 1. Since then, as we’ve built these apps out, we’ve amassed this collection of libraries — whether it’s a routing library, or UI components — to work in these Angular apps, and they’re all tied to Angular because of the way that the framework works. So we have all of these pieces that are tightly coupled together, and now after a few years we’ve realized that we’ve become caged within this framework.
The problems that you run into if you’re using a framework: Like I mentioned, components that are written for one framework usually can’t be easily used inside another framework. If you write a component for your app, it has to fit within that framework. We’ve run into friction when trying to maintain the applications, or adding new features. New developers obviously have to learn the framework or know it before they join. These frameworks have extra weight that they add to your application, whether it’s just the payload that the users receive, with that extra layer of abstraction that the frameworks give you, or if it’s even just pieces of the framework that you don’t use — often that’s weighing down on the user. Also, this extra abstraction slows down the performance of your application. There’s a good video that some Google developers did that looked at mobile performance and the frameworks specifically, and it showed that they’re really not designed to work on mobile devices with the CPU and the network limitations that they have.
Also, with all the new frameworks that keep coming out, what if you want to move your application to the latest hotness — how do you migrate from one framework to another? It’s usually a non-trivial amount of work. And there’s no guarantee that the framework that you choose will still be around in a couple years, or even a few months.
The solution that we’ve come across is the web platform. What that means is that the browser itself is the framework.
The first thing to mention is Javascript itself. Since it first came out, with the latest ECMAScript progress that’s been made, Javascript has really reached the point where plain Javascript is useful by itself. A lot of the stuff that jQuery and those tools were created for, to fix the incompatibilities across browsers, is not needed as much as it used to be. Javascript gives you a lot of things out of the box nowadays. You can use your object-oriented programming or your functional programming. It’s got DOM traversal and manipulation. You can observe DOM mutations. Ajax is possible with the fetch API. It’s got events built-in. Promises are part of Javascript. Modules are part of Javascript now.
Of course, a lot of browsers don’t support the latest Javascript. For that, you can use polyfills, whether it’s building into your app or using a service like polyfill.io. There’s transpilers like Babel, which will let you compile down to a more accessible language.
Even if you’re using native Javascript, there’s still this paradigm of components that pretty much any modern framework follows. Angular has components, React has components, Vue has components. And this is actually also built into the web specs. These are the 4 web specs that cover it.
Custom elements let you create your own tags. That’s the Javascript you need to create your own custom element; it’s basically extending an HTMLElement
with a new class and then calling customElements.define()
with your tag name and your class, and then you can use it in your app. It’s that easy.
Templates let you specify inert fragments of HTML. You can reuse those, import those into your app. Here’s the Javascript for that — basically just calling importNode()
.
Shadow DOM is the piece of the web that lets you encapsulate your components. It creates the boundaries between the DOM of your component and the DOM of the rest of the page. It keeps those separate. You can also separate your styles so that it doesn’t bleed into other parts of the app; it’s just used for your component. This code here puts it all together — We’ve got your customElements.define()
to create a fancy-tabs
tag. It extends HTMLElement
. And then in your constructor call attachShadow()
to create a new shadow root — that’s the shadow DOM. And then you can import your template there and attach it to your shadow DOM. That’s pretty much all you need to create your own components — your native web components.
The fourth piece is HTML imports. This lets you import a component into another page or another component. It’s similar to ES6 modules where you can import Javascript. Here you’re importing HTML.
Browser support currently for these 4 specs is pretty good. Templates are supported across all modern browsers. Custom elements and shadow DOM have pretty good support or they’re in progress of being added to browsers. Microsoft is thinking about adding support — don’t know when that will be. For most of these that don’t have support yet or are in progress, you can use polyfills to fill in the gaps there. They only real wrinkle is the imports — that specs is actually on hold now; browser vendors and the standards committee are discussing where that might go, since there are some argument about that and the whole ES6 modules stuff and how that will shake out. But you can still use polyfills or transpilers now, if you want to use that.
The nice thing about components, of course, especially native web components, is that you can easily share them. This is webcomponents.org. They have a collection of some components that you can search for, so for example if you’re searching for a calendar. Since they’re native components, you can basically use them in any application or any framework, since there’s very little required to import them into your app.
And then everything else that’s not built into the platform, you can still use libraries. For your routing or your application state, data binding — stuff like that — you can use your standard npm install
, and then import it into your app. So the idea is to have these reusable components and other small libraries, and then compose them into your app, so that you kind of make your own custom framework in a way.
So, about a year ago at work, we had a task to create an online banking white-label app for our customers. This was greenfield project, so we didn’t have any of the baggage from Angular 1 or anything; it was completely fresh. What we came up with for that was an application that used these web components. Here’s a screenshot of the app. Everything you see here is components; it’s components all the way down. It runs on all modern browsers. It’s written in ES6, compiled down to ES5.
There’s really only 3 polyfills that are used: there’s the web components polyfill that provides the custom elements and templates for those browsers that don’t support the native stuff. And then there’s 2 small polyfills; one for the dialog
element and one for the closest()
method on elements. We have a custom router that’s based on page.js. We don’t use any CSS compiler; it’s just pure CSS. But we do use CSS variables and of course the shadow DOM, which makes it pretty easy to work with; we don’t have to worry about it cascading into other parts of the app, it just stays inside the component there. And there’s still the core CSS that’s used for styling across the entire app. The components themselves and bundled using vulcanize and crisper, and we also created a couple of projects to fill gaps in the Polymer ecosystem; one’s for linting, the other’s a renaming utility for Closure Compiler.
If you haven’t guessed yet, for this we’re using the Polymer library to create our components — Polymer version 1. And there is a Polymer app framework out there that we don’t use — it’s more like a traditional framework, I think. The Polymer library itself, which was created and backed by Google, is a very small library. It’s mainly a polyfill for native web components, but there’s also a little bit of syntactic sugar to make it a little bit easier and more concise to write the components.
Here’s a list of the different components, grouped into categories. Each component has an HTML file that has a template in it, and CSS. And there’s a Javascript file that the functionality for the component, and those get bundled together and split out by the build tools. Then we also have Jack Henry components. This is just our general UI components, like dropdowns, icons, modals, that can be used in any of our apps, that provide a consistent design.
So, a few months ago, we had the opportunity to rewrite our enterprise apps from Angular 1, from scratch, using any tech stack or framework we chose. The only restriction was that we would have to research and come up with a tech stack that would have the best maintainability for 5 years or so. It doesn’t sound like much, but 5 years is a pretty long time in the tech world. So we had to look at the different frameworks, create some prototypes, and figure out what direction we wanted to go to rewrite these apps so that they would be easily maintained and looking future-forward. We looked at the banking app that we created, and we decided to continue in that direction.
Polymer 2 was released a couple of weeks ago. It’s a very small upgrade; we’re already in the process of migrating our banking app from 1 to 2, and there’s not much to migrate, since it’s a very small library. The direction that we’re looking at is, again, to have these components that we’ve already created for the banking app and can be reused across the new apps as well, write new components in Polymer probably — we’ve started doing that — and then use libraries for routing, application state, and all that on an as-needed basis — evaluate them as we go, and integrate them into our custom app framework. So that’s the idea, to reuse these components, and keep everything as loosely coupled as possible to give us the most flexibility going forward. In case Polymer suddenly dropped off the face of the Earth, we can plug in React or some other view layer for components. If the router turns out to not work, we can throw that out and put in a new router library.
It’s still early days. Like I said, it’s been a year since we’ve used Polymer for the banking app, and we’ve started rewriting our enterprise apps into Polymer 2. But it looks promising; I’m optimistic. I’ll quote one of my co-workers here, since he’s a smart guy. He said:
“These are the early days of web components. I think Polymer is going to help more developers start using components. And in the next several years we’ll see more contenders like Polymer staying close to native APIs but adding what developers claim is missing from the browser. Add 10 more years and nobody will know what we’re talking about.”
Sort of the goal of Polymer — this polyfill — is to eventually just disappear, because as the browsers add these native APIs, the polyfill will get smaller and smaller. Other than maybe a little bit of syntactic sugar, there’s not going to be much there other than that close-to-the-metal native layer.
Maybe frameworks won’t disappear completely, but they might fade into the background a little bit, and turn into the “age of the platform”, where the browser is the framework. I’d like to encourage all of you, the next project that you start, give this approach a try. Simplicity matters. It’s not easy. It’s very easy to install a framework, grab CLI tools or a boilerplate, and just start writing. But as we’ve discovered, it’s not always the best thing for the long term. If you’re building an app that’s going to last more than a few months and has multiple people working on it, you might want to try this: a simple set of libraries, coupled together and using the native web components underneath. You’ll get the flexibility, the performance, and the longevity without sacrificing a lot of the power that frameworks give you.
We had the backing of management to rewrite our apps from scratch, but I would not expect this to be a normal thing at all. It’s very rare to have the time and the resources to be able to take a mature app and rewrite it in a framework of your choosing. So don’t paint yourself into a corner. Look towards the future of where the platform is heading, and free yourself from the framework cage. Thank you.
|