SPA’s are apps too. And as such when creating a SPA you will find yourself writing code to get data, push data, handle validation, change tracking, storing data locally, presenting data, and so much more. All of these roles could be written in a scattered manner across the app, but that causes redundancy, low code re-use and a readability and maintenance headache. And for you pattern folks (like me) it also violates DRY and SRP.
So what do we do? Make more, smaller code files that each handle one specific job.
You can get the details on how I use this approach in my upcoming Pluralsight course titled “Building Single Page Apps (SPA) with HTML5, ASP.NET Web API, Knockout and jQuery”. It’s T-minus 2 weeks before it’s due to be completed … so it’s getting close!
You can catch up on the previous posts in this series here:
More on the Code Camper SPA
Part 2 - Client Technologies
Part 3 - Server Technologies (the Data Layer)
Part 4 - Serving JSON with ASP.NET Web API
Part 5 - HTML 5 and ASP.NET Web Optimization
Part 7 - MVVM and KnockoutJS
Part 8 - Data Services on the Client
Part 10 - Saving, Change Tracking, and Commanding
Part 11 - Responsive Design and Mobility
Spaghetti to Ravioli
I get ideas that pop in my head quickly and then they often leave just as quickly. So it’s important for me to get them written in code before I lose that thought. Because of this, I write code in iterations. I write it, test it, refactor it, test it, refactor it, and so on.
Pass 1: Toss the Spaghetti Against the Wall
The first pass of my code is rarely the best or most elegant, but it gets the job done. If I stopped here, I’d leave a code smell behind and have a lot of intermingled code that nobody would enjoy maintaining and would be impossible to test or expand upon.
Pass 2: Tasting the Spaghetti
Then I refine the code for all use cases. This is where I make sure it handles the roles that the code needs to handle. It’s better code, but still has a lot of duplication and ugliness.
Pass 3: Introducing Ravioli
Finally, I refactor it to be more maintainable. This is where I optimize the code, shorten it, create extension methods, service classes, and apply DRY and SRP.
$('#messagebox').text('Welcome to Code Camp, John');
We could wrap this in a function, and that would help. But then what if other files want to use it? Then we need to make sure it is loaded in time. We could put it in its own module, and then it would be more reusable. Then we could make it use a custom message, but maybe a better solution is to tell it how to get the message. For that we could tell it to go talk to a module to get the message.
Again, this is an overly simplified example … but it is easily applicable to larger code issues.
- The ID of the module
- The dependencies
- The factory for the module
- This ‘alerter’ module can be loaded as needed (using RequireJS)
- It is self-sufficient since it defines the dependencies up top (jQuery and dataservice). RequireJS will go out and find those modules and load them first, before the alerter is cranked up. How nice!
- The alerter doesn’t know how to go get the message, it defers that to the dataservice. So alert just “alerts” the user … which is its job.
- Using this code all over our app is as simple as saying
- Defines modules
- Resolve module dependencies
- Load scripts in the proper order (and asynchronously)
This code has a few advantages our first spaghetti example did not:
In my course I use RequireJS to handle the dependency resolution for my modules. RequireJS helps:
In my course I go deeper on this concept and show how modularity can make it much easier to manage a SPA as it grows. I include several examples and as a bonus, here is a quick introductory sample using modularity and RequireJS on github that I wrote to help explain it. I call it kis-requirejs-demo for “Keep It Simple RequireJS Demo”