Menu Search
Jump to the content X X
Smashing Conf Barcelona

You know, we use ad-blockers as well. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. our upcoming SmashingConf Barcelona, dedicated to smart front-end techniques and design patterns.

Lessons Learned In Big App Development, A Hawaiian Airlines Case Study

Having spent over two years making it, we just pressed the “Ship” button on the new Hawaiian Airlines website1. It has been the biggest project of my career, and I’ve worked with the most talented team I’ve ever worked with. Everything was rebuilt from the ground up: hardware, features, back-end APIs, front end, and UX and design. It was a rollercoaster ride like no other, but we have prevailed and built what I believe to be one of the best airline-booking experiences on the web. Yes, humble, I know!

Join me while I reflect on some of the mistakes we made, the tools we used, the workflows and guidelines we followed, and even some of the custom tools we built, all while growing a UI development team from one (yours truly) to over ten people to get the job done.

Further Reading on SmashingMag: Link2

Full disclosure: Our company, User Kind, is a vendor for Hawaiian Airlines, and all opinions expressed here are my own. This article and the information herein has been shared with the explicit permission and generosity of Hawaiian Airlines.

Humble Beginnings Link

When I came aboard this project as a UI developer, Hawaiian Airlines had already hired another agency7 to rethink the UX and design of the existing 10-year-old website. That agency delivered a 500+ pages wireframe document, a handful of beautiful annotated Photoshop mockups and a front-end style guide. Seeing these deliverables immediately got me excited about the project and some of the fun UI development challenges that lay ahead.

Flight Hop Link

Flight Hop8

The “hops” between stops are dynamic and represent the duration of that flight relative to the total flight time. Seemed like a fun thing to build using SVG or canvas. (View large version9)

Travel Goals Link

Travel Goals10

When I saw this, I envisioned the orange progress bar and plane icon animating across the screen, while the “miles to go” number counted down. (View large version11)

Price Chart Link

Price Chart12

The price chart calculates a relative height for each day, based on the data at hand, fast-forwarding through months while making AJAX calls, and readjusting bar heights based on new data. (View large version13)

The Front-End Sandbox Link

Around the time I was getting started, a large back-end team of 40 or so developers were ramping up on rebuilding all of their service APIs. Knowing that there was a tsunami of UI work to do, no back-end APIs for the front end to consume yet, and a hard deadline staked in the ground, we got to work.

Because the back-end stack was still being defined and built behind a private network, we started with a lightweight front-end sandbox to begin building UI components.

Here’s what the stack of tools and workflow looked like:

Sandbox Dev Stack14

Stack of tools and workflow. (View large version15)

Dynamic Templates Fed by Static Data Link

While working in the sandbox environment, we used AngularJS to create dynamic templates based on a static JSON, which would eventually be replaced with live endpoints once we delivered the code. Sometimes the back-end folks would send us a JSON file generated from real flight data, and other times we would just define it ourselves if the data didn’t exist yet.

Using static JSON data worked OK for a while, but once we started building some of the more complex UI components, we quickly ran into a problem: multiple data states.

Take flight results, for example. You have one-way, round-trip and multi-city flight results, each with up to four layovers, overnight flights and multiple airlines. You can even travel back in time if you fly across the right time zones at the right time!

Given the thousand-line JSON files, hand-tweaking the JSON to test other states was a chore and prone to human error.

We needed a better way to build and test all of these different states in the sandbox. So, Nathan set out to solve this problem and came up with what we call the “data inspector”:

Data Inspector16

We used the data inspector to simulate live data in the static sandbox environment. (View large version17)
Data Inspector Stack18

The data inspector used PouchDB to handle localStorage, which also allowed us to sync up to a lightweight CouchDB server so that we could share data states between team members. (View large version19)

Armed with the data inspector, we were able to prepare the front-end code so that it was production-ready when we delivered it to be hooked up to live data. As a bonus, designers and product owners could use this tool on the demo Heroku website to ensure that everything looked as intended across states.

Tossing Code Over the Fence Link

Spoiler alert: Don’t ever do this!

When it came time to integrate the front-end code with back-end services, we had to toss it over the fence to the folks who were integrating it in a totally different environment (.NET) with completely different tools (Visual Studio and Team Foundation Server), tucked securely behind a private network in Hawaii.

While this worked OK initially, it quickly became a nightmare. Product folks would request changes to the UI; we would make those changes in the sandbox, then toss it back over. Code changes would then have to be hand-merged because we had Git on one side and Team Foundation Server on the other. With different file and folder structures, these two repositories didn’t play nice together.

We quickly put an end to this and worked with the IT team to get access into the walled paradise. However, this process set us back months of productivity, as we switched to a completely different development stack, got VPN access, learned a different toolset and set up our virtual machines to match what the back-end team was using.

From then on, we’ve worked directly with the back-end teams to build and integrate the UI code, using the scrum process in two-week sprints, and things have gone a lot smoother since.

In the short term, the sandbox gave us a huge head start. We got to use a bunch of modern tools and workflows that we were all familiar with. It made us really efficient. Given the circumstances, it might have been the right move, but we waited way too long to rip off the bandage and hop over the fence once it was ready.

Sandbox Learnings Link

  • If you’re using Git, choose a branching model carefully on day one, and ensure that it fits your team, project and workflow.
  • If your Git branching strategy is done right, then reverting or cherry-picking features over the timeline of your project should be a cheap and easy task.
  • If building the front end of an app with real data and endpoints isn’t possible, then figure out a way to make it possible. (Mocked-up endpoints would have been better.)
  • Avoid multiple teams working across multiple environments at all costs, even if it causes delays up front.
  • Establish your tools, workflows and environment early on, and ensure that everyone on the team uses them.
  • Had we taken a more forward-thinking approach, it would have given us a big leg up in the long run, and we would’ve avoided the mid-project slump altogether.


In the beginning of this project, we adopted the methodology20 that keeping the HTML light, with very few CSS classes, while using LESS’ :extend heavily was the way to go.

It’s nice because when your design changes in the future, your HTML won’t be full of a lot of CSS classes, and you shouldn’t have to touch it. Simply update your LESS styles, and change your :extends.

Most elements in the HTML had either no class or a single defining class:

<section class="my-section">
   <p>Some Text</p>

Then, in our LESS, we’d have styles like this:

.my-section {

The net result of this method is a lot of selectors in the CSS output. After a year of coding, our CSS output got unwieldy, with thousands of lines of this:

.ha-modal .help-template h2,
.ha-modal .help-template h3,
.ha-modal .help-template h3:first-child,
.ha-help.collapsable-block h4,
.tooltip-block h4,
.traveler-lg .name,
address h4,
.ha-cms-teaser-sidebar .heading,
[ha-calendar] .ha-calendar-month,
.ha-modal#locationModal .destinations-container .standard-location .heading,
[ha-alert] .alert .alert-content .alert-content-primary,
[ha-avatar] .avatar .name,
[ha-avatar] .avatar.small .name,
[ha-tooltip] .ha-tooltip h4,
[ha-global-alert] .global-alert .alert-content .alert-content-primary,
[ha-promo-tile-other-small] .promo-tile.tile-small .headline,
[ha-promo-tile-other-large] .promo-tile .headline,
[ha-child-nav-tile] .child-nav-tile .page-title,
.navtray-content-inner--stackedlistwrap .stackedlist-li-title,
.lte-ie7 .navtray-content-inner--stackedlistwrap .stackedlist-li-title,
.ha-flight-hop .departure-city,
.ha-flight-hop .arrival-city,
.ha-receipt .trip,
.ha-my-trip-itinerary .trip-header span.segment-city,
.ha-my-trip-itinerary .segment .check-in .status,
.ha-my-trip-itinerary .segment .check-in .status:before,
.ha-my-trip-itinerary .segment .check-in,
.ha-my-trip-itinerary .segment .check-in,
.ha-my-trip-itinerary .segment .check-in .status.yellow:before,
.ha-flight-status .flight-info .flight-number,
.ha-flight-status .flight-info .flight-route,
.ha-print-confirmation .reservation-code-title,
.ha-my-trips-itinerary-details .trip-header span.segment-city,
.ha-my-trips-eticket-receipt .trip-header span.segment-city,
.ha-my-trips-itinerary-details .segment .segment-header .col,
.ha-my-trips-eticket-receipt .segment .segment-header .col,
.ha-my-trips-itinerary-details .segment .leg .leg-details .status,
.ha-my-trips-eticket-receipt .segment .leg .leg-details .status,
.ha-my-trips-itinerary-details .segment .leg .leg-details .status:before,
.ha-my-trips-eticket-receipt .segment .leg .leg-details .status:before,
.ha-my-trips-itinerary-details .left-heading .trip-locations,
.ha-my-trips-eticket-receipt .left-heading .trip-locations,
.ha-book-flight-results .segment .selected-flight-info,
.select-class-wrapper a,
.ha-book-flight-results .discount-applied .credit-applied {
  font-style: normal;
  font-size: 0.9375em;
  font-family: "helvetica-neue", "HelveticaNeueLT Std", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: bold;
  text-transform: none;
  line-height: 1.4;
  letter-spacing: 0.02em;

Fun fact: Did you know that Internet Explorer 9 and below will stop processing a given CSS file once it reaches 4095 selectors? Heavy use of :extend put us way over that limit early on. Figuring out why the website looked totally messed up in Internet Explorer 8 and 9 took a bit of debugging and research. We ended up using a Gulp task to break up the CSS files for old versions of the browser.

This ended up being really bad. It bloated our CSS with an output that made it difficult to debug styles in the inspector.

Mixins vs. Extend Link

When our CSS output started exceeding 100 KB in size, a question arose. What would output a smaller style sheet: more styles (using @mixin) or more selectors (using :extend)?.

I’ll let Jake21 explain:

“After testing it out, we discovered that, despite :extend outputting significantly less CSS, Gzip compression of the redundant mixin styles could actually translate into a similar if not smaller file size. What puts this idea over the top is that transitioning to mixins would make the DOM inspector CSS much more legible. We would no longer have 200 unrelated selectors grayed out for that h1 you’re trying to debug (which can make the inspector lag and reduce legibility). We did a small Gzip test comparing a small-scale mixin-ed style sheet versus an :extend-ed style sheet, and the mixin version actually came out on top.”

So, we did a big overhaul to change all :extends to @mixins. (We covered 80% with a simple script, the rest by hand.)

Thus, this…

.my-section {

… became this:

.my-section {
   h1 {.header-uppercase-1}
   p {.bodycopy-sans-3}

This discovery was an improvement, but the bloated CSS could have been avoided altogether if we had adopted an entirely different framework…

OOCSS and BEM Link

Looking back on all of this, our CSS would have reduced in size and our development productivity would have increased if we had established a pattern with more defining classes in the markup (OOCSS22 and/or BEM23).

Here are the pros of OOCSS and BEM:

  • Style sheets are smaller, flatter and easier to maintain.
  • Troubleshooting and development of styles are more efficient:
    • Source maps can tell you where to find the source LESS code.
    • Modifying styles in the browser (for experimenting) is easier because they will appear as different syles.
    • The DOM will tell you what the custom class is versus what the global classes are.
    • You can more easily break out specific style sheets to serve only what a page or section needs (rather than a lot of classes being downloaded that the page doesn’t refer to).

And here are the cons of OOCSS and BEM:

  • The HTML is more wieldy, with a lot of CSS classes.
  • You’ll have less flexibility to make CSS-only changes down the road.
  • When the design changes, you’ll likely need to modify the HTML classes.

In hindsight, OOCSS and BEM clearly would have been ideal frameworks to approach a project of this size.

CSS Learnings Link

  • Agree on a general approach across the team, or adopt an OOCSS-esque approach, like BEM.
  • Use a linter like Jacob Gable’s LESS Lint Grunt plugin24 to keep your LESS and CSS inline with your patterns.
  • Stay away from using :extends as much as possible on a big project. The way it works is smart, but the output is confusing and difficult to debug.
  • Use classes that are flat and reusable throughout the project, and continually analyze existing classes when creating new ones.

AngularJS Link

When I came aboard this project, I had a lot of experience with jQuery, jQuery Mobile and vanilla JavaScript, but I hadn’t touched AngularJS or similar JavaScript frameworks. The paradigm shift25 to AngularJS was a struggle for me at first; but, as many others have experienced, once I got over the learning curve, I fell in love.

Custom UI Components Link

What makes AngularJS a great solution for a big project like the Hawaiian Airlines website is the amount of flexibility it gives you to create custom UI components.

All of that flexibility means that there are a lot of ways to skin the AngularJS cat. In the beginning, we skinned it in ways that made our code difficult to test and difficult to reuse in different contexts. We’d have a directive that depended on some parent scope variable, and when that didn’t exist, the directive would break. We learned pretty quickly that if you don’t have an isolate scope in your directive, you’re asking for trouble.

Over the course of the project, we learned to think about AngularJS directives more as self-contained web components with an API.

AngularJS directives should be very self-centered. They shouldn’t know or care about the world they live in, so long as their basic needs are met, as defined by an API in the form of element attributes:

   excluded-airport-codes="['OGG', 'DEN']"

In the example above, the data you feed this directive via the attributes tells it how to behave and exposes a way to pull data back out of it, yet completely isolates its inner workings and template that renders to the DOM.

AngularJS Performance Link

While AngularJS magically data-binds everything defined on $scope two ways, this magic doesn’t come for free. For every item on $scope, a listener is created that detects changes to it. When changes are detected, it goes through and updates everywhere else it is used. Each time AngularJS loops through all of the items on $scope, we call that a digest cycle. The more stuff you have attached to $scope, the harder it has to work and the slower your digest cycle becomes.

In a big application such as Hawaiian Airline’s flight results, we started noticing laggy performance on tablets and slow desktop computers. Upon investigation, we realized that the page had over 5,000 watchers, and the digest cycle was taking several hundred milliseconds!

With a new problem and awareness of AngularJS’ performance, Nathan and Scott26 set out and built a handy tool to monitor AngularJS performance27, and they open-sourced it.

This tool ended up being key in troubleshooting and taming AngularJS performance across the website. Check it out: You can see AngularJS performance data on the live website28 by adding ?performance=true to any page’s URL.

AngularJS Performance Panel29

The performance panel gave us valuable insight into the number of watchers and overall performance of a given page. (View large version30)

In conjunction with the performance tool, we used AngularJS’ bind-once31 directive to ensure that we have watchers only on data that needed to change.

As a result, we brought our watchers from over 5,000 down to under 500, and we saw a nice bump in responsiveness on tablets and slow devices.

AngularJS Learnings Link

  • With great power comes great responsibility. Make sure you understand the inner workings of your chosen framework so that you harness it for good and not evil.
  • AngularJS has taught me an entirely different way to think about constructing a UI, such as breaking components down to their bare reusable essence, and avoiding DOM manipulation via jQuery altogether.
  • Think of directives as web components that expose an API into them, and keep your scope isolated from the outside world to avoid bugs and headaches.

Custom Form Controls Link

Booking travel online basically consists of a complex set of forms. So, designing beautiful custom form controls seemed obvious, and everyone (me included) was excited about it.

Looking back, if I had to pick the single most painful thing we did on this project, it would be the custom form controls.

You might not realize it, but those form controls that come out of the box in your browser do a lot of heavy lifting:

  • They ensure that people with accessibility challenges can still use them.
  • They keep track of focus, blur, active, inactive states.
  • They allow the user to cycle through all fields using the “Tab” key.
  • They figure out how and where to place dropdown menus based on the page’s scroll position.
  • They allow the user to type up to several letters to jump to an item in a dropdown menu.
  • They auto-scroll dropdown menu items for long lists.

When we decided to roll our own form controls, we took on the burden of reinventing the wheel and supporting all of the requirements above.

We ended up with a solution that uses AngularJS to hide the native HTML of select dropdowns, checkboxes and radio buttons, and replaces them with alternate markup for which we had full control over styling.

Old Form Controls32

This is what our custom form controls looked like. (View large version33)

While this approach gave us OCD-level control over every pixel, it ended up causing all kinds of obscure bugs and accessibility issues in complex situations, which we spent countless hours patching.

In the end, we decided to scrap these custom form controls in favor of their native counterparts. We realized that, while we couldn’t achieve the pixel perfection of a pure custom solution, we could get 99% of the way there just by using background images and pseudo-selectors on the native input HTML. In the case of <select> dropdown menus, we just styled the default look of the select menu and let the browser handle the look and feel of the actual dropdown of the select menu. For checkboxes and radios, we hid the default control off screen and then styled the label via pseudo-selectors.

New Form Controls34

These new form controls use 100% native code and achieve a nearly identical look (minus the native dropdown menu). (View large version35)

Jamie36 made a Codepen37 of these new form fields as a proof of concept.

Custom Form Controls Learnings Link

  • Rolling your own form controls, especially for dropdown menus, on a project of this size and complexity is not worth the hassle. The only thing you’ll gain is shiny controls.
  • Do what you can with native form code, and avoid replacing it with custom markup.
  • Try using background images, SVGs and pseudo-selectors to achieve the look you want.

Pattern Consistency Link

With a code base this big, pattern consistency becomes really important. Big code bases should look as though a single person developed it. In practice, this is easier said than done.

Anytime we developers code something, we can look back almost immediately and realize how we could have done it better. That’s just human nature. There’s always this temptation to change and improve one’s patterns. It’s a healthy but dangerous instinct.

I would argue that pattern consistency across a big code base is more important than doing something different in one place, even if you know the solution is five times better.

Think of it like the user experience of your code. Once you learn one pattern, you would expect it to look and work the same way everywhere else. If it doesn’t, then you’ll get bogged down in a costly spiral of troubleshooting and debugging in order to learn how the foreign pattern works — and you’ll then have to keep track of more than one pattern in your head.

When patterns are all over the map, you end up with steep learning curves and unproductive developers across the team or, even worse, individual developers who hold all of the knowledge of the patterns they’ve worked on.

UI Docs Link

UI documentation38

The UI documentation provides information about global styles, AngularJS directives and patterns. (View large version39)

One of our most valuable assets on the front end that helped us maintain pattern consistency (and, as a bonus, prevented my instant messenger from blowing up with questions all day long) was the UI documentation that we built and maintained throughout the project.

We used Yeoman to generate the scaffolding of new AngularJS directives, which in turn generated a demo page for that directive that we could build from. So, most of our documentation was created during the development of the component; it practically built and maintained itself.

We built the documentation directly into the local and development environments, so that anyone working on the project could access and maintain it anytime.

Code Reviews Link

This project moved so fast that each person barely had time to get their own work done, let alone pay attention to what their peers were doing. Our pattern consistency degraded over time as a result.

To combat this later in the project, we started doing peer code reviews. Before merging code into the main repository, a developer would request a review from a handful of peers, and they would not check in or merge their code until at least one team member had reviewed and approved it. At first, this workflow slowed things down a bit, but the result was that our patterns aligned, we caught bugs, and knowledge of the code was better disseminated.

Guidelines Link

While JSHint40 helps with enforcing some JavaScript standards and the UI documentation helped as a general reference, a higher level of consistency is still missing in the front-end code base. Looking back, it would have been helpful to establish some detailed guidelines41 for the JavaScript, HTML and CSS that could be referenced and followed throughout the project, and to enforce as much as possible via Grunt tasks.

Pattern Consistency Learnings Link

  • Changing patterns for the better is a good thing, but only if it can be done across the entire code base in one fell swoop and clearly communicated to the team.
  • Code reviews help to align patterns, catch bugs and spread learning.
  • UI documentation is a great reference for everyone involved. The next time around, I would look into creating a living style guide42 — self-generated and self-maintained from the source code, via a tool like KSS43.
  • Document and enforce detailed JavaScript, HTML and CSS style guides, similar to Airbnb’s for JavaScript44, Google’s for JavaScript45, GitHub’s for CSS46 and Google’s for CSS and HTML47.
  • Use Grunt or Gulp tools wherever possible to automate the enforcement of patterns.

Conclusion Link

On a project of this size and scale, it was really hard to see the forest for the trees until we looked back from the other side. We made plenty of mistakes throughout the project. Some we recovered from gracefully; with others, our efforts were too little too late, and we have to live with them.

A wise person once said that making mistakes is a rite of passage to success. It makes us better. More importantly, learning from each other is how we get better as a community, so that history doesn’t repeat itself.

What really matters in the end is how well a website works and the experience people have while using it. And we’ve ended up with something we’re all really proud of, an experience that makes you want to sink your toes in the sand, sip on a Mai Tai and get lobstered by the sun.

I hope this story helps you start your next big project and arms you with the foresight to go forth and conquer.

(vf, ml, al, jb)

Footnotes Link

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47

↑ Back to top Tweet itShare on Facebook

Cory is a UI designer and developer with over 15 years of experience improving the web. He runs a boutique agency in Boulder, CO called User Kind, and has worked on projects with Google, Mozilla, W3C, and many others. In his spare time he likes to run, hike, travel, surf, and build tools that help developers make the web faster such as and

  1. 1

    Not to criticise here, but at what point did you decide that you wouldn’t care about users not running Javascript?

    • 2

      Hi Juanjo,

      I think that decision was made on day one when it was decided to use AngularJS and SPA where possible on the site. It’s not so much that we don’t care, it’s that most of their users have JS enabled, so supporting would be too costly to be worth it on a codebase of this size and scope.

    • 3
      • 4

        Also, the homepage of the site and help section render fine with JS disabled, which is more than can be said for some sites I’ve seen. Awesome design and seems to load fast (:

  2. 5

    This is a great overview of your process! We’re going through a similar project (much smaller) and found some valuable lessons here.

  3. 7

    Thanks for the nice write-up!

    Just one point from me:

    .my-section {
    h1 {.header-uppercase-1}
    p {.bodycopy-sans-3}

    Then some SEO guy decides to change h1 to h2 or something else and all you tag styling is lost. So I would avoid cascading and go for BEM classes (even with messier HTML).

  4. 9

    Laurent Lemaire

    December 8, 2015 10:25 pm

    Great article! Very inspiring and always useful to see issues and things learned from others.
    I’ve 3 questions for you:
    – Can you give us an idea of the size of your team (frontend + backend + qa ..), I’m wondering for what team size did this processes worked.
    – I’m looking for good tools to show and maintain ui guidelines, code standards and overall documentation (for backend processes..), what would you advice?
    – And a more practical one, what library have you chosen for autocomplete inputs (like your airport fields, love them ;-))?

    Thanks again for this great article.

    • 10

      Hi Laurent,

      Thank you!

      “Can you give us an idea of the size of your team (frontend + backend + qa ..), I’m wondering for what team size did this processes worked.”

      The frontend team is about 10 strong right now, backend I would guess is ~50, QA + Mgmt is around ~20.

      ” I’m looking for good tools to show and maintain ui guidelines, code standards and overall documentation (for backend processes..), what would you advice?”

      There are some great tools for auto generating your docs from your source code (KSS for CSS, YuiDoc for JS, or generic generators like Yeoman or Jekyll for everything in between). The more you can automate, the better chance you have at a living and maintainable set of docs.

      I also like the idea of using docs as your development sandbox for creating components. They practically write themselves that way.

      “And a more practical one, what library have you chosen for autocomplete inputs (like your airport fields, love them ;-))?”

      We ended up starting with the Angular Bootstrap Typeahead directive, but had to modify it quite extensively to get what you see on the site. It’s practically a different script now.

  5. 11

    The fail notice is not very intuitive. All I wanted was Flight and Hotel on particular dates. Methinks might be better off going to a travel agent.

    We need help in order to complete your request
    error Hotel component is not available on the selected dates. Please try a new search selecting different dates.

    • 12

      I totally agree. When you do anything but a flight search from the homepage, you end up on a third party package booking site that is a totally different system/site from the new one referred to in this article.

  6. 13

    Great read! Thanks for sharing. A lot of helpful insights.

    A couple of things I noticed while looking across the site – in purchasing a ticket the bread crumb links also act has a progress bar, I would steer away from this, confusing for users.

    Also on seat selection, the front of the plane is not labeled. While Western users will expect row 1 to be at the front of the plane, many Asian airlines have row 1 at the rear of the plane.

  7. 14

    The new website is horrible…slow, unresponsive at times, and I am not the only one who feels like this; many of my friends are voicing the same thing. Bring the old website back

    • 15

      I do not work with the team that built the site but I can tell you the old site isn’t coming back.

      I can also tell you your comment won’t be helping matters. If you really care, try and be a bit more specific and actually point out an issue.

    • 16

      Thanks for your feedback. Interesting fact: The old website codebase was over 10 years old! The good news is that we now get to focus on improving what we’ve built, so we take comments like this to heart.

  8. 17

    What a great article. There are so many tools that I myself need to learn as I read through, things like Grunt, Angular JS, OOCSS, BEM, and also a way to define and create an informative UI Document as well as creating a patter for every other developer to use. I think I would need to follow your advice at the end of each section so that the next time, I am going to work on a gigantic project like yours, your advice would be very helpful and comes in handy.

  9. 18

    Hey…gr8 post. lots of people learn from this & keep in mind before developing.
    Thanks for sharing :)

  10. 19

    Panayiotis Velisarakos

    December 9, 2015 1:27 pm

    Thank you for sharing! Great effort has been put into this, really complex, project but I think that it should be responsive, and the page weight at 3ΜΒ without the images is way to much.

  11. 20

    Frustrated Booking User

    December 9, 2015 2:07 pm

    So I clicked on the site, the first thing I did was type London in the first box. It says invalid airport. It gives me no other explanation, choices or suggestions. Does the airline only fly from the US, I have no idea it gives no indication?

    “one of the best airline-booking experiences on the web”

    Next I just type Hawaii in the next box and click find, invalid airport. Guess I’m forced to type one letter at a time and click a suggestion then.

    “one of the best airline-booking experiences on the web”

    Finally able to select an airport, getting a white loading screen (was an image meant to be here?)

    “one of the best airline-booking experiences on the web”

    Next I have to choose a flight, but how? Oh you have to click the price, is that a normal design pattern? Hang on I click the price and the list changed, now what? Oh wait this is a different list for departures but the only thing that has changed of any significance is the title?

    Okay, got to the next screen, but on this page you select the radio next to the price, not the price itself?

    Actually I’ve changed by mind let’s hit back a few times, oh, “Sorry! There’s something wrong with your search request. Please check the Origin/Destination and your travel dates and try again.”

    “one of the best airline-booking experiences on the web”

    • 21

      Frustrated Booking User

      December 9, 2015 2:15 pm

      Also, why is everything on the ancillary content pages two clicks deep?

    • 22

      You know you could have brought all that up without actually trying to be rude?

    • 23

      Thanks for your feedback. There’s certainly room for improvement and I’m looking forward to digging into all the feedback to see how we can create a better experience.

  12. 24

    Tarik Zakaria Benmerar

    December 9, 2015 4:53 pm

    I have personally worked on a separate custom field project for The code is live and yes it was complicated to do it. We haven’the adapted it to touch screen but worked very well on desktop. I am really curious about the kind of issues you I want to compare with our own experience.

    For now, we have even front-end validation and the backend dev’s don’t need to master js. The controls include : text field, select field, checkbox, radio, tag fields and others.

  13. 25

    Hi, nice insight. Thank you for sharing. I’m wondering if you can share your Git branching model.


  14. 26

    Very details article. I appreciate the thought and work you put into this process. Your insight and methods are greatly appreciated, and I look forward to more content from you.

  15. 27

    Thank you very much for sharing this interesting process! Congrats on the results! I’m having the same struggles you had with some smaller projects. I just have a few questions about the choices your team has made:

    – Why is the current website not responsive? (with a separate mobile website)
    – Why did you chose less over sass? ( I think sass a much more powerful language )


    • 28

      It was decided before I came on board that the site would be semi-responsive to support Desktops and Tablets…so it scales down to 1024px as a min-width. At the time we started, the mobile website was just completed, so I dont think it made sense to increase the scope of the project for mobile users.

      3 years ago LESS was pretty much at parity with SASS feature and adoption wise…fast forward to now and it seems like SASS is the clear winner. For what we’ve used LESS for, I’ve been happy with it.

  16. 29

    Thank you for sharing!
    I learned a lot from this.
    BTW great work !

  17. 30

    Home Page overview:
    While choosing Dates, it’s very confusing. You don’t know what you have done. So once you choose the Departure, I think just close it (fadeout) and let users to click on Return Date. I know you guys are using Angular to live reload but still quite confusing.

    And agree, this site contains a lot content and definitely it will be heavy lifting but I prefer to have at least fake loader while changing the content or loading another set of modules because that helps user to think “oh yeah something is happening…”

    Page speed is 74/100, should be above 85 to get better feeling.

    Good luck.

  18. 31

    Hi Cory,

    Thanks for sharing this nice article. The site looks beautiful. One quick suggestion on Homepage, when switching between tabs, (Flights -> Package, Hotel->Package), I noticed that the background image stretches because of cover property(.ha-homepage .header-1.hero-2).

    Congrats and Goodluck.

  19. 32

    Great article, Cory.

    It totally resonates with me where I’m at right now as a UI dev, as I’ve spent the last 3 years working on a total re-build of a massive eCommerce site (everything from infrastructure, to brand new back-end & UI codebase, and implementing a new content management system).

    Like you, we’ve learnt alot of lessons along the way. We’ve made many mistakes; fixed some, and ignored others (for now).

    We’ve changed processes during the project life cycle, which has been extremely frustrating but beneficial in the long run – e.g.
    – New Git workflows.
    – No task runner initially, then moved to Grunt and now Gulp.
    – Used native CSS but now fully migrated to Sass / SCSS.
    – Static style guide / component library built retrospectively to aid on-boarding of new devs.
    – Single VM to aid integration with back-end code.

    Your concluding statements are so true. As are your comments on:
    – Pattern consistency, even if the pattern is not as good as it could be.
    – Documentation and living style guides.
    – Using native form controls.
    – Methodical approach to CSS naming conventions, and using OOCSS principles (adding more classes to HTML).

    Thanks again for a great write-up.

  20. 33

    Thanks Cory, that’s really great article. I’m working on some similar projects just now and I’m glad that I’d already made some good choices but likewise, have already made plenty of bad ones too!



  21. 34

    Andy Leontovich

    December 10, 2015 5:11 pm

    Thank you for the great insight! Would you be willing to share the disciplines covered in your team? What did your managers manage? How was the team assembled and what was each group responsible for? We have some large projects coming up and it sounds like you had a great team experience.


  22. 35

    Hi and thanks for the write up! I appreciate you putting effort in writing down all your hard earned lessons from project of such magnitude. It’s always interesting to see how people tackled all sorts of technical and non-technical problems.

    However, I can’t help but notice that the site not only isn’t the best experience I had on airline booking, but it’s simply unusable.

    I tried booking a flight, entered ‘berlin’, and nothing happened (no suggestions of an airport, information that I got the name wrong or anything of that matter). I filled up the rest of the form, and all I got was “$rootScope.$apply already in progress” somewhere along the steps.

    Like you said, there’s always room for improvement. We’re talking about the front page, and number one purpose of the website – booking flights, which during my visit was not possible.

    I hope you manage to resolve all the problems. Deadlines set in stone months in advance never work out well, and make us cut corners where they shouldn’t be cut, skip tests that should be performed etc. Please don’t take it as a criticism of your work, but rather my experience of the website at this point in time.

    Best regards,

    • 36

      Thanks for your feedback. Yeah I think you (and a couple of others on here) nailed a key problem we need to solve: Properly notifying users when Hawaiian Airlines doesn’t service the entered city or airport code. We’re on it!

  23. 37

    Thanks Cory for a great write up! I’m working on a similar project in terms of scale and like your team we’ve been making our own mistakes and have our own lessons learned. One of the things I’m really curious about is how your frontend team handled testing your javascript code? Do you guys have any automated JavaScript unit testing, such as QUnit or Jasmine? Also, do you mind sharing a list of the Grunt plugins you guys used? My team is currently integrating a task runner into our stack and we’re still exploring the various plugins that could increase our productivity and alleviate some of the headaches we’ve been experiencing.

    Lex French

    • 38

      Hi Lex,

      We do have some Jasmine unit tests for our angular services and directives. When we were in the sandbox environment, they were run on JS file save, and on git push/build. When we hopped over the fence to the .NET environment, we had no way to automate the running of our tests :(. We still run them manually via a gulp task though. Apparently Visual Studio Online has lots of grunt/gulp build support, so we’re working on moving everything there, and can bring all of the front-end automation tasks back to life.

      Here’s some of the tasks I like to use:

      HTML Hint – Catch those pesky unclosed tags (not needed if you use Jade)
      LESS/CSS Lint
      Code Complexity
      Live reload or Browsersync
      ng-annotate – Add, remove and rebuild AngularJS dependency injection annotations
      ng-templates – Package all the html partials into a single javascript payload
      unit testing

  24. 40

    That’s really a nice article, and I would say you really covered almost everything and actual problems faced by developers during a project of this large size. Here are my 2cents to it.

    I would add SMACSS also to list of CSS methodologies. I recently did a project of similar size, and we baselined OOCSS for identifying reusable CSS components, BEM for CSS class naming conventions and SMACSS for file naming and managing convention. And this approach has really helped us keep CSS tidy.

    On JS side of things I would say its also good to have a code style checker in place (JSCS) this helped us keep the coding style exactly same.

  25. 42

    As I’ve always warned people, when they use .NET anything on the web, .NET everything is foreign to the web and when you start handing things off to it, you will have problems … guaranteed … as your article mentions.

    I have never run a project where using Microsoft technologies on the web did not cause issues of some sort interfacing it to standard methods and technologies used by everyone.

  26. 43

    Not sure when they went live, but I can no longer find my itinerary on the Hawaiian Airlines website… says that “this field is invalid” …

    That said, this was an excellent piece on getting a huge task off the ground. Many things to consider wrt design and coding that apply to smaller projects.

    Good work.


↑ Back to top