Line-Of-Business applications with ASP.NET.
In this article I would like to discuss challenges we facing developing
business applications with ASP.NET and what we have done to make life simpler. By
business
applications I mean loads of interrelated forms, grids, trees and so on. Let's
make thought experiment: Imagine we have to develop new CRM from scratch.
CRM should have web interface, it should show customers, register orders,
print reports and so on (just usual stuff). How are we going to implement this?
As we are going to use ASP.NET let's follow straightforward way and look where
it leads us; that's how our application initially looks:
Quickly we discover that the same functionality is required on several pages.
For example, grid with customers is useful at both Customers.aspx and CustomerSelectDialog.aspx.
Fortunately it's not a problem: There are user controls in asp.net so we refactor
.aspx pages to .ascx user controls which makes them reusable. We also notice that
using .aspx pages gives us no advantages comparing to .ascx user controls so we
refactor everything to user controls.

And if we see that there is still some code duplication, we create smaller controls
and combine them for bigger controls and so on... As it has been done, there is
no code duplication but application structure is getting more complex:

Usually having a bit complex application structure is ok as far as each component
is simple; I think of it just as of normalization. What is problem is that
these
user controls are absolutely not testable, though they contain code
that can be tested. Solution is obvious and well known - testable code should be extracted to special testable classes.
I would like to illustrate concept with sample:

public
partial
class
CustomerRegistrationForm
: System.Web.UI.Page
{
protected
void
OkButton_Click(object
sender,
EventArgs
e)
{
var
customer =
new
Customer
{ Name = Name.Text };
customer.Persist();
}
}
(please, do not think we've really developed CRM and
shipped something like this, it's just a sample).
Obviously, this form registers new Customers in system. Now let's refactor it into
make something testable. As MVC pattern is increasingly popular, I use the same
terminology:
public
class
CustomerController
{
public
void
CreateCustomer(string
customerName)
{
var
customer =
new
Customer
{ Name = customerName };
customer.Persist();
}
}
public
partial
class
CustomerRegistrationForm
: System.Web.UI.Page
{
CustomerController
controller =
new
CustomerController();
protected
void
OkButton_Click(object
sender,
EventArgs
e)
{
controller.CreateCustomer(Name.Text);
}
}
Wow! Application logic is now testable! We can do the same thing with our imaginary
CRM. Let's create Controller for each user control and that's what our application
structure looks like:

Just great, isn't it? Unfortunately, it is not. It does not take long to realize
that most breakable application logic is interaction between controllers and it
is still not testable. The problem is that presentation layer is still a decision maker.
Everybody knows that presentation layer should be thin and simple but how to achieve
that ? If you heard of "inversion of control" the solution lies on the surface:
revert arrows at the image above and let controllers rule the application.
I.e initially controllers were created and used by views; after refactoring
they should create and use each other, they also should know as little about
Views as possible. So we can create controller tree in test environment,
replace Views with mocks and have application running almost the same way as
it is does in production. Of course, Views Controller and View should be
loosely coupled and intermidiate interface should be introduced.

At the figure above, I renamed CustomerController to CustomerForm and CustomerForm
to CustomerView to emphase that controller is not just a helper for presentation
anymore. And let's use term "Component" for controller; that's where real fun
begins.
Imagine "Components" just work and we once again refactored CRM to make it Component
based. Now code is testable (except Views) and clean because application logic
is now separated from presentation. Next thing we notice is that all grids in application
look alike or at least should look alike. Why not to create one configurable Grid
component for them all ? In this case we can create grids without implementing View
every time, this would make our code not only nice but also compact. For example,
that's how Grid Component would be used:
var grid =
new Grid<Customer>();
grid.AddColumn(customer=>customer.Name); grid.AddColumn(customer=>customer.Country);
Of course, we like the result - code is small, testable, there is no Html or
JavaScript and all our grids look alike. Moreover, if we need new feature we can
implement it in one place and it will appear everywhere. Of course, we can't
help but do the same thing with all components. Eventually we have basic set of
components which should be just configured and new Form or Grid or Tree is
ready. This basic Components have nothing to do with CRM so we move them apart
into an independent module. That's what our CRM turned into:

It's it. Our application is testable, all code looks clean, just one step
left. If we have module for building business applications and all
infrastructure
is implemented why not to share it with other developers? We decided that
it is good idea; all previous discussion was just a fiction but results are
real. We indeed implemented Components and Views, organized them in modules and
shared through the web site. You are welcome : http://liveui.net
|