On the 1 year anniversary of launching the latest version of WeWork.com, we look back on the history of the website — all 6 versions! — and share some learnings and reflections picked up on the way.

The Prologue

WeWork at one point was a wee little startup with zero software engineers on the team. True to our nature, our team figured it out (our co-founder Miguel actually writing the original code), and the website was born:

For the purposes of this post, I’m going to focus on the post 2012 world, when WeWork had full time software engineers on staff.

WeWork.com #1: Wordpress, the Inevitable (Jan. 2013)

Open WeWork Buildings: 7

WeWork Countries: United States

WeWork.com #2: Wordpress, a Newer Theme (Nov. 2013)

Open WeWork Buildings: 9

WeWork Countries: United States

I’m combining versions 1 and 2, as the entire engineering team was comprised of three people at the time and we outsourced the website development to a member company. It was 2013. WeWork had fewer than 10 buildings, and we wanted to focus our limited engineering bandwidth on building our internal social network, member services like booking conference rooms, and a billing system. Long story short, Wordpress was perfect for our needs at the time. Content managers could create landing pages quickly, and adding new buildings was as easy as creating a new Building Post Type through wp-admin.

Fast forward to October 2014. Our engineering team had doubled in size and we started running into a few issues with the website.

Problems:

Content Management : Uploading new building data into wp-admin was tedious and error prone

: Uploading new building data into wp-admin was tedious and error prone Data Availability : Wordpress data wasn’t immediately available in a query-able API

: Wordpress data wasn’t immediately available in a query-able API Styling: We were locked into our Wordpress template, re-skinning the website would require creating a new Wordpress theme.

WeWork.com #3: A Basic Rails App (Dec. 2014)

WeWork Buildings: 25

WeWork Countries: United States, Israel, United Kingdom

We expanded into a robust engineering team — 14 engineers, mostly ruby on rails developers — and our internal services started to grow in scope and functionality.

Engineering Considerations:

Rails Experience : Go with what you know

: Go with what you know Rails Backend : Handles complexities with our Building data model and an API layer out of the box

: Handles complexities with our Building data model and an API layer out of the box Rails Convention : Better developer experience compared to Wordpress

: Better developer experience compared to Wordpress Ownership over UI: jQuery + Sass + Asset Pipeline

After hacking around in our Wordpress repo for far too long, we could barely contain our excitement:

We built out rails views and updated styles quickly. We streamlined content management with an Active Admin CMS. Our internal services consumed our shiny new Rails API. We were living free and easy — thanks, idiomatic Rails!

Unfortunately, our site felt so…how do you say…2009. In spending all of our time getting the content up, we couldn’t focus on fancy UI enhancements or modern JS techniques outside of a few jQuery animations. SO MUCH TOGGLING.

React had been out in the open source community for about a year and a half at this point. We saw the buzz and like true ignorant explorers with little oversight, wanted to try it out…in production! We had first tested out Angular on a new signup flow but we didn’t appreciate the bloat it added to our application.js bundle. As was commonly noted with Angular, it felt like we were using a forklift to pick up a feather, albeit a moderately heavy feather.

I’ll leave the Angular vs React debate for a different time, but we were curious about React and wanted to test it out on our beautifully static Market Page:

In a previous post I went over the pros of switching from reflux to redux which does a better job explaining the underlying tech for this flow.

If you’re following closely, yes, this means that in one rails app we had pages that included one or many of the following: jQuery, Angular, and React. Also, this is probably the perfect time to mention we didn’t have a single test around any of our UI. …and look at the results!

Little oversight + inexperience = no tests and sloppy code, BUT we were moving quickly and that’s all that mattered — wears trash bag to protect from impending hurricane.

Problems:

Slow Development : we were including far too many modules with bower, and asset pipeline re-compilation wasn’t the speediest of things

: we were including far too many modules with bower, and asset pipeline re-compilation wasn’t the speediest of things Slow Deploys : similar to the problem above, too much bloat

: similar to the problem above, too much bloat Random Breakages : We had a lot of spaghetti logic injecting different bits of data from our Rails backend into our client, leading to a constant stream of UI bugs.

: We had a lot of spaghetti logic injecting different bits of data from our Rails backend into our client, leading to a constant stream of UI bugs. Testing and Monitoring: With the exception of our minuscule rspec suite, we’d deploy and hope for the best.

WeWork.com #4: Static Site Generator (Sep. 2015)

Open WeWork Buildings: 54

WeWork Countries: United States, Israel, United Kingdom, Netherlands

With React, we caught the modern Javascript bug, but we were in the middle of an existential crisis. Who are we? What are we? Are we just a mere collection of landing pages? We felt like we could drastically simplify our workflow, and started exploring static site generators on top of Node.

Engineering Considerations:

Static Site Generator: Lightning fast deploys — through the use of smart caching — and easy developer setup

Lightning fast deploys — through the use of smart caching — and easy developer setup Fewer Random Errors: If it deploys (compiling every page) it works

If it deploys (compiling every page) it works More JS Please: Our SSG Roots, was built on top of node, giving us a universal language for client and server/compiler

Things were looking and feeling great. We could still use React to add a little sugar on top of our more simplified marketing site. We even wrote an article about how much we loved working with a static site generator.

Unfortunately, when you have stakeholders who want complex lead submission and signup funnels, we started to reconsider our static lifestyle.

Problems

Abstracted Build Process: Our static site generator made it difficult to inject React server rendering into the abstracted away compilation step.

Our static site generator made it difficult to inject React server rendering into the abstracted away compilation step. Not a Single Page App: We weren’t taking advantage of something like react-router to create the SPA feel. All page transitions required full page loads.

WeWork.com #5: Experimenting with Node (Feb. 2016)

WeWork Buildings: 66

WeWork Countries: United States, Israel, United Kingdom, Netherlands, Canada

At this point all of our pages were Jade templates with a few client rendered React components on top. WeWork was starting to expand its global reach, and we knew buildings in Asia and South America were coming down the pipeline. This website needed to work for different browsers, in different regions, on different devices. For this main reason, along with SEO concerns, we knew we had to embrace a universal, server rendered, React application.

Engineering Considerations:

React : Add React as main UI builder

: Add React as main UI builder Server Side Rendering

Single Page App!

As a transitional step before rewriting everything as React components, we compiled our Jade templates, and inserted them inside — dangerouslySetInnerHtml — a parent React page component.

With all of our crucial pages now wrapped in a React page component we were able to take advantage of server side rendering for the SEO benefit, and react-router to give us that single page app zippiness. This also gave us the ability to slowly rewrite each page in React as we worked on new features and designs.

EVERYTHING IS GREAT LET’S CELEBRATE THE REPO IS PERFECT WHAT COULD POSSIBLY GO WRONG!

A few months after completing this effort, we were asked to completely redesign WeWork.com. Rather than continue in this half-jade-half-react-component world, we had the luxury to greenfield an application using everything we’d learned from the previous 3 years.

Problems

Still No Tests : With the added server render complexity, and no official QA process pre and post deploy, it was hard to know when things broke.

: With the added server render complexity, and no official QA process pre and post deploy, it was hard to know when things broke. Maintenance: We never kept node nor any of our packages up to date

WeWork.com #6: John Quincy Adams (June 2016)

Open WeWork Buildings: 93

WeWork Countries: United States, Israel, United Kingdom, Netherlands, Canada, Germany, China

If you haven’t figured it out already, John Quincy Adams was the 6th President of the United States, and the code name for this effort, our 6th rewrite, was “Quincy”.

Engineering Considerations:

Finally, Testing: Literally all the tests. When we moved over to the node app (#5) we added unit test coverage, but didn’t focus on functional or UI regression.

Literally all the tests. When we moved over to the node app (#5) we added unit test coverage, but didn’t focus on functional or UI regression. Server rendered react redux application: We set the tone in the node app and wanted to continue it here

We set the tone in the node app and wanted to continue it here Api Proxy Server: Handles all requests from the client. We had many disparate services — Contentful, Smartling, internal applications — and this would significantly clean up our main wework.com repo

Quincy became responsible for the wework.com UI.

Expanding on the makeup and tech in this new application will most definitely require a follow up post or two, but allow me to whet your appetite:

Webpack bundled express server to handle security headers (helmet), compression (shrink-ray), and ultimately react server rendering

CSS modules with Sass for styles — I’m so ready to rumble about css modules vs inline styles if you want to take this outside

Redial to manage ordering of API requests — server vs client only, and blocking vs non-blocking on client

Redux and redux-api-middleware for consistent API request handling

React-storybook for snapshot testing and a better UI development experience

Smoke tests for sanity checks —confirming all pages have canonical and hreflang tags, testing redirects — with casperjs

Prettier + lint-staged ;)

A Few Takeaways

Testing

Be careful of the looks good, ship it mentality.

As a smaller startup with limited engineering resources it was quite easy for us to ignore testing. When you’re barely holding on to the startup rocket ship, product and features rule the day and if you’re not careful, neglecting testing becomes a part of your team’s culture.

Examples of tests from the Quincy suite that have caught bugs before deploying to production:

Functional tests caught our Signup flow breaking — literally instant money for the company saved. Snapshot tests caught when our placeholders for our form fields got out of alignment Smoke tests caught missing canonical tags and href lang tags, our SEO savior

Speed and Performance

Similar to testing above, page speed is often neglected. It’s a major topic with which we’re constantly tinkering: brotli compression, http2, and webpack chunks to name a few strategies. Unfortunately, bloat and speed issues tend to build up over time. It’s hard to know how your specific feature affected the site as a whole.

Main takeaway here, if you don’t pay attention to all the libraries and bloat that you’re adding to the page, it will hurt you. Maybe not today, but definitely in the future.

Prioritize Maintenance: Keep packages up to date

After completing the first version of Quincy, we convinced our product manager to reserve 8% of our 2-week sprints for maintenance.

Bigger updates like webpack 2 and react-router 4 required us to plan in advance, but by and large we were able to use this maintenance buffer to keep our apps up to date with the latest stable package releases. Also, most package updates are trivial as we rely on our now robust suite of tests — another win for testing!

Build For the Future

We’re at 200 buildings, 16 countries, and 13 languages now and won’t stop growing any time soon. With our new robust infrastructure, test coverage, and focus on cleaner more maintainable code, Quincy allows us to focus on building features quickly and less on fires. It took some creative alignment with our product folks, but making the investment in engineering was more than worth it.

Final Takeaway

Get a designer to make a mascot for your team. Then you can take your own family photo celebrating the launch (yes that is our mascot on our t-shirts):

Also, if you want to join the team — and not miss out on ridiculous t-shirts that take way too long to explain to your friends — we’re hiring.