|
Simplicity is prerequisite for reliability.
–Edsger W. Dijkstra
1930-2002, Dutch Computer Scientist |
When building web applications, everybody seems to be using the Model View Controller (MVC) pattern. We all use it. It’s a fundamental pattern. However, a lot of people use it incorrectly. Actually, in my six years of programming, I have never seen it done the proper way. From what I’ve seen, the majority of the MVC implementations have a major flow: too much “model” in the controller. That’s a critical error and a no-no in proper usage of the pattern.
So how should it work? The critical thing is not to have any business logic in the controller, and have a separate business layer that is not aware of the view technology.
Here are fundamental characteristics of MVC:
Model: encapsulates all of the business logic. It is not aware of the view technology.
Controller: fetches the information needed from the view, puts it together and calls the appropriate models for processing. It contains no business logic.
View: displays the model that it gets from the controller.
I just thought of a good analogy for the Model. Think of it as the brain. It’s the most important thing. You don’t want to distribute its knowledge into other parts. What if you lose the other part, a finger let’s say, do you want to be dumber as a result? I certainly would not like that.
Martin Fowler, in Patterns of Enterprise Architecture, says that the proper definition for the Controller is “input controller.” He has a good explanation of MVC.
“A request comes in to an input controller, which pulls information off the request. It then forwards the business logic to an appropriate model object. The model object talks to the data source and does everything indicated by the request as well as gather information for the response. When it’s done it returns control to the input controller, which looks at the results and decides which view is needed to display the response. It then passes control, together with the response data, to the view.”
“Ensure that the models are completely separated from the Web presentation,” says Fowler.
How can I test whether I have a good MVC? It is not always easy. Here’s a good test: can I add a different view technology without duplicating any business logic?
The biggest benefit of proper implementation of the MVC pattern is that you have a separate business layer. Because it is seperate, it is easier to test — you don’t need a container to test. It is easier to understand. You don’t have duplication. And you are well prepared to add a different view technology to it without a major effort.
Another great benefit is that your architecture remains simple. Your controllers are simple. The business logic might be complicated, but it is in a separate layer and encapsulated in one place.
It is tempting to put business logic into the controller or the view (we all did it). Stop. Don’t do that. (I should yell here. ) Refactor the architecture if you have to. Putting business logic into the controller makes the application harder to maintain, it makes the business logic almost impossible to test, and it also spreads the business logic into several layers. All smells of a bad design.
The Spring framework gives you a skeleton MVC out of the box. But if you look at it, it only gives you the VC part, without the M. You have to add the M, the business logic yourself. It is very easy just to add it into the controller. I that’s what a lot of people do. Then you really have a VC pattern. Make sure you add the missing M and make sure it sits in a different room than the VC.
You will benefit in a big way if you followed the MVC principles. And no exceptions. You are hurting yourself if you follow an ad-hoc approach — a little logic here, a little there.
If you want to be a good coder, when using the MVC pattern, never break its principles.
A fairly common occurence I’ve come across in software development is that a class I’m working onchanges for various non-related reasons. For one type of change, I modify a portion of it, and for another, another portion. That’s not a good situation.
Martin Fowler calls this “divergent change” under the Code Smells category. He says thefollowing,
“Programs should be structured in such a way that we can make changes easily. When we make a change we want to be able to jump to a single clear point in the system and makethe change.Divergent change occurs when one class is commonly changed in different ways for different reasons. Ifyou look at the class and say, “Well, I will have to change these three methods every time I get a new database; I have to change these four methods every time there is a new financial instrument,” you likely have a situation in which two objects are better than one. That way each object is changed only as a result of one kind of change.”
Robert Martin calls this principle The Single-Responsibility Principle: A class should have only one reason to change.
In this context, he defines responsibility as “a reason for change.” If you can think of more than one motive for changing a class, then that class has more than one responsibility. “It’s not easy to see that because we usually think of responsibilites in groups.”
What’s an example of a responsibility coupling? Martin gives a common violation of the SRP: Employee class containing business rules and persistence control. Business rules tend to change frequently, and persistence usually changes for completely different reasons. A clear violation.
Interestingly, Martin calls this principle one of the simplest, and at the same time, one of the hardest to get right. “Conjoining responsibilities is something that we do naturally. Finding and seperating those responsibilites from one another is much of what software design is really about.“
Thus, when adding new functionality to a class, I think it’s important to keep in mind that they don’t violate the Single-Responsibilty Principle. This has a side effect of keeping your classes cohesive. And you knowthat is a good thing.
Once again, if over time you make changes to a class that touch completely different parts of the class, you have a violation of the principle. Split the class in two. Put the parts that change together into their own class. You’ll be glad that you did.
ReferenceMore Info on SRPSingle-Responsibility principle is a fundamental principle in software design. It is a good idea to”embed” it into your software development knowledge. http://www.objectmentor.com/resources/articles/srp
Refactoring, Martin Fowler’s influential and still relative book on refactoring (Code Smells section is invaluable).
Agile Software Development, Robert Martin’s book on patterns, a great book. He talks about fundamental patterns in OO development. A must read.
Object Solutions : Managing the Object-Oriented Project
by Grady Booch
ISBN 0805305947
Date Read 6/2006
My Rating
I love reading what Grady Booch has to say. He’s an authority to me. In this book, he gives a lot of good advice. He gives a lot of good information what OO should be like, not just projects but advice on how to do better OO design. That’s good stuff. This book, however, shows its age. The good stuff is mixed with at times “dry” information, boring at times. A better format of the book would help as well. Nonetheless, a valuable book to read.
Sams Teach Yourself Regular Expressions in 10 Minutes
by Ben Forta
ISBN 0672325667
Date Read 5/2006
My Rating
This is a great intro book to regular expressions. The best, I would say. This is the first book I read on regular expressions. I loved the short-chapter style; I loved the examples and the referenced program to run them (though now I can run RE in Eclipse). Like I said, this is the best intro to RE, a valuable tool in your toolbox. For a more advanced book, Mastering Regular Expressions is considered a bible.
In an object-oriented world, special exceptions are evil. To me, they ruin a well-structured framework/project. Yet in the business world, they are fairly common. What do you do?
I think the worse thing you can do is to actually add a special exception to a special-case free project. Once you do that, your project will take a downhill drive towards unmaintainability.
Let’s say that you have a nice inheritance and polymorphism in place: a well-structured OO system. To be more specific, let’s say you have a base class Shape and a Circle and a Square as subclasses. Everything works nicely: you only care about the Shape class and everything else takes its polymorphic runtime form.
Then, a business person comes in, with the usual time pressure, and asks you to implement something that resembles a Shape but it works a little differently. What do you do? You don’t want to spend some extra time to refactor the original structure. And you don’t want to implement a new structure as well — too time consuming.
So what do you do? You add a special exception: you create a special-cased Shape. From now on, whenever you use the Shape object, you add the special exception to make sure something different is performed. Just a few lines of code. Everything works. You’re happy. You’re done. Quick.
But you did something else. You just ruined a well structured OO project. From now on, anytime you use the Shape object, you have to duplicate the special exception. It’s only a matter of time when somebody forgets to do that. Ooops. A bug is let into the system. You created the opening with the special exception.
What else did you do? A level of frustration to the maintainer. The system is much more difficult to maintain after that.
Never do that! Take the time to do it right. Never put a special condition to a perfectly working OO system (with inheritance and polymporphism). Unless, of course, you don’t care… and you consider yourself a crappy programmer.
I like the following saying: If you don’t have the time to do it right, will you have the time to do it over?
You save some time at the time of implementation, but you will pay for it several times later.
So, anytime you need to add a special condition, and it’s inevitable, refactor the code to support that, but don’t add a special condition. It never works.
A better coder is a happy coder, don’t spoil that.
I have been enjoying the CareerNews letter for some time. It is a newsletter (available to all) produced by the ACM organization. It focuses on, guess, IT career-related news. It does a nice job agreggating them from different sources. It also does a nice job providing concise comments. A lot of times I only read their comments, as the article itself is not as clear. They really do a great job.
The latest issue of the CareerNews newsletter is packed with excellent articles.
The article I like the most is “Young and Hungry“, which explains how you, as a young professional (and not only), should work towards going up in the corporate ladder.
Another article that I liked is “Enterprises Focus on Retaining Tech Talent” (the title says it all).
I recommend that you check out the newsletter and subscribe to it. It’s bi-weekly and every issue contains at least one good article. It is a good way to see what’s going on in the IT profession.
ReferenceCareerNews Newsletter, available for everyone
Writing good OO code is not easy. Here’s a set of rules of thumb when creating classes. These are taken from the Object-Oriented Design Heuristics book by Riel — good stuff.
2.2 Users of a class must be dependent on its public interface, but a class should not be dependent on its users.
2.3 Minimize the number of messages in the protocol of a class.
2.4 Implement a minimal public interface that all classes understand [e.g., operations such as copy (deep versus shallow), equality testing, pretty printing, parsing from an ASCII description, etc.].
2.5 Do not put implementation details such as common-code private functions into the public interface of a class.
2.6 Do not clutter the public interface of a class with things that users of that class are not able to use or are not interested in using.
2.7 Classes should only exhibit nil or export coupling with other classes, that is, a class should only use operations in the public interface of another class or have nothing to do with that class.
2.8 A class should capture one and only one key abstraction.
2.9 Keep related data and behavior in one place.
2.10 Spin off nonrelated information into another class (i.e., noncommunicating behavior).
2.11 Be sure the abstractions that you model are classes and not simply the roles objects play.
ReferenceObject-Oriented Design Heuristics, Riel
Creating methods is probably the single most often performed activity during programming. Thus, it is crucial that it is performed well. When creating a method, I think the most important thing is that it should perform one task and do it well: it should have high cohesion.
High cohesion is the fundamental principle in object oriented programming (probably the most important). If there was a way to require high cohesive methods, then it should be a requirement. I’m all for it.
If you have cohesive methods then it is a good sign that you are a good Object Oriented developer. It shows that you program for a human to read, not the computer. Having high cohesion is hard, you have to have one-task methods with good method names. It is a constant struggle to keep it cohesive with the additions/modifications. But if you accomplish that, then you’re good. :- )
So do you have to care about the method size?
Actually, you should not. But somehow, you find a lot of methods that are very long. A lot of them are over 100 lines, some are over 150 lines. I’ve seen even longer than that.
I think a good rule of thumb to adopt is to have methods that do not exceed your screen’s size. It’s a good rule. It allows you to see the whole method without scrolling. Which means your method should not be longer than 70-100 lines, roughly.
Alternatively, if you have a generic method name and your method is long, it should (be required to) be refactored and the related things put into its own method.
In the Signs You’re a Crappy Programmer (and don’t know it) article, the author states [that you are a crappy programmer] if:
You are adamantly opposed to function/methods over 20 lines of code. (or 30 or 10 or whatever number of lines) Sorry, sometimes a really long function is just what’s needed for the problem at hand. Usually shorter functions are easier to understand, but sometimes things are most simply expressed in one long function. Code should not be made more complex to meet some arbitrary standard.
I think the key word is “sometimes.” It’s OK to have a long method here and there, the problem is when you have it in a lot of places — in too many places. If your method does one function — one responsibility — and it takes over X lines, it’s fine, no reason to break it up. But a lot of times, those long methods “accrue” extra responsibilties, making them harder to maintain. I think everyone can agree that a long method is harder to understand and modify than a shorter one.
Actually, I think you are a crappy programmer if you have a lot of those long methods with non-specific names.
The bottom line is to have functions that do one task and do it well. If you do that, you don’t have to worry about the length, your methods will be short and easy to modify.
Everybody would benefit if you adhered to the rule of thumb, especially the maintainers of the code.
ReferenceSigns You’re a Crappy Programmer (and don’t know it), Damien Katz
RelatedWrite English the Way You Write Code – very good post
I don’t know if anybody actually reads the comments that we sometimes write as Javadoc. Do you? I don’t, most of the time.
That’s why I think it’s important to write code that speaks for itself and that does not need a comment. I’d go this far: if you need a comment, your code should be refactored and made easier to understand. (What does it mean easy? Easy for somebody else to understand — important to keep this in mind as well.)
So how do you write self-documented code?
Use good names. For class names. For variable names. And for method names. Don’t name your class WriteData or ConnectionInfo. They should have better names. They should be more specific. You should be able to tell what a class or a method does by its name.
Be short and specific. I hate it when I have to modify a 1000+ line class. I hate it when I have to modify a method over 100+ lines (you should have rules for these :- )). Have classes that have a specific set of tasks to accomplish. Have methods that do one thing and do it well. In this regard, it helps to have good and specific names so you know exactly what your class or method is doing, and whether you need to assign the new responsibility to a new class (assigning responsibility is crucial in OO development, as I said before).
Abstract it when you can. When you have some complicated logic, encapsulate it in a class, hide the complexity. By doing so, you’re putting it in one place and you don’t have to delve into details of how it works, as long as it works — you assign it a responsibility and you hold it accountable. If you keep adding complicated logic to a class or a method, you’re messing up the class, making it harder to undertand and modify. If it was seperate and nicely abstracted, you can modify it with more confidence. Maybe it’s better to add a new class, a new method? Ask yourself that before adding any complex logic.
When writing a comment, focus on “why” not “how.” Make every comment be of substance. Comment surprises.
In some cases you have to have complex logic. Add a comment then. Make it easier for you and for others. Prepare the reader for complex logic with a comment, explain why it is being done that way.
I think writing a self-commented code, code that is easy to read, is a crucial part in our day-to-day programming. It’s one of the things that has huge effect — in both positive and negative direction.
To be a good coder, to become a better coder, make sure your code is easy to read.
RelatedCode Complete, Steve McConnell’s excellent book (my previous recommendation), required if you want to become a better coder