April 18, 2018
mikesefanov
Achieving Major Stability and Performance Improvements in Yahoo Mail with a Novel Redux Architecture
<p><a href="https://yahoodevelopers.tumblr.com/post/173059437072/achieving-major-stability-and-performance" class="tumblr_blog">yahoodevelopers</a>:</p><blockquote>
<p>By Mohit Goenka, Gnanavel Shanmugam, and Lance Welsh</p>
<p>At Yahoo Mail, we’re constantly striving to upgrade our product experience. We do this not only by adding <a href="https://yahoomail.tumblr.com/post/173062841545/the-best-of-the-new-yahoo-mail-made-better-by-you">new features based on our members’ </a><a href="https://yahoomail.tumblr.com/post/173062841545/the-best-of-the-new-yahoo-mail-made-better-by-you">feedback</a>, but also by providing the best technical solutions to power the most engaging experiences. As such, we’ve recently introduced a number of novel and unique revisions to the way in which we use Redux that have resulted in significant stability and performance improvements. Developers may find our methods useful in achieving similar results in their apps.<br/></p>
<p><b>Improvements to product metrics</b></p>
<p>Last year Yahoo Mail implemented a <a href="https://yahooeng.tumblr.com/post/162320493306/yahoo-mails-new-tech-stack-built-for-performance">brand new architecture</a> using Redux. Since then, we have transformed the overall architecture to reduce latencies in various operations, reduce JavaScript exceptions, and better synchronized states. As a result, the product is much faster and more stable.</p>
<p>Stability improvements:</p>
<ul><li>when checking for new emails – 20%</li>
<li>when reading emails – 30%</li>
<li>when sending emails – 20%</li>
</ul><p>Performance improvements:</p>
<ul><li>10% improvement in page load performance</li>
<li>40% improvement in frame rendering time</li>
</ul><p>We have also reduced API calls by approximately 20%.</p>
<p><b>How we use Redux in Yahoo Mail</b></p>
<p>Redux architecture is reliant on one large store that represents the application state. In a Redux cycle, action creators dispatch actions to change the state of the store. React Components then respond to those state changes. We’ve made some modifications on top of this architecture that are atypical in the React-Redux community.</p>
<p>For instance, when fetching data over the network, the traditional methodology is to use Thunk middleware. Yahoo Mail fetches data over the network from our API. Thunks would create an unnecessary and undesirable dependency between the action creators and our API. If and when the API changes, the action creators must then also change. To keep these concerns separate we dispatch the action payload from the action creator to store them in the Redux state for later processing by “<b>action syncers</b>”. Action syncers use the payload information from the store to make requests to the API and process responses. In other words, the action syncers form an API layer by interacting with the store. An additional benefit to keeping the concerns separate is that the API layer can change as the backend changes, thereby preventing such changes from bubbling back up into the action creators and components. This also allowed us to optimize the API calls by batching, deduping, and processing the requests only when the network is available. We applied similar strategies for handling other side effects like route handling and instrumentation. Overall, action syncers helped us to reduce our API calls by ~20% and bring down API errors by 20-30%.</p>
<p>Another change to the normal Redux architecture was made to avoid unnecessary props. The React-Redux community has learned to avoid passing unnecessary props from high-level components through multiple layers down to lower-level components (prop drilling) for rendering. We have introduced <b>action enhancers</b> middleware to avoid passing additional unnecessary props that are purely used when dispatching actions. Action enhancers add data to the action payload so that data does not have to come from the component when dispatching the action. This avoids the component from having to receive that data through props and has improved frame rendering by ~40%. The use of action enhancers also avoids writing utility functions to add commonly-used data to each action from action creators.</p>
<p><a href="https://s.yimg.com/cv/api/default/20180417/YahooMailReduxArchitecture.png"></a></p>
<a href="https://s.yimg.com/cv/api/default/20180417/YahooMailReduxArchitecture.png"><figure class="tmblr-full" data-orig-height="1430" data-orig-width="1999" data-orig-src="https://s.yimg.com/cv/api/default/20180417/YahooMailReduxArchitecture.png"><img src="https://66.media.tumblr.com/e61fce6c14aeb1d3db3efe10d043d58a/tumblr_inline_p82janFFoG1rgj0aw_540.png" alt="image" data-orig-height="1430" data-orig-width="1999" data-orig-src="https://s.yimg.com/cv/api/default/20180417/YahooMailReduxArchitecture.png"/></figure></a><p>In our new architecture, the store reducers accept the dispatched action via action enhancers to update the state. The store then updates the UI, completing the action cycle. Action syncers then initiate the call to the backend APIs to synchronize local changes.</p>
<p><b>Conclusion</b></p>
<p>Our novel use of Redux in Yahoo Mail has led to significant user-facing benefits through a more performant application. It has also reduced development cycles for new features due to its simplified architecture. We’re excited to share our work with the community and would love to hear from anyone interested in learning more.</p>
</blockquote>