When the data to be listed in a page becomes too long everybody agrees that it’s
necessary to split the long flow into several small pieces, well that’s known in
IT world as paging data, as you should know from day-to-day work in web
applications. Every web technology gives us in some way the opportunity to do
this without too much complexity. ASP.NET MVC is not an exception, after a quick
Google-research I’ve found, of course since this problem is so common, tons of
implementations, but the most relevant (at least in my modest opinion) was the
one we can find at
http://en.webdiyer.com/.
There is another important implementation at
https://github.com/martijnboland/MvcPaging that has also a NuGet package for
ease the distribution. Almost all the implementations I found were inspired by
ScottGu's PagedList
idea.
I inspected many others but the general idea was in a way or another the same
mentioned before over and over again. Finally I decided grab the first one and
start using it as it comes out of the box. It was really easy to use: just make
sure of your viewmodel has a IPagedList object, then specify the controller,
action, pagination options, ajax options and html custom attributes.
Long story short, everything went good until I found a scenario where I needed a
parameter combination that the author did not foresee. Wow! I really appreciate
the amount of overloads made by the author, but in some way it was not enough
for my scenario, so that’s Open Source magic. I downloaded the project and
inspected it in a more detailed way. It really allowed the most common ways to
make the pager but I needed at same time to specify controller, action, route
data and ajax options for accomplish my task, after all I think this is not so
uncommon scenario, I had a filter for my list and of course when I changed the
current page the filter information must keep between round trips to the server.
The solution was actually simple, just make another overload in the Helper class
and ready, but I wanted to dig deeper in the project structure and
implementation and I discovered something I didn’t like too much (and it’s
something I’ve seen in almost every projects in my research). The logic and view
were strongly coupled. I am not a software philosopher but I like the good
practices and the life had demonstrated to me that they are important. When I
say strongly coupled I mean the same class is responsible of these two different
tasks and concerns.
The relation between the classes is like this:
+-------------+ Render Pager +--------------+
| PagerHelper |------------------->| PagerBuilder |
+-------------+
+--------------+
The idea was to split that big class into two classes PagerModel and PagerView
(obvious naming?) where the class PagerModel is responsible for all the logic
involved such as the tedious calculations about page numbers, amount of pages,
etc. model integrity validations using as transport a class PagerItem, this
class holds data about each item to be shown in the pager but NOT how is to be
shown, it’s only responsible for return a valid list of PagerItem. This
separation of concerns is not just for to be compliant with the “holy bible” of
design good practices, I’ve done this because I forecasted that in a short
future it was going to be useful.
My refactoring looks like this:
+-------------+ Render Pager +-----------+ Get Model +------------+
| PagerHelper |--------------->| PagerView |----------->| PagerModel |
+-------------+ +-----------+
+------------+
That future moment is arrived a few days ago, when I had to implement the same
pager but this time with a different markup, actually just HTML and links and no
ajax compatibility despite the fact I’m using unobtrusive from the default
template. With this new distribution it was easy to me to create a new type of
view, and why not, a little change of name, PagerView to AjaxPagerView and the
new view named HtmlPagerView. It looks this way:
Render
+---------------+ Get Model
+------------------>| AjaxPagerView +-----------------+
|
+---------------+
V
+------+------+
+------------+
| PagerHelper |
| PagerModel |
+------+------+
+------------+
|
+---------------+
^
+------------------>| HtmlPagerView +-----------------+
Render
+---------------+ Get Model
This is my vision of making a reusable design; in this case, instead of making a
bunch of if-else or switch-case statements I apply a mixture between the
Strategy and Decorator Design Pattern where every kind of view is a different
“strategy” of rendering and “decorates” the model, which allows me in a future
to implement many other types of view without affecting the core functionality
and the actual logic: the model. The input options must be processed by the
model class and make all the proper decisions returning a data structure which
in most cases is named view model, ready for the view engine to read the
necessary data from it. The view engine could be dependent in some way of the
model element, but the model can NEVER be dependent of the view engine.
I hope this little refactor-reflection had made you think a bit more about real
code reuse and the importance of using good practices and design patterns not
just for to follow magic guidelines. I’d like to remark the consequences of
developing software without keeping on eyes these techniques.
By the way, tell me about my ASCII-UML? Not bad, is it?