Wrike is sunsetting its AngularDart usage

WrikeDEV
Wrike TechClub
Published in
16 min readMay 13, 2021

In this article, we’re shedding light on Wrike’s technology stack — how it used to be and how we envision its future. We’ll explain why we chose Dart as the main language for frontend development five years ago and how we’ll change our tech stack in the future.

1. What is Wrike?

2. A brief history of the technology stack

JS and EXT
Why DART?
Current State
Dart Ecosystem

3. Reasons for abandoning AngularDart

AngularDart
OverReact
Flutter for web

4. Possible migration options

Language
Choosing our framework
Code organization and build
Data flow
Component composition
Summary

5. Migration plan

Language agnosticism
FAQs

6. Conclusion

1. What is Wrike?

To fully understand our technical solutions, it’s necessary to explain Wrike as a product. Wrike is a large SaaS platform for project management and team collaboration. And by large, we’re not just talking about the number of features, but also the code base. The product has grown and evolved over several years. We’ve come a long way from this:

Wrike in 2014

to this:

Wrike in 2021

And, our tech stack and Development team have evolved just as rapidly as our user interface.

In layman’s terms, Wrike is a full-fledged work management product with all of the must-have features necessary for a product in this market.

Gantt charts, calendars, and tables are just a fraction of Wrike’s capabilities

Wrike is a comprehensive work management platform that dictates the complexity of the UI and imposes additional responsibility on the Engineering team in terms of performance requirements, development speed, and cost of application support.

2. A brief history of Wrike’s technology stack

Wrike was established in 2006, but we won’t go back that far. The history of Wrike’s modern-era frontend development can be roughly divided into several stages over the last six years.

JS and EXT

By 2013–2014, we had already written a significant amount of code in JS, which had no alternatives at the time. We used Ext.js v3 as our main framework. Despite being archaic, you’ll be surprised to learn it’s still alive and well. It had a series of breakthrough features, which, over the years, transformed it into what we’re used to now. For example, data stores can be, to a certain degree, considered a precursor to stores in React.

However, it was already clear in 2014 that JavaScript didn’t meet our requirements. With a growing team and a growing codebase, we needed a language that could offer:

  • Strong typing.
  • Great out-of-the-box features.
  • Efficient work with large amounts of code (build, minification, etc.).

Why Dart?

2014–2015 were difficult years in terms of making engineering decisions. We faced a dilemma: should we use TypeScript, which had just got its stable version at that time, or commit to Dart, which was less widespread but more of a “mature” language.

The main pros for Dart at the time were:

  • Stronger typing: As time has shown, Dart and TypeScript have moved towards a stronger typed system. While Dart completely switched to the sound type system, TypeScript still had some difficulties with it.
  • Out-of-the-box features: Third-party libraries can be useful but sometimes harmful. One of the problems of the modern internet is the abundance of libraries to speed up development. However, the issue is that you still need to choose, maintain, and update those libraries from time to time. As we all know, Node_modules jokes have already made history. This was an issue that TypeScript didn’t solve. Meanwhile, Dart had a fairly rich built-in library with core libraries updated and maintained by Google.
  • Aggressive tree-shaking: Wrike has a huge set of features, which ultimately makes for a ton of code. Our language needed to help us avoid uploading large amounts of code to the client. Check out these articles from Seth Ladd, and GitHub.

These pros and some other unique features convinced us to opt for Dart. Looking back at the six-year history of Dart in Wrike, we know we made the right choice at the time.

Of course, we’ve come a long way from Dart 1.x, with its dynamic typing and Polymer integration, to AngularDart and Dart 2.x. Dart has helped us grow the product year after year from an engineering and business perspective, pushing the company and the product to become the market leader in collaborative work management platforms (Gartner and Forrester ratings).

Current state

We’ve already written 2.5 million lines of code on Dart, and the codebase consists of more than 400 repositories. We’ve created a large number of solutions for Dart code building and validation (e,g, dart-code-metrics). Outside of Google, Wrike is, without exaggeration, one of the largest Dart consumers in the world of web application development. Flutter’s appearance contributed to the explosive growth of Dart’s popularity, but mostly in the world of mobile development at that point. Read to the end of the article to find out what will change in Flutter!

However, the reality is that the language by itself can’t provide all the necessary tools to build a major web application. The ecosystem is just as important, if not more. Build systems, syntax highlighting, internationalization, and visual frameworks are all vital to modern web development.

Dart ecosystem

We won’t go through all of the documentation here, but we’ll explore the most important part of modern web development: frameworks. Despite the fact that, in theory, Dart allows you to work with all web frameworks through JS interop, there still aren’t many frameworks to choose from:

  • OverReact: a wrapper for React from Workiva.
  • Flutter for Web: a popular cross-platform framework written in Dart. A stable version with web support has recently been released.
  • AngularDart: the de facto standard for web-app development via Dart.

There are other solutions but they’re either inconvenient or difficult to implement. Therefore, by choosing Dart for web development, you have to take one of the three frameworks listed above or write something on your own.

3. Reasons for abandoning AngularDart

We gave a brief overview of the current state of the Dart language ecosystem above, mainly covering the frontend. The world of frontend development is constantly moving forward — sometimes even faster than we’d like. So we’ll now touch on one of the key problems, which (at the time of writing) hasn’t yet been resolved. The world of frontend development is constantly moving, sometimes faster than we’d like. And as much as we’d like to, it’s impossible to choose a technical solution that will withstand the test of time. Web browsers are also evolving, adding new features and expanding APIs. And even web frameworks, which are by definition created to abstract from the web browser’s API, are forcing us to react and evolve, too.

Even the chaotic world of frontend development has its trends. Previously, it was progressive rendering (e.g., React Fiber and Angular Ivy). Now there’s a tendency to reject global state managers (e.g., Effector). There are a lot of things that must be supported in a modern web framework like GraphQL or Server Side Rendering, for example.

For an evolving SaaS product, it’s vital that the technical stack evolves just as quickly. This technical infrastructure has two base components:

  • The code your engineers write.
  • The code your engineers don’t write.

The modern development process (especially frontend) is rich with third-party libraries and tools. Now you can deliver a product to the market without writing a single line of code (i.e., the “no-code approach”). However, the code you don’t write is time saved, but also a risk.

Developing a large product usually involves a tricky balancing act between writing your own solutions, reusing existing ones, and interacting with developers of third-party frameworks. As one of the most extensive and pervasive parts of development, the language and framework you use can become your product’s most vulnerable aspect. Previously, products were distributed on disks and the concept of “continuous delivery” didn’t exist. Therefore, changing the language or framework could be very expensive. Now, especially with the emergence of the micro frontends concept, this isn’t a tragedy, but rather a healthy mechanism of evolutionary development.

With all of the above, we’re facing a difficult choice. We have to revise our current tech stack, because despite the fact that Dart and its ecosystem are moving forward (partially due to Flutter’s explosive growth in popularity) and Dart is improving (e.g., with null safety), one ingredient was still missing for us* — a web framework. Yes, the language itself already has primitives that allow you to work with the document object model (DOM) directly, but such development may be suitable for individual developers, rather than for large teams.

*We’d like to highlight the words “for us” here. Generalizations about the choice of tech stack can be dangerous. Every company has its own requirements, scale, business features, etc.

By “missing a web framework” we mean that we need four qualities from the tech product:

  • Feature richness (it works with all or most of the possibilities of the modern web)
  • Performance
  • Community support
  • Development and implementation of new features

Here’s what we’ll see if we take a closer look at the existing frameworks for Dart:

AngularDart

AngularDart is the de facto standard for web applications. It meets almost all of the requirements, but the Google team shifted the priority of its development towards Flutter. Read the official post from the Dart team. You can also read the relevant issue on GitHub. Yes, AngularDart still lives and is usable, but it lacks a key element: “Development and implementation of new features.”

OverReact

OverReact is a ported version of React for Dart. Unfortunately, there isn’t much support from the community, and the project itself is developed mainly by Workiva.

Flutter for web

This is the framework that Google engineers rely on and it’s moving full steam ahead. However, frameworks that suit small companies or are fit for porting a mobile app to the web aren’t yet ready for our tasks.

We’ve identified several issues related to Flutter Web and our requirements at Wrike. The main one is that it isn’t yet possible to embed a Flutter application into the current web application. Unfortunately, Flutter can’t be wrapped in a web component yet. This greatly interferes with the concept of micro frontends, the point of ​​which is to divide all the functionality into independent applications. These applications are deployed and developed by different teams and are loosely connected with each other. There’s a related bug if you want to know more. The solution would be to wrap micro frontends in an iframe, but this comes with a number of technical difficulties.

In addition, Flutter doesn’t yet have a number of features that are important for the modern web (e.g., SSR or SEO).

Another important aspect is related to the speed of the application; it’s not yet entirely clear how Flutter will be able to cope with a table view, for example. We’ll research this once it’s possible to embed a Flutter application inside another one.

Note: Flutter is one of the fastest growing frameworks in the world. It’s quite possible that by the time this article is published, its status will have completely changed. So follow the updates!

Despite our love for Dart and the years that we’ve spent together, we’ve decided to add a new ingredient to our technical stack. It’s important to note that we’re not saying goodbye; Dart will continue to be a big part of our work. But we’ll be considering other tech stacks for our new projects. Which ones, you may ask?

4. Possible migration options

Language

The main criteria that we used in choosing a language are the same from five years ago.

  • Strong typing, which helps large teams work more efficiently on a single codebase.
  • Community development and support.
  • Availability of ready-made solutions in libraries, or patterns, best practices, and approaches. We don’t want to reinvent the wheel.
  • Capable of building systems that can handle large volumes. As practice has shown, not everything that works well for a group of three to five developers scales well to a group of over 100.
  • Understandable syntax, making technical onboarding for new developers as quick as possible.

If you analyze the language market, it turns out that there aren’t a broad range of choices. Dart, TypeScript, and JavaScript with various linters are the main players. There are “non-mainstream” choices like Closure, Reason, or even Kotlin, but almost all of them don’t meet our requirements. This means that besides Dart, TypeScript was our only choice for a development language.

Choosing our framework

The main criteria that we set for the framework are similar to those that we used to choose the language.

  • Community support.
  • Minimal changes to the current infrastructure and approaches so that the cost of the transition doesn’t exceed its benefits.
  • Performance in a large application, from rendering to the actual development speed.

Let’s take a closer look at the criteria we used to choose a framework with examples from Angular and React, our main candidates.

Code organization and build

Code organization refers to the code being divided into repositories and packages.

Over the years, we’ve written a fine-tuned build system, and the application itself is often too big for standard scenarios, so we needed the framework to provide maximum flexibility and performance. We organize the Dart code as a multi-repository, which now contains over 400 libraries. This is the approach all of our build tools are set up for, so the transition to mono-repo can be quite expensive.

Note: With Dart, we use the pub package manager and publish the package source code. This allows us to use a multi-repository to change several packages at once. Just override dependency in pubspec.yaml to the git branch to get access to the sources.

One of the main advantages of React is that it doesn’t need to know anything about our development flow. The framework can be configured more or less to our preference.

Angular, in turn, is more like an enterprise system. It provides a lot of out-of-the-box features (e.g., angular cli), but it’s hard to configure. You either have to take Angular flow or not use this framework at all.

React allows us to keep a multi-repository and have DevExp and CI/CDs similar to the current ones. As for Angular in its current state, only a mono repository was a realistic option.

Data flow

Data flow is a model of data organization in an application and the way it flows through a system. This defines the abstractions that the developer will encounter every day.

In both React and Angular, the key abstraction is a component that has its own props or inputs and its own state. Re-rendering of the component tree is executed from top to bottom. The main difference is that re-rendering in React is executed from the node with the new state down, and in Angular from root to components at which point (explicitly or not) markForCheck is called, and then down.

Due to the fact that the change detection mechanism in Angular stays and is executed starting from the root component, changes in individual components don’t re-render as fast as in React. This closes a series of features, like controlled <input>, which React provides.

There are no, and never have been, Zones in React — a global context that affects how the entire application works. This results in less time required to debug and profile the application, since problems are “local” to a specific subtree of components. However, Angular for TS allows you to opt out of using zone.js, but this feature is still considered experimental.

Component composition

Component composition refers to the ability to transfer one component to another. Such components are often referred to as “templated” components.

React significantly outperforms Angular in its component composition capabilities. There are no concepts like static template or dynamic component loading in React. Everything is “dynamic” by default; it’s possible to transfer some components to others and to process the rendered template with code. This allows us to create more flexible components instead of sewing all the visual elements and logic together in one component. We can also divide components into UI-only or logic, writing and testing them in isolation.

Summary

In summary, Angular provides a lot of out-of-the-box features, but at the same time embeds them into an existing ecosystem that would be equivalent to rewriting it from scratch, which seems impractical. React is flexible enough and allows us to reuse elements of our existing infrastructure.

Therefore, we’ve decided to choose a bundle of Typescript and React as the main toolset for developing the client side of our application.

5. Migration plan

Language agnosticism

A lot of important features will remain written in Dart for a long time, so Dart won’t turn into a legacy language for us overnight. It makes no sense to rewrite what has been developed over the years and is working fine.

However, for the development to be effective and consistent in both Dart and TS stacks, we must move in two directions:

  1. Engaging and increasing the expertise of the company’s developers: If engineers start switching to TS at the beginning of the first product development, the quality and timing of the implemented feature will suffer. To prevent this from happening, the expertise boost must be carried out before the development of a large feature starts.
  2. Development and support of the same type of toolkit for both stacks: Switching between development stacks within the same application leads to developers wasting time on adaptation. It’s necessary to ensure both stacks use tools as similar as possible (libraries, paradigms, architectural approach, etc.).

This is a more detailed plan for implementing a TS workflow:

  1. Provide similar dev experience on both stacks: Linting rules, architectural approach for Dart/Angular and TS/React, unit testing, and localization.
  2. Provide a single deployment process for an application on different stacks: The process of application delivery to production is uniform and automated regardless of the development stack.
  3. Provide a consistent set of development libraries: Tasks that were closed on the Dart stack using libraries are also closed on the TS stack with analogs of the same libraries. For example, work with user sessions, routing, different types of transport, contracts generation, etc. At the same time, the development of such libraries guarantees a feature parity between Dart and TS implementations.
  4. Ensure interface consistency: There can be two applications on the same page on different stacks. The interface of both applications should consist of the same components. For this, the support and development of visual components in compliance with feature parity on both stacks is guaranteed.
  5. Conduct internal training for developers: Conduct workshops and engage in new projects on TS that don’t have a high priority, in order to build up expertise in a calm environment.

In addition, we’re moving towards micro frontends. However, this is a complex question that you’ll read about in our future articles.

FAQs

Q: Will you continue to write Dart code?
A:
We’ll continue to support and develop existing Dart features. It’s also quite possible that some new features will be in Dart, such as features with a large number of existing, ready-made modules. Also, the Flutter team moves forward at full speed, so who knows what will happen in the future?

Q: Will you require new developers to know Dart?
A:
No. Our previous approach has been training and onboarding new engineers since Dart developers are quite rare on the market. With the transition to TypeScript, nothing will change as we still have code written in Dart, and sooner or later developers will have to face it. Since we’re still at the very beginning of our journey, our engineers will code in Dart and TypeScript.

Q: Why didn’t you take the X or Y framework (Vue, Svelte, etc.)?
A:
In the wake of micro frontends, choosing a framework isn’t something that’s set in stone. However, we wanted to strive for the learning curve to be as flat as possible. Many of our engineers already knew and had worked with either React or Angular, which is why our choice was mainly between these two frameworks. But with a micro frontend architecture, nothing prevents us from considering Vue, Svelte, and other frameworks in the future.

Q: Will Wrike continue hosting the DartUP conference?
A:
Even though the DartUP conference was founded with the assistance of Wrike, today the event has spread far beyond our company. A large, active community has formed in Russia, and DartUP itself entered the international arena in 2020, organizing a parallel stream for English-speaking participants. We hope that the conference will continue to live and develop thanks to the community and companies that aren’t so indifferent to Dart and Flutter (including us), and attract new “Dartizans” and “Flutters” from around the world.

6. Conclusion

Wrike is gradually changing its frontend stack towards TypeScript and React. This doesn’t mean that Dart is a bad language! We’re grateful to the Dart and AngularDart team for everything they’ve done and are doing so far for our platform. It’s been a long journey and Dart is still an important part of our product. We hope to see the language develop and reach new heights.

Here you can read a small note from Tim Sneath, Director of Product Management for Flutter & Dart:

“Wrike has been a fantastic partner for Dart over many years. They were one of the first to see the potential of the language for building mission-critical web applications, one of the most active and engaged community members, and continue to this day to make many contributions to Dart.

Here on the Dart team, we’ve been shifting our external resources towards Flutter’s web support, which has just reached its first stable milestone. As Flutter is our next-generation UI framework, we’re prioritizing AngularDart resources on serving the needs of internal massive-scale products like Google Ads and Google Play Console. We’ve been working with Wrike over the last few years to help them plan for the future, and we fully endorse their plan to add TypeScript for their large enterprise forms-based application. It’s a great choice for their needs, and we are excited to see how they evolve!”

Are you interested in more in-depth technical details? Would you like to follow our journey into the land of TypeScript? Don’t hesitate to subscribe to our Medium blog to follow our updates.

--

--