User Interface

This post will conclude our story of a Vertical Slice of an application build to help First Pop Coffee Company be more successful with its Roast Planning. We are far from finished, as I know that the pain in actually implementing these architectural principles is stronger than I can describe with a single Bounded Context.

So how do we tie everything together for Nick to check out the Team’s prototype? We have a few dependencies that we need to wire up. We have those interfaces that we came up with in our Domain Model, the Bus and registering Command/Event Handlers, and the Read Model Facade that we just talked about.

For the UI, we’ll use the Ninject IoC container to wire up our dependencies. The Team would like to look at alternatives in the future… even the idea of not using an IoC container. For now, however, they will use Ninject.MVC5 to tap into ASP.NET MVC 5’s Composition Root to allow constructor injection into our MVC Controllers. Here’s what our Roast Planning Controller looks like:

public class RoastPlanningController : Controller
{
    private readonly ICommandSender _bus;
    private readonly IRoastPlanningReadModel _readModel;

    public RoastPlanningController(ICommandSender bus, IRoastPlanningReadModel readModel)
    {
        _bus = bus;
        _readModel = readModel;
    }

    public ActionResult Index()
    {
        var viewModel = _readModel.RoastSchedules.ToList();
        return View(viewModel);
    }

    public ActionResult Create()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Create(string create)
    {
        _bus.Send(new CreateNewRoastScheduleCommand(Guid.NewGuid()));
        return this.RedirectToAction(nameof(Index));
    }
}

And here’s our Ninject Module that wires everything up via Ninject.MVC5:

public class RoastPlanningNinjectModule : NinjectModule
{
    public override void Load()
    {
        Bind<IEventStore>().To<EventStore>();
        Bind<IRepository<RoastSchedule>>().To<EventSourcedRepository<RoastSchedule>>();

        // Inject FakeDbSet<RoastScheduleView> to simulate persistence
        Bind<FakeDbSet<RoastScheduleViewModel>>().ToSelf().InSingletonScope();
        Bind<IRoastPlanningContext>().To<RoastPlanningContext>();
        Bind<IRoastPlanningReadModel>().To<FakeRoastPlanningReadModel>();

        Bind<IEventPublisher, ICommandSender>().To<FakeBus>()
            .InSingletonScope()
            .OnActivation(bus =>
                {
                    bus.RegisterHandler<CreateNewRoastScheduleCommand>(
                        new RoastScheduleCommandHandlers(Kernel.Get<IRepository<RoastSchedule>>()).Handle);
                    bus.RegisterHandler<ChooseRoastDaysForRoastScheduleCommand>(
                        new RoastScheduleCommandHandlers(Kernel.Get<IRepository<RoastSchedule>>()).Handle);
                    bus.RegisterHandler<RoastScheduleCreatedEvent>(
                        new RoastScheduleView(Kernel.Get<IRoastPlanningContext>()).Handle);
                });
    }
}

What’s going on under the hood here?

Here’s a demo gif:

A lot is being done just to accomplish this small task, however we’ve put the infrastructure in place to continue to model this Domain how it was discovered in the Design Level Event Storming:

Summary

This series has reached 25 mini-posts. This means I’d like to provide some closure so that we can step back and re-address some finer points about this style of software architecture.

We started with meeting Nick and First Pop Coffee for the first time as a Team of software developers that he wants to pay to help him develop software for his unique business idea: to offer roast-to-order coffee while allowing for him to allocate the amount of available roast batches through his online shop.

Nick and the Team went through a vigorous, yet effective process of Event Storming. They began with a Big Picture Event Storming session, which left them with an artifact that represented the overall idea that Nick has for using software to manage his coffee roasting business. They identified the major Subdomains in the business, and decided which ones were worth the application of Domain Driven Design.

They followed up the Big Picture Event Storming session up with a Design Level Event Storming Session. In this, they focused on the Roast Planning Bounded Context that they identified in the Big Picture session. They focused on Domain Driven Design terminology in this session, identifying Commands, Aggregates, Events, Read Models, etc in a way that Nick could understand how they fit in with his view of his domain.

The Team began working a prototype. They tried to implement a design using Domain Driven Design that applied patterns such as CQRS and Event Sourcing. They designed a couple Aggregates that were built with the ability to persist their state using an Event Store. They designed Command Handlers, Event Handlers, and a Bus that carried Messages throughout the Application.

Finally, they implemented a quick Read Model to be used by the User Interface for the Roast Planning Bounded Context. They built an in-memory version of what will eventually be a full-fledged persistence store that is designed to be optimized for reads. They IoC’d it all together quickly so to demonstrate the first Vertical Slice of the application for First Pop Coffee.

Our goal moving forward is to pick out smaller concepts and use First Pop Coffee as a foundation for exploring them. We’ll talk about aggregate design, process managers, and more production-worthy infrastructure projects that we can use for this type of project.

If you want to look at the full project on github, feel free to check it out here. It will change and it may not be organized perfectly, but if you want to build it, or even submit PRs I’m open!


previous…


I will be releasing most of this content only to subscribers. Make sure you sign up by clicking the big red button!


Related Posts:

Tweet
comments powered by Disqus