
Things to Know When Making a Web Application in 2015 - venantius
http://blog.venanti.us/web-app-2015/
======
tspike
First of all, thanks for the nice writeup. I hate that comments tend to hone
in on nitpicking, but so it goes. My apologies in advance.

> If you're just starting out with a new web application, it should probably
> be an SPA.

Your reasoning for this seems to be performance (reloading assets), but IMHO
the only good reason for using a single-page app is when your application
requires a high level of interactivity.

In nearly every case where an existing app I know and love transitions to a
single-page app (seemingly just for the sake of transitioning to a single-page
app), performance and usability have suffered. For example, I cannot
comprehend why Reddit chose a single-page app for their new mobile site.

It's a lot harder to get a single-page app right than a traditional app which
uses all the usability advantages baked in to the standard web.

~~~
joepie91_
I fully agree with this. SPAs are for web _apps_ , not web _sites_.

For websites, you should _always_ use progressive enhancement - there is no
reason why you couldn't obtain the same performance gains by progressively
enhancing your site with reload-less navigation. That's what AJAX and the
HTML5 History API are for.

Especially don't forget that no, _not_ all your clients support JS. And
there's no reason why they should need to, for a website.

~~~
baddox
> Especially don't forget that no, not all your clients support JS. And
> there's no reason why they should need to, for a website.

Sure there is, if you care about interactivity, responsiveness, and general
user experience. The fact that not all potential clients support JS is
probably irrelevant, since that number is probably incredibly small. You might
as well say that not all potential clients have access to the Internet.

~~~
joepie91_
> Sure there is, if you care about interactivity, responsiveness, and general
> user experience.

And all of these can be provided just fine using progressive enhancement. This
is _not_ an argument for SPAs.

> The fact that not all potential clients support JS is probably irrelevant,
> since that number is probably incredibly small.

Your use of the term 'probably' suggests to me that you have not run any
actual metrics. Here's a short list of some examples:

\- Bots and spiders

\- Low-powered mobile devices

\- Privacy-conscious users who use NoScript

\- Terminal-based browser users

\- Literally every single one of your users until the .js blob has completed
downloading

\- ...

Requiring JS for a website is not okay, end of story. We all collectively
understood this 10 years ago, and I'm not really sure where along the way this
understanding has gotten lost.

EDIT: Forgot that HN has a neutered version of Markdown. Fixed.

~~~
baddox
> Your use of the term 'probably' suggests to me that you have not run any
> actual metrics.

What I really meant is that if you have a significant non-JS-supporting
visitor base, you almost certainly already know it. There are a huge class of
web apps that simply do not have to worry about it. If you know who your
customers/visitors are then you should already know how important it is to
support non-JS browsers.

> Requiring JS for a website is not okay, end of story.

It's really not the end of story, and it's not your call except for your own
web apps. JavaScript is an integral part of the platform that is the web, just
like HTML and CSS. You might as well make the argument that "requiring a web
browser for your app is not okay, end of story."

> We all collectively understood this 10 years ago

Things were a lot different 10 years ago, and perhaps your reluctance to
update your understanding less than once per decade might explain some of your
views. You may as well be saying "making a store than can only be accessed
over the Internet is not okay, end of story, we all collectively understood
this 25 years ago."

~~~
wwweston
> JavaScript is an integral part of the platform that is the web, just like
> HTML and CSS

I always think it's interesting when people bring CSS into this, because it's
actually a very strong counter to the general argument.

By design a user agent is well within its rights to _completely ignore_ any
stylesheets attached to a page, and the idea was always that this should be
completely OK, partly because you have no idea what the UA's capabilities are,
up to and including whether or not it's doing any kind of visual rendering at
all.

This isn't a news flash to everyone, but even those already aware of this seem
to think the main reason you'd do this is ADA accommodations and those are
some kind of minority afterthought. My experience is that this is misguided --
accommodations for unusual visitors _is_ important, but I think the biggest
benefit might be that the simpler you make things for the client, the less
complicated the engineering tends be, even if you can't import your Java-
imitation-of-smalltalk-inspired application paradigm of choice.

And "too bad if you didn't have JS!" position seems to basically boil down to
the idea that serving a custom client that consumes JSON instead of HTML as
the media type for a given URI is Real Progress™.

Keep things as simple as possible. Don't require JS unless what the
application needs to do can't be done without it.

~~~
baddox
> By design a user agent is well within its rights to completely ignore any
> stylesheets attached to a page, and the idea was always that this should be
> completely OK, partly because you have no idea what the UA's capabilities
> are, up to and including whether or not it's doing any kind of visual
> rendering at all.

I think that is just an outdated idea that does not apply to highly
interactive, long-lived web applications. The user agent is well within its
rights to ignore anything it wants, of course, but the user agent is not
_owed_ anything by the server. With CSS, or JavaScript, the app may just not
work.

~~~
wwweston
> With CSS, or JavaScript, the app may just not work.

When it comes to CSS, generally most apps _will_ continue to work even if the
CSS is simply ignored.

Because that was one big point of CSS. Separation of presentation from content
and function.

It's funny. That kind of separation of concerns is something developers talk
about valuing, but the SPA/webapp craze erodes the user-facing aspect of it,
even while developers are very proud to demonstrate they're thinking hard
about which specific kind of separated-concern architecture they're working
with well away from the boundary where an outside user or UA would care.

------
balls187
If you're new to web application development and security, don't blindly
follow the advice of someone else who is also new to web application security.

You should instead have a security audit with people who have experience in
security, so they can help you identify where and why you're system is
vulnerable. If no one exists on your team/company that does, then hire a
consultant.

Security is a hairy issue, and no single blog post/article is going to distill
the nuances down in an easy to digest manner.

~~~
codingdave
Security is never perfect. It is a deterrent, not impenetrable prevention. So
sure, to security people, it is never good enough. To everyone else, a easy to
digest blog post might give them food for thought that would make their work
one step better than it was before, resulting in security that is still
flawed, but better. So why not just accept the post for what it is - some
basic advice to do that one better step.

~~~
balls187
> So why not just accept the post for what it is - some basic advice to do
> that one better step.

[http://www.nytimes.com/2015/07/10/us/office-of-personnel-
man...](http://www.nytimes.com/2015/07/10/us/office-of-personnel-management-
hackers-got-data-of-millions.html)

~~~
woah
Look up "medium-brow dismissal"

~~~
balls187
I did. Wasn't sure what I was looking for.

[https://www.google.com/search?q=medium-
brow+dismissal&ie=utf...](https://www.google.com/search?q=medium-
brow+dismissal&ie=utf-8&oe=utf-8)

It's clearly a logical failure to suggest heeding the authors advice would
result in a catastrophic security breach.

Not paying attention to security by reason of "I've done a little better than
nothing at all" feels like willful negligence.

~~~
jaawn
[https://news.ycombinator.com/item?id=5072224](https://news.ycombinator.com/item?id=5072224)

(edit: this is an explanation of what "middle-brow dismissal" is)

------
quadrature
This is a bit of a pet peeve of mine, but that banner image is 10 megabytes,
it can be compressed down to 2mb without any perceptible loss of quality. Heck
it could probably be shrunk further if you can accept a bit more loss because
most of the image is blurry and noisy anyway.

heres a compressed version:
[https://www.dropbox.com/s/bw606t7znouxpj1/photo-141847963101...](https://www.dropbox.com/s/bw606t7znouxpj1/photo-1418479631014-8cbf89db3431_mini.jpeg?dl=0)

~~~
lewisl9029
Good catch.

That is ironic on so many levels.

I mean there is even a section on "UX: Bandwidth"...

Maybe the author should brush up on image compression best practices and
consider adding a subsection on images and other media.

EDIT: Realized my previous wording was probably a bit too harsh considering
the author is still relatively new to web development.

~~~
quadrature
Hard not to catch it when its loaded in progressively on a 20Mbps connection
:P. Websites are way too fat these days.

------
joepie91_
> If you can get away with it, outsource identity management to Facebook /
> GitHub / Twitter / etc. and just use an OAuth flow.

The thing that everybody seems to overlook here: _this has serious legal
consequences_.

You are demanding of your users that they agree to a set of TOS from a third
party, that does not have either their or your best interests at heart, and
that could have rather disturbing things in their TOS - such as permission to
track you using widgets on third-party sites.

Not to mention the inability to remove an account with a third-party service
without breaking their authentication to your site as well.

Always, _always_ offer an independent login method as well - whether it be
username/password, a provider-independent key authentication solution, or
anything else.

> When storing passwords, salt and hash them first, using an existing, widely
> used crypto library.

"Widely used" in and of itself is a poor metric. Use scrypt or bcrypt. The
latter has a 72 character input limit, which is a problem for some
passphrases, as anything after 72 characters is silently truncated.

------
devNoise
Question about JavaScript and CDN for mobile devices. Should I use a CDN for
standard libraries or should I just concat and minify all my JavaScript?

The concat and minify seems better as that reduces the JavaScript libraries
and code load to a single HTTP request.

A CDN seems nice in theory. Reality is: Does the browser have the library
cached? Is the library cached from the CDN that I'm using? The browser is
making more HTTP requests, which sometimes takes more time to request than to
download the library.

I agree that using CDNs is a good speed boost. I'm trying to figure out if
hoping for a library cache hit out weights a library cache miss.

~~~
billyhoffman
Just to clarify. General CDNs tend to be a good idea of you are having latency
issues.

Standard libraries for major JavaScript project, all served from a single
shared CDN (like Google, maxcdn, cdnjs, etc) also tend to be called "CDNs" but
this is a little confusing. Yes, these shared files are often stored on a CDN,
but that's not the so-called major benefit of these shared hosts. The main
benefit is supposed to be that, if everyone references the same copy of jQuery
on one of these shared hosts, the when visitors hit other sites, jQuery will
already be in their browser cache.

This rarely works in practice. The URLs to these shared libraries. Multiple
shared services. Multiple version numbers. HTTPS vs HTTP. The net result is
that the probability that someone visiting your site has a copy of the exactly
same resource referenced via the exact same URL is very low.

With the overhead of having to do a DNS lookup, a TCP connection, TCP slow
start, its rarely worth it. Just concat/minify into your own block of JS
served from your own systems. Shared JS hosts/CDNs are a terrible and annoying
hack, all in an attempt to save 50KB or so

~~~
vdaniuk
Ugh, I will never understand this reasoning. Overheads of fetching library
from a CDN are applicable to the first request. Why do you consider this to be
an important factor?

Also can you provide any stats/citation that cache hit probability on first
request is in fact very low?

~~~
billyhoffman
First, research on hit factor:

[https://zoompf.com/blog/2010/01/should-you-use-javascript-
li...](https://zoompf.com/blog/2010/01/should-you-use-javascript-library-cdns)
[http://statichtml.com/2011/google-ajax-libraries-
caching.htm...](http://statichtml.com/2011/google-ajax-libraries-caching.html)
[https://github.com/h5bp/html5-boilerplate/pull/1327#issuecom...](https://github.com/h5bp/html5-boilerplate/pull/1327#issuecomment-14799362)

I have more recent data on this that is not yet published from my day-to-day
work at a web performance company. The pictures has improved somewhat, but not
significantly.

You are correct, "Overheads of fetching library from a CDN are applicable to
the first request" The problem is, because of the fragmentation, every website
is asking you to hit a different URL, so every request is a "first request".
You aren't leveraging the browser cache.

Most sites are already serving you site-specific JS anyway over a warm
connection (even more so with HTTP/2), so there is even less benefit to going
to a 3rd party host to potentially avoid downloading a few dozen kilobytes.
Couple that with the security implications of injecting 3rd party code into
your page, its just plain silly and wasteful to do this for a modern website.

~~~
vdaniuk
jQuery CDN cache hit rate is 99.8%[0], Google CDN numbers should be
comparable. So yes, you are leveraging browser cache for most popular
libraries.

Also I was talking from the subsequent requests from the same client.

[0][https://www.maxcdn.com/blog/maxscale-
jquery/](https://www.maxcdn.com/blog/maxscale-jquery/)

~~~
billyhoffman
You are confusing browser cache hits with a CDN/edge server cache hit.jQuery,
or MaxCDN for that matter has no idea what the "hit rate" of a browser cache
is.

This sentence should be a big clue: "We usually average around 15,000 hits per
second to our CDN with 99.8% of those being cache hits."

"We" in that sentence is Kris Borchers speaking collectively about the jQuery
foundation, talking a MaxCDN interviewer. But he is not talking about the
browser cache. He can't be, because jQuery, or MaxCDN for that matter has no
idea what the "hit rate" of a browser cache is.

Example: If I go to _1.example.com_ , which links to _maxcdn.com /jquery.js_,
and then later I go to site _2.example.com_ , which links to the same
_maxcdn.com /jquery.js_ file, my browser doesn't send any requests! That is
the entire point of far-future caching! I was able to use the version of
jquery that was in my browser cache. However MaxCDN, or jQuery for that
matter, have no idea this hit took place.

By the same token, if I go to _1.example.com_ , which links to _maxcdn.com
/jquery.js_, and then later I go to site _2.example.com_ , which links to a
different URL like _maxcdn.com /master/jquery.js_, my browser has a cache
miss. /master/jquery.js is not in my browser's cache, I've never been there.
MaxCDN, or jQuery for that matter, have no idea that I requested something
different then before.

CDN cache hit rate has nothing to do with browser caches. In fact, people that
are not you, being able to detect if something is in your browser cache or
not, is a massive security problem. See my talk at BlackHat in 2007, Many of
Jeremiah Grossman's talks at BlackHat (2006, 2007, 2009), or go all the way
back to Ed Felton's work on using the timing side channels against browser
caches.

In the industry, "99.8%" cache hit on a CDN's edge server means that 99.8% of
the time the edge server can handle the request, instead of the request having
to go all the way to the origin. They have no way of knowing how often a
random person on the internet loads a random file from their browser cache.

This whole thing proves my point: Calling shared, common, publicly hosted
copies of popular JS libraries "CDN's" or "JavaScript CDNs" is just confuses
people. CDNs are about reducing latency. Share JS libraries are about trying
to avoid requests altogether by leveraging the browser cache, and they are
largely ineffective.

~~~
ersoft
Maybe they are talking about 200 vs 304 caches.

A browser can use be told to revalidate files, telling the server to return
the content using the "If-Modified-Since" and "If-None-Match" headers. This
way, the server will return 304 and empty content if the file has not changed
or 200 and the file if it is new or it changed

------
shiggerino
>When storing passwords, encrypt them

Nopenopenopenopenope!

This is terrible advice. Don't do this. Remember what happened when Adobe did
this?

~~~
rfrey
The full quote is:

"When storing passwords, encrypt them first, using an existing, widely used
crypto library. If you can get away with it, outsource identity management to
Facebook / GitHub / Twitter / etc. and just use an OAuth flow."

Can you elaborate on what's so "nope" about that advice? Are you saying one
_shouldn 't_ encrypt passwords?

~~~
ovi256
Of course one shouldn't _encrypt_ them, one should salt and hash them. With a
cryptographically secure hash such as bcrypt or scrypt.

If you use a batteries-included web-framework, this is already done for you.
If you do not, you better understand the tradeoff of redeveloping those parts.

~~~
mcdougle
I imagine the OP probably meant that and simply wrote the wrong thing in the
post. I probably wouldn't have noticed it was the wrong wording if not for
this comment chain.

~~~
woah
The only acceptable advice in this situation is "use bcrypt". Vague stuff
about "hashing or encrypting" is not good enough.

~~~
cpitman
Wait, what about "scrypt"? Maybe the only acceptable advice changed in the
last hour? :-)

~~~
woah
Bcrypt is a very easy to use hashing tool that exists in all popular
languages. It is the best choice, and the easiest to implement.

------
balls187
> If you can get away with it, outsource identity management to Facebook /
> GitHub / Twitter / etc. and just use an OAuth flow.

OAuth isn't identity management, it's for authorization.

Each of those platforms does provide it's own identity management, but that
isn't OAuth.

~~~
artmageddon
I took that to mean use both identity management as well as OAuth.

~~~
balls187
1\. Why use OAuth unless you want to grant 3rd parties access to your services
data, on behalf of your customers?

2\. Security best practices subject to "open for interpretation."

~~~
superuser2
While OAuth isn't "for" authentication, everyone uses it that way by
"authorizing" access to "view your email address" which is as good as
authenticating your email address.

~~~
balls187
Can you link to implementations that use OAuth in such a manner?

Login with FB, Google, Github, Twitter, etc different systems, separate from
OAuth.

~~~
cpitman
GitHub How To: [https://developer.github.com/guides/basics-of-
authentication...](https://developer.github.com/guides/basics-of-
authentication/) And the OpenID Connect standard (essentially OAuth V2 +
identity service): [http://openid.net/connect/](http://openid.net/connect/)

------
romaniv
_> All assets - Use a CDN

> If you can get away with it, outsource identity management to Facebook /
> GitHub / Twitter / etc. and just use an OAuth flow._

Questionable advice. At the very least neither of these two are some kind of
automatic "best practice" everyone should just follow.

 _> it can be helpful to rename all those user.email vars to u.e to reduce
your file size_

Or maybe you should less JavaScript so length of your variable names does not
matter.

------
vbezhenar
One thing to note is login redirect. Please be sure that redirect parameter is
local URI and don't redirect user to another site.

Maybe even append HMAC signature to that parameter with user IP and timestamp.
Might be an overkill, but still be careful with craftable redirects, they
might become vulnerability one day.

~~~
rudolf0
True, open redirects can cause serious security issues. Do not have an route
that simply does the equivalent of `return redirect(params["url"])`, either at
login or anywhere.

------
jameshart
"You don't have to develop for mobile..."

... well, no. Technically you don't _have_ to. But you almost certainly
_should_.

~~~
davnicwil
Was surprised to see this too, considering the article's title is Things to
Know When Making a Web Application in _2015_

If anything the advice should be inverted by replacing 'mobile' with 'desktop'

~~~
trace303
Yes, even moreso now since it hurts your Google page rank to not make your app
mobile friendly.

~~~
jameshart
I believe it only hurts your google rank for searches conducted on a mobile
device.

So, most searches, then.

------
toynbert
As a web application developer in 2015+ I would argue that developing with
mobile in mind should be required. At least taken into consideration. At bare
minimum have a pre-deployment test: is my app unusable/does this look terrible
on the most popular iphone/android.

~~~
schnable
And that it passes Google's mobile check, so it doesn't get penalized in
SERPs.

------
patcheudor
For mobile apps that use WebView and/or has the capability to execute
javascript or any other language provided by any network available resource
I'd like to add:

ALWAYS USE CRYPTOGRAPHY for communication! Simply doing HTTP to HTTPS
redirects is not sufficient. The origin request must be via HTTPS. Also make
sure the app is properly validating the HTTPS connection.

Sorry I had to shout, but I'm growing tired of downloading the latest cool app
that is marketed as secure only to find that it doesn't use HTTPS and as a
result I can hijack the application UI to ask users for things like their
password, credit-card number, etc., all without them having any way to tell if
they are being asked by some bad guy.

------
Domenic_S
How to make a reasonbly-decent webapp in 2015 without having to worry about
bcrypt and open redirects and such:

1\. Use a widely-accepted framework.

2\. Implement your application using that framework's methods.

Why a beginner would implement even 1/3 of this list manually is beyond me.

~~~
ahayschi
I think this is more of a question of what kind of project or team you are
working on, not one of experience in web development. Because it seems that
you're suggesting beginners use Sails or Meteor (if focusing on JS), which are
great and allow for rapid prototyping, but they and other 'high-level
frameworks' that implement these methods for you tend to be very opinionated
with important details of developing for the web abstracted away.

If you're a student or are serious about learning web development (and want to
focus on developing in JS), it would make a lot of sense to dedicate your time
to actually learning Node and Express, figuring out all of these hairy details
and 'manually' implementing the items in Venantius' list.

Or don't figure out the hairy details, because many of his items have proven
and documented solutions in the Node context, and learning how to properly use
bcrypt and passport isn't too difficult. These libs are a good middle-ground
between low-level details and something more out of the box.

------
martin-adams
>> When users sign up, you should e-mail them with a link that they need to
follow to confirm their email

I'm curious, why is this good? Sure, sending an email to them so they confirm
they have the correct email, but what is the benefit of the verification step?
Is it to prevent them from proceeding in case they got the wrong email? It
would be nice if this was justified in the article.

I would also add, that changing a password should send an email to the account
holder to notify them. Then when changing the email address, the old email
address should be notified. This is so a hijacked account can be detected by
the account owner.

~~~
cpitman
This may not be the writer's reason, but I tend to get people's e-mail
accidentally. One time someone signed up an iTunes account with my email, then
kept requesting new verification emails. Most of these automated emails do not
have a "this isn't me" link, since they assume that the person who signed up
and the person getting the email are the same.

------
Quanttek
> The key advantage to an SPA is fewer full page loads - you only load
> resources as you need them, and you don't re-load the same resources over
> and over.

I don't know much about web development, but shouldn't those resources get
cached? Isn't the disadvantage of SPAs that you are unable to link to / share
a specific piece of content?

~~~
blowski
> Isn't the disadvantage of SPAs that you are unable to link to / share a
> specific piece of content?

Actually, this is achievable with push states, so isn't a strong argument
against single page apps.

I think the problem with SPAs is that they exacerbate memory leaks, since they
don't have the typical 'reset' of a browser page load to clear them. Also, a
lot of SPAs re-implement browser functionality like scrollbars and the back
button without proper cross-browser testing - let alone usability testing.

Conceptually, there's nothing wrong with SPAs, but many of the implementations
are shoddy at best with no clear advantage gained.

------
Kudos
One big omission from this list: gzip. Before you ever think about uglify,
make sure you're gzipping your textual assets.

------
donmb
Rails has most of this out of the box. Use Rails :)

~~~
avinassh
I think, even Django also has most of this stuff.

------
Yhippa
I like this list.

> Forms: When submitting a form, the user should receive some feedback on the
> submission. If submitting doesn't send the user to a different page, there
> should be a popup or alert of some sort that lets them know if the
> submission succeeded or failed.

I signed up for an Oracle MOOC the other day and got an obscure "ORA-XXXXX"
error and had no idea if I should do anything or if my form submission worked.
My suggestion would be to chaos monkey your forms because it seems that
whatever can go wrong can. Make it so that even if there is an error the user
is informed of what is going on and if there's something they can do about it.

------
Kiro
> Avoid lazy transition calculations, and if you must use them, be sure to use
> specific properties (e.g., "transition: opacity 250ms ease-in" as opposed to
> "transition: all 250ms ease-in")

Why is it better to be specific?

------
sambeau
I was surprised at the lack of mention of SVG. The biggest change to my
working habits (apart for working in a SPA) is that every non-photographic
image I use is now SVG.

~~~
lewisl9029
Don't be surprised. See this:
[https://news.ycombinator.com/item?id=9866461](https://news.ycombinator.com/item?id=9866461)

------
jgalt212
>If you can get away with it, outsource identity management to Facebook /
GitHub / Twitter / etc. and just use an OAuth flow.

Has anyone built a lasting stand-alone business that relies on Facebook, et al
for identity management?

~~~
tim333
Tinder? Facebook only when I tried. Valued > 1 $bn

[http://www.businessinsider.com/jmp-securities-analyst-
note-o...](http://www.businessinsider.com/jmp-securities-analyst-note-on-
tinder-2015-4)

------
andersonmvd
When using SPA, validate CORS origin instead of allowing *.

------
stevewilhelm
Internationalization?

------
sarciszewski
_> For all of its problems with certificates, there's still nothing better
than SSL._

Yes there is. It's called Transport Layer Security (TLS).

------
tomcam
web2py is a batteries-included framework that has all of this and much more
done for you, tested and proven over many years.

------
suyashbansal
I was thinking to make a web app for my college project. Can you please help
me with some inspirations for my project ? :P

------
JikkuJose
Hey uncss supports dynamically added stylesheets too (via running in through
PhantomJS).

------
anton_gogolev
> sent to a page where they can log in, and after that should be redirected to
> the page they were originally trying to access (assuming, of course, that
> they're authorized to do so).

Smells like an information discolsure highway. I usually 404 all requests that
hit "unauthorized" content.

------
Kiro
> Confirm emails

Why?

~~~
y_mesh
It's for authentication. It's kinda like: you (email server) know this person,
then we (developer) know this person.

