Coding tactics: .Net MVC

The following are some of the general guidelines I follow while coding to get a better code structure and easier test driven development. IMHO, these also make code easier to understand and debug.

  1. Do not use regions – these only hide information and are probably an indication your class is too big.
  2. Put the fields, properties and methods in alphabetical order and similarly the tests in the unit tests.
  3. Name the unit tests starting with the method name so the ones relating to same methods can be grouped together.
  4. A recommended format for naming tests is MethodName_Input_ExpectedResult. This differentiates method name, input and desired result, something other formats usually don’t. Also, all the tests for the same method are grouped together when searched for by using Resharper (Alt + \) or Visual Studio (the methods drop down on top). If the tests are put alphabetically, they will reside next to each other for the same method.
  5. Start writing unit tests with the all green (positive) condition first. This fleshes out all dependencies so the hard work is done. Now the unit test can be copied and things changed for other conditions – so work is completed quickest.
  6. Limit unit tests to assert one or two things, unless maybe if these are related to the same object.
  7. The unit tests should be guiding responsibilities of classes – Test Driven Design is a more appropriate expansion for TDD. Whenever testing a method takes too much setup and too many assertions, it’s doing too much and some if it needs to be done by another class, to be injected into the method.
  8. Do not hard code data in unit test expectations. If needed, variables should be used to check the right string/int etc is being returned. The System.Random class can be used to create random integers, doubles, or strings by using ToString() on the integer generated. The same can be extended to create random decimals if needed.
  9. Use Dependency Injection effectively – never create new instances of dependencies in methods/properties, inject them where possible.
  10. Any method which needs scrolling to read is probably too big to grok easily. An object should always tells others to do work, instead of asking for their properties and doing it.
  11. Smaller classes and methods, with less responsibilities, are usually easier to debug, especially if every class’ method validate input independently.
  12. Do not use abbreviations, name variables as per their class or utility. The class names should be per business terminology where possible, otherwise as per their utility.
  13. Private/internal methods should be avoided as their usage encourages keeping too much responsibility in a class since the method calling it is smaller. Most likely, these should be part of a new class tasked with the responsibility of what the method does. Moreover these cannot be mocked so every class calling them has to cater for what they do.
  14. ViewBag usage should be minimised/eliminated. The biggest disadvantage being no name or type safety checks, it also encourages unplanned hacks which are best avoided.
  15. Use models for all method parameters – the more specific the better. This is useful for MVC actions too. In the vast majority of cases, MVC binds them without any problem. The signature of method calls doesn’t change if the model changes and the method/action is easier to test or mock out. A whole bunch of logic can be pushed to the model which the calling class doesn’t need to know of – it can tell the model to do stuff, even passing it repositories/services etc to do work.
  16. The size of models should be an indication of complexity of the calling method/class. Too many properties/methods indicate a need to split it (and possibly the calling class/method) into multiples.
  17. At a more advanced level, the use of models allows use of custom model binders, which can add a whole level of logic before the controller is involved, like redirecting based on model properties – I’m looking at you Multi-Tenancy. The result, the controller is cleaner and more specific.
  18. Still need more reason to use models? For MVC controller actions FluentValidation validators can be attached to models and it’s integration with MVC can make sure that the validator is called automatically by the controller before the action. So the validation logic can be pulled into different classes, another responsibility off the controller! Tie this up with Dependency Injection and your custom validator can have services injected to do the validation.
  19. MVC controllers and their actions should be smallest possible. New view/condition? Create a new action or even new controller, making the calls as RESTful as possible.
  20. MVC filters provide a helpful way to take repeated pre/post action work out of controllers. Besides authorisation and exception handling, these can also allow setting of controller properties if that can be done using injected services. Coupled with well implemented Dependency Injection to provide constructor parameters, these can keep the controllers as lean as possible.
  21. Use AutoMapper to take care of converting classes to one another. For all its drawbacks, it provides a really nice way to separate concerns and take out a whole lot of distracting code responsibilities out of the controllers/service classes.
  22. When using AutoMapper, don’t utilise it’s Mapper class static methods – instead inject IMappingEngine for using the mappings and create them in profiles (classes extending AutoMapper’s Profile class) which can be automatically picked up & added on application start if DI is used well. In the profiles, use the CreateMap method available in the class instead of calling the Mapper.CreateMap static method. A good setup will also allow injecting other services into custom resolvers/converters when required for mapping.
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s