tech blog

AppNexus is today’s most powerful, open, and customizable ad tech platform. Advertising’s largest and most innovative companies build their businesses on AppNexus.

Renovating Microservice UIs

| Comments

AppNexus Console has evolved from a simple PHP application to a highly complex platform, built using a micro-services architecture. During this transition, we learned that scaling applications is not easy. We had to find a new approach that would simplify our architecture, reduce deployment times, and enable testing release builds on production environments. We chose to build our solution using a combination of Node.JS, Express, and Docker — creating an AppNexus special sauce that we call Resin UI.

Before I explain the goodness that is Resin UI, it is worthwhile to go through a brief history of Console.

AppNexus Console 1.0

At the beginning, Console was simple. It was built on PHP using Zend Framework (an open source PHP application library), and it served templated HTML for each page in Console. This was easy for a single engineer, who worked on both PHP and HTML, to maintain. As the web development evolved, so did Console. It moved from raw HTML to a collection of JavaScript modules that formed the UI. The code base wasn’t the only thing that changed: the development team scaled up from a single engineer to over 50, in just five years.

As AppNexus grew, the UI team was split into two dedicated teams to better align with our customers. We now had two teams sharing one monolithic code base which presented code management, ownership, maintenance and deployment issues. Our solution was to split the JavaScript modules by team, where each team would be responsible for their own code base. However, we still experienced issues with deployment and code management, which pushed us to come up with a better approach. We decided that the best solution was to move to a micro-service architecture.

The Era of Micro-Services

With AppNexus’ migration to a micro-service architecture, each team became responsible for their own application, on its own servers, using Virtual Machines (VMs). Each VM had its own virtual CPU, memory, hard drive and OS. This gave teams the flexibility to control their own app and release process, while allowing our dedicated DevOps team to maintain the systems that virtualized the services.

With the migration, we came to the conclusion that we needed a centralized service to control Console authentication, styling and configurations. We also required a router to control traffic and direct it to the corresponding app depending on the page a client visited in Console. These were simple services that we built on Node.JS, and they integrated easily with all our apps; new and old alike.

Resin to the Rescue

As the number of engineers and apps increased, we required more and more VMs. It quickly reached a point where we had too many VMs to maintain, and it became apparent that we lacked a standard way to build apps. This prompted one of our teams to come up with a simple solution - Resin. Inspired by Console services, Resin was a simple Node.JS server framework and toolset that used Docker, a new type of virtualization system. Docker requires noticeably less overhead than VMs do. It does so by sharing its operating system across instances—this is known as “containerizing” the app. Resin would now serve up a web application built with React.JS that integrated nicely in the AppNexus ecosystem.

Resin UI

This brings us to today. As the new Resin architecture matured, I realized that we could take it a step further and move to a single server architecture with abstraction around external services. The single server system hosts multiple UI applications which would allow us to collapse the number of containers required to run UI applications and thus, reduce our hardware costs. Resin UI is born!

It was relatively easy for us to convert container apps into the single server Resin UI architecture since most of them were single page apps that relied on little, or no server code. Motivated by Ember’s built-in deployment, I designed Resin UI such that when we release a Resin UI app, the generated JavaScript, CSS, and image files, get uploaded to a CDN. Resin then tells the server what files to access, and where they can be accessed. With this new architecture, all the server must to do is serve up HTML.

Our web engineers can now focus on building web applications without having to worry about server maintenance. Since the app is Resin based, and comes with the same build commands, Resin UI is a seamless transition from an engineer’s point-of-view.

Applications built on Resin UI can be developed locally (with built-in support to AppNexus APIs and services required for development) and releases now take less than 30 seconds! In contrast, our monolithic PHP UI required a development server box and took about an hour to two hours to release. Resin UI has freed teams from a fixed release schedule, empowering them to release ad-hoc with limited overhead. We are delivering new features and bug fixes quicker and more often to customers, providing them a much better Console experience.

As AppNexus continues to grow, engineers have continued to see and improve the whole system (one of our core values) —even parts of the development ecosystem that clients will never see. With innovations such as Resin UI, we are working to make Console faster and ensuring that our customers get the best experience possible!