Design goals for NerdDinner

In Chapter 3, Developing Dockerized .NET Framework and .NET Core Applications, I extracted the NerdDinner home page into a separate component, which enabled the rapid delivery of UI changes. Now I'm going to make some more fundamental changes, breaking down the legacy application and modernizing the architecture.

I'll start by looking at a performance issue in the web application. The data layer in NerdDinner uses Entity Framework (EF), and all database access is synchronous. A lot of traffic to the site will create a lot of open connections to SQL Server and run a lot of queries. Performance will deteriorate as the load increases, to the point where queries time out or the connection pool is starved and the site will show errors to the users.

One way to improve this would be to make all the data-access methods async, but that's an invasive change—all the controller actions would need to be made async too, and there is no automated test suite to verify such a wholesale set of changes. Alternatively, I could add a cache for data retrieval so that GET requests would hit the cache and not the database. That's also a complex change, and I would need to cache data for long enough to make a cache hit likely while keeping the cache in sync when the data changed. Again, the lack of tests means complex changes such as this are hard to verify, so this is also a risky approach.

It would be hard to estimate the benefit if I did implement these complex changes. If all the data access moves to asynchronous methods, will that make the website run faster and enable it to handle more traffic? If I can integrate a cache that is efficient enough to take reads away from the database, will that improve the overall performance? These benefits are difficult to quantify until you've actually made the change, when you might find that the improvement doesn't justify the investment.

With a container-first approach, you can look at the design differently. If you identify one feature that makes expensive database calls but doesn't need to run synchronously, you can move the database code to a separate component. Then you use asynchronous messaging between the components, publishing an event from the main web app to a message queue and acting on the event message in the new component. With Docker, each of these components will run in one or more containers:

If I focus on just one feature, then I can implement the change quickly. This design has none of the drawbacks of the other approaches, and it has a number of benefits:

  • It's a targeted change, and only one controller action changes in the main application
  • The new message handler component is small and highly cohesive, so it will be easy to test
  • The web layer and the data layer are decoupled, so they can be scaled independently
  • I'm moving work away from the web application, so we can be sure of a performance improvement

There are other advantages too. The new component is completely independent of the original application; it just needs to listen for an event message and act on it. You can use .NET, .NET Core, or any other technology stack for the message handler; you don't need to be constrained to a single stack. You also have events that are being published from the app, so you have the option to add other features later by adding new handlers that listen for these events.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.12.136.63