Unity Dashboard: Lessons Learned Scaling Frontends, Culture, and Process

Over the past 4 years, Unity has undergone tremendous growth as a company. Our engineering organization has expanded from around 200 to over 1800 people globally. Along the way, the number of products and platforms we support has proliferated.

Amidst this rapid scaling, we‘ve faced the challenge of evolving our frontend architecture, development practices, and team culture to keep pace. A key inflection point was the initiative to unify our fragmented product dashboards into a cohesive user experience and platform.

In this post, I‘ll share the story of this ongoing journey and the valuable lessons we‘ve learned along the way. While our specific solutions are tailored to Unity‘s context, the principles and patterns we‘ve adopted are relevant to any organization scaling the development of customer-facing web applications.

The Legacy Landscape

Two years ago, the state of Unity‘s product dashboards was emblematic of the growing pains we were experiencing as an engineering organization. Fueled by organic product expansion and multiple acquisitions, we had accumulated a patchwork of disconnected frontend codebases and design languages:

State of Unity dashboards in April 2018

Some of the major issues with this situation:

  • Disjointed user experience across products
  • Difficulty in cross-linking or integrating products
  • Duplicated development effort and lack of code reuse
  • Inconsistent tooling and practices across teams

The negative impact on our customers and business was tangible. Users struggled to navigate between products and regularly voiced frustration with the lack of cohesion. Conversely, our engineers were mired in project-specific silos, unable to easily share knowledge and solutions between teams.

Envisioning a Unified Platform

To address these challenges, we set out to reimagine our dashboards as a unified platform. The high-level vision was to consolidate all products under a single domain with consistent navigation, design language, and frontend architecture.

Creating this integrated experience would be a staged journey involving both technical and organizational transformation. While the end state was clear – a single web application serving all products via shared components and infrastructure – we had to chart a pragmatic path to get there.

Laying the Technical Foundation

A core decision was choosing the frontend tech stack that would power our new unified platform. After extensive research and prototyping, we landed on the following:

  • React as our view layer
  • TypeScript for static typing
  • Webpack for bundling and code splitting
  • Cypress for end-to-end testing
  • Storybook for UI component development and documentation

This stack provided a solid balance of ecosystem maturity, developer productivity, and application performance. Just as importantly, it aligned with industry best practices and the skill sets we wanted to cultivate in our teams.

Of course, we couldn‘t migrate all our legacy codebases to this new stack overnight. We needed an incremental adoption strategy that allowed us to:

  1. Develop new features using the modern stack
  2. Gradually replace legacy code with minimal disruption
  3. Have old and new code coexist in production

Our solution was to build a core "container" application in React that would serve as the foundation for all new development. Legacy Angular apps would be embedded within this container using iframes and communicate via cross-frame messaging. This allowed us to start building new features with React immediately while gracefully retiring old code over time.

Here‘s a simplified view of this architecture:

Legacy app integration architecture

To facilitate this coexistence of old and new, we adopted a monorepo structure using Yarn workspaces. This allowed us to house both the legacy and modern codebases in a single repository while still keeping their dependency management separate.

Over time, as we ported features to React, we could shrink the legacy bundle and expand the new one until eventually, the old code was eliminated entirely.

Sharing Code at Scale

Beyond the technical foundation, we needed better ways to share code and enable collaboration across teams. This was especially crucial in a monorepo structure where the lines between projects can blur.

To address this, we established clear boundaries and ownership around different classes of components:

Component ownership model

This model allowed us to scale UI development across teams while maintaining high quality and consistency. Cross-cutting components could be shared universally via the design system while product-specific elements remained fully owned by individual teams.

To further promote reuse and alignment, we established a living style guide powered by Storybook. This served as the definitive resource for our UI building blocks:

Living style guide powered by Storybook

Having this central hub for components dramatically streamlined designer/developer collaboration and reduced duplication of efforts across the organization.

Enabling Autonomous Teams

While shared tools and components were critical, we also wanted to preserve the autonomy and agility of individual product teams. Our frontend architecture and development practices had to strike a balance between centralized governance and local flexibility.

Some key ways we achieved this:

  • Establishing coding conventions and best practices via shared ESLint configs, unit testing strategies, and code review guidelines
  • Providing a suite of reusable frontend infrastructure as npm libraries teams could adopt incrementally (e.g. logging, error handling, analytics, etc.)
  • Empowering teams to make localized tech decisions within the guardrails of our global standards

This federated model allowed us to maintain a coherent frontend platform while still enabling teams to move quickly and own their product experience end-to-end.

Transforming Our Engineering Culture

Arguably the biggest shift in our journey was not technical, but cultural. Decomposing the barriers between frontend and backend, web and native, and product and infrastructure was key to scaling effectively.

Some of the key mindset and process changes we championed:

  • Shifting from project-based teams to durable, cross-functional product squads
  • Instituting an internal open source model for frontend infrastructure contributions
  • Investing in automated testing and continuous delivery to enable rapid iteration
  • Prioritizing ongoing learning and knowledge sharing (e.g. lunch and learns, hackathons, etc.)

By aligning our people and processes with our target architecture, we were able to unlock new levels of collaboration and execution across the organization.

Measuring the Impact

The results of our unified frontend platform speak for themselves. In the span of 18 months, we saw dramatic gains across key productivity metrics:

Frontend productivity metrics over time

Beyond the quantitative gains, we also saw significant improvements in developer satisfaction and product quality. By providing a better-architected foundation for frontend development, we were able to attract and empower top engineering talent.

In tandem, our consolidated codebase and design system greatly reduced defects and inconsistencies in our product UX. We could deliver polished, professional applications much more quickly and confidently than before.

Looking Ahead

While we‘re proud of the progress we‘ve made, our frontend journey is far from over. As our product suite and user needs continue to evolve, so must our tools and practices.

Some key areas of continued investment for us:

  • Deepening our design system to cover more advanced component patterns and use cases
  • Expanding our frontend testing strategy to better balance unit, integration, and E2E coverage
  • Exploring new approaches to state management and data fetching (e.g. GraphQL, SWR, etc.)
  • Cultivating a community of frontend practice to continuously elevate our craft

At the architectural level, we‘re also keeping a close eye on emerging trends like micro-frontends, server-side rendering, and edge compute. While we‘re happy with our current React foundation, we want to remain open to new innovations that could further optimize our UX and productivity.

As the web platform matures and user expectations rise, the role of the frontend engineer will only continue to expand in scope and importance. Investing in scalable frontend architecture and empowered product teams is now table stakes for any company looking to deliver best-in-class digital experiences.

Parting Wisdom

For engineering leaders and practitioners looking to level up their own frontend practices, I‘ll leave you with a few parting recommendations:

  1. Align your architecture with your organizational model – technical decisions and team structures are inextricably linked
  2. Bias towards incremental adoption vs. big bang rewrites – it‘s ok to have multiple generations of your stack coexist in production
  3. Invest in a design system early – it will pay massive dividends in UX consistency and development velocity
  4. Empower autonomous, cross-functional product teams – they are the key to scaling effectively
  5. Champion a culture of learning and collaboration – the soft skills are just as important as the technical ones

While there‘s no one-size-fits-all playbook, these principles have served us well in scaling frontend development at Unity. By continuously evolving our tools, practices, and culture, we‘ve been able to keep pace with our explosive product and organizational growth.

I hope this glimpse into our journey has been insightful and I welcome any questions or experiences you‘d like to share. If solving challenges like this excites you, we‘re always looking for outstanding frontend engineers to join us. Thanks for reading!

Similar Posts