I recently started a side project to learn how to better compose a “web api” project. I am using ASP.NET and ASP.NET Web API, but there were a lot of things I really wanted to drill down on.
First of all, I have seen many a project at various places I’ve worked begin with the ASP.NET templates. Obviously, this is nothing new. Many a team has gotten the chance to work on a brand spankin’ new ASP.NET project and hits File > New Project in Visual Studio and starts coding away in what the project template spits out.
But I really believe the project templates are meant more for exploration of what is possible. You look at them to see how the framework operates and some ideas of what you can do with it. When you start wanting to go down the road of laying out the project so it’s actually easier to code, deploy, and maintain… well that’s an entirely different story. And since I may find myself in the situation of being asked to hit File > New Project someday, I’d like to have practiced with starting on a truly EMPTY project and composing the building blocks that will make it deliver real business value quickly and EASILY.
So I wanted to come up with a non-trivial project that I might actually have a use for. And I came up with the following.
I’d like to have a small website that allows me to enter dues payments for residents who live in a homeowner’s association. Each quarter, the residents have dues to pay, and it’s nice to be able to record some information about the dues payments. I’ve found it’s nice to keep track of when the payment was received, deposited in the HOA account, what the check number was, and how much they paid (because it’s not always the balance due!). I’d like to be able to build in the logic to automatically assess fines for being late and eventually generate the billing statements (perhaps either for display in the site or by email).
(It’s important to note that the code being built is truly for no particular purpose and that I have no plans to ACTUALLY use this with any real homeowners association. The data will always be completely made up.)
What do I want to explore?
There is a laundry list of things I want to put into practice. Many of them are the things that many teams wish their project could do, but feel like they don’t have the time to do it:
- Continuous Deployment – I admit this is a serious BABY STEP compared to industrial strength continuous deployment, but I wanted to deploy “on commit” from GitHub to a cloud platform and have the process verify the code’s worthiness by running tests, etc.
- Separate the Web API’s “host” from the Web API implementation. I’ve long thought that it’s not THAT MUCH work to separate your ASP.NET Web API implementation (e.g. your Controllers, Models, and maybe Routes) from the assembly that HOSTS the API. It’s not about violating YAGNI (who said I need Console version? where is that requirement!). It’s that I truly believe there is little effort to it and MUCH TO GAIN in separating responsibilities.
- Don’t marry the business logic to the Web API. Again, this isn’t about violating YAGNI and saying that tomorrow we’re taking the business logic to an Android app running on Xamarin. It’s that I truly believed there was no additional effort involved and would actually result in easier-to-compose software.
- Find awesome ways to test these components that run fast and run every build, and will be a quality gate to deploying the app into the cloud.
- Using async/await in ASP.NET on I/O bound operations without complicating the code.
- Don’t marry the data persistence to the Web API implementation, either.
- This list isn’t complete.
I want to point out that none of this list is to be considered “golden rules”. In fact, the whole idea is to find out where to draw lines and be pragmatic. I have walked into many projects that proclaimed “This time, we’re going to build it right!” and set out to abstract everything away. A result I have seen, sometimes, is that it takes TONS of code to do what is normally quite simple (in other words, the abstractions are there, but nothing is by convention, so everything requires complete setup and teardown of the same ceremony).
What about “You ain’t gonna need it”?
So on the one hand, you see a sample MVC tutorial do all of the data persistence right in the controller and you know in your heart that seems like more than you want the controller to handle, but when the team sets out to separate the concerns there is SO MUCH abstraction that you can’t get anything done or you lose the power of your ORM because you abstracted it away.
Sometimes I think we lose sight of where to draw the lines here. I know as developers we are TERRIFIED of building a web site “by the book” and with little more abstraction than the common tutorial. We figure that sure enough, someday there will be a need to reuse business logic or the persistence or something and we’ll cry because it’s all intertwined in the code. And we either over-engineer it and turn out to be dead wrong (nope, this is not ever going to need to be reused) or just do it fast and “by the book” only to be dead wrong about that.
Where am I today?
So as I approach 3-14-15 9:26:53pm (I’m looking at the clock now and it’s 9:15pm EDT), this is the state of the project:
- There is one GitHub repository where I commit code (and one Visual Studio Solution). Each commit (on the branch Azure Web Sites is listening to)deploys to two Azure Web Sites. One builds the web site and the other builds the Web API. The deployments get updated (if the build works). This means I’ve got two Azure Web Sites hooked up to ONE GitHub repo but each site knows what code is meant for it.
- The Web API uses CORS and only allows calls from this “production” Azure web site, but on my local dev machine everything still works with the SAME code.
- The Unit Tests explored two techniques for testing Web APIs. One is to leverage the testability of ASP.NET Web API Controllers. The other technique leverages hosting Web API in a temporary in-memory server and just making http requests to it. While both methods work, I am beginning to like the second technique better.
- The core data models are in a simple class library whose references are just System and System.Core (I think this may grow just a bit).
- The whole thing currently uses an in-memory data store which may remain in place for unit testing. The intent here is to prove out the interfaces and then see if it can be backed by Entity Framework or something else. Who knows? After all, Uncle Bob says “A good architecture allows you to defer critical decisions” (completely out of context, but the blog post has the larger context).
- The web site is purely static files… and happens to use some Angular and jQuery. I was letting the web site be an opportunity for my friend to learn to build a front end that talks to a web based api. He’s been writing about his experience (in the last several months) of learning to code at his blog.
A Work In Progress
There is plenty of work to do, but I’ve worked out a few things I think are worth sharing. I’ll specifically be writing about how I set up the continuous deployment and CORS support that is still developer friendly in upcoming posts.
Wait, where’s the code?
Oh yeah. You can find it in the GitHub Payments Project, of course.