Nice book written by Allen Holub.We can easily come to conclusion after reading the book that author is really bold and confident on himself.
I wanted to share few important points i found from this book.
1) Programmers need to write the code in such a way that it's easy to add new features or modify existing ones, but not add the features now.
2) A recent Standish Group report, which looked at thousands of programming projects over multiple years, determined that roughly 72 percent of software projects were failures.
3) Procedural programming separates the data of the program from the operations that manipulate the data. For example, if you want to send information across a network, only the relevant data is sent (see Figure 1), with the expectation that the program at the other end of the network pipe knows what to do with it. In other words, some sort of handshaking agreement must be in place between the client and server to transmit the data. In this model, no code is actually sent over the wire.
The fundamental advantage of OO programming is that the data and the operations that manipulate the data (the code) are both encapsulated in the object. For example, when an object is transported across a network, the entire object, including the data and behavior, goes with it. In Figure 2, the Employee object is sent over the network.
4) Microsoft deliberately created a procedural system in C++, because that system would be "easier to understand." That OO-is-hard-to-understand philosophy is still dominant at Microsoft. The .NET APIs are procedural in structure, for example, and C# has language features that encourage procedural thinking. So, it's not surprising to find Microsoft applications that don't follow some of the basic principles of OO systems. Many Microsoft programmers seem to take violent exception to any OO practice that doesn't jibe with the way .NET does things, however. They're confusing "familiarity" with "correct."
5) An object is defined by what it can do, not by how it does it.Never ask an object for information that you need to do something; rather, ask the object that has the information to do the work for you.
6) Don't ask for the information that you need to do some work; ask the object that has the information to do the work for you.
For example, you don't say the following:
Money a, b, c;
//...
a.setValue( a.getValue() + b.getValue() );
Rather, you ask the Money object to do the work, as follows:
Money a, b, c;
//...
a.increaseBy( b );
You don't say, "Give me this attribute so I can print it." You say, "Give me a printable rendering of this attribute" or "print yourself."
Another way to cast this rule is to think about coarse-grained vs. fine-grained operations.A coarse-grained operation asks an object to do a lot of work. A fine-grained operation asks the object to do only a small amount of work. Generally, I prefer coarse-grained methods because they simplify the code and eliminate the need for most getter and setter methods.
7) When Are Accessors and Mutators Okay?
If you must pass information between objects, encapsulate that information into other
objects. A "get" function that returns an object of class Money is vastly preferable to one that returns a double.
8)
At a JavaOne conference James Gosling was asked to give some pithy piece of programming advice to the multitude. He chose to answer (I'm paraphrasing) that maintainability was inversely proportional to the amount of data that moves between objects. The implication is that you can't get rid of all data movement, particularly in an environment where several objects have to collaborate to accomplish some task, but you should try to minimize date flow as much as possible.
9) In Template Method, base-class code calls an overridable placeholder method, the real implementation of which is supplied by the derived class. The base-class version may be abstract, or it may actually implement a reasonable default operation that the derived class will customize.
The Factory-Method pattern describes nothing more than a Template Method that creates an object whose concrete class isn't known to the base class.
10) Whenever you see a subset, you should think "normalization." All operations that are used by all the objects in the system should be defined in a common base class. All operations that are used by only a subset of the objects in a class should be defined in a class that extends that "normalized" base class. Adding derivation, then, is a design activity that occurs well into the design process, after you've done enough dynamic modeling that you can identify the common operations. It's a way of concentrating common operations into a shared base class. So, normalization is one quite reasonable use of implementation inheritance.
If the two classes perform identical operations but do so differently, then there should be a common interface that each class implements. For example, Employee could be an interface that is implemented in different ways by both the Manager and Engineer classes.
11) If you need to change the interface or class name again, you'll still have to go back and change a lot of code. You really want to get rid of that new altogether, or at least hide it.One good strategy for avoiding the must-change-all-new-invocations problem is to use the Abstract-Factory pattern, which is usually combined with a second creational pattern, Singleton, when it's implemented.
A Singleton is a one-of-a-kind object;only one instance of it will ever exist
12) A good example of a classic Abstract Factory in Java is in the Collection class, which serves as an Iterator factory.
13) Another useful pattern for creating objects in an abstract way is Strategy, which is a specialization of the more general pattern Command.
Command is a building-block pattern upon which almost all the Gang-of-Four Behavioral patterns rely.The basic idea of Command is to pass around knowledge of how to do something by encapsulating that knowledge within an object.
One basic-to-Java use of Command is in threading. The following code shows a way to run a bit of code on its own thread that emphasizes the use of the Command pattern:
class CommandObject implements Runnable
{ public void run()
{ // stuff to do on the thread goes here
}
};
Thread controller = new Thread( new CommandObject() );
controller.start(); // fire up the thread
You pass the Thread object a Command object that encapsulates the code that runs on the thread. This way, the Thread object can be completely generic—it needs to know how to create and otherwise manage threads, but it doesn't need to know what sort of work the thread will perform. The controller object executes the code by calling run(). One of the main characteristics of the Command pattern is that the "client" class—the class that uses the Command object—doesn't have any idea what the Command object is going to do.
14) Strategy Pattern: Use a Command object to define a strategy for performing some operation and pass the strategy into the object at runtime. You can often use Strategy instead of implementation inheritance if you're extending a class solely to change behavior.
Another good example of Strategy in Java is the LayoutManager used by java.awt.Container and its derivatives. You add visual objects to a container, which it lays out by delegating to a Strategy object that handles the layout. For example, the following code lays out four buttons side by side:
Frame container = new Frame();
container.setLayout( new FlowLayout() );
container.add( new Button("1") );
container.add( new Button("2") );
container.add( new Button("3") );
container.add( new Button("3") );
15) The point of Facade is to make it easier to access a complex system via a simple one.
16) A Bridge separates subsystems from each other so that they can change independently. Unlike Facade , a Bridge provides complete isolation between subsystems. Code on one side of the Bridge has no idea what's on the other side. (Facade, you'll remember, doesn't hide the subsystem—it just simplifies access to it.)
17) Abstract Factory makes it easy to create and manipulate objects without knowing exactly what they are. (This example uses an Iterator—it doesn't care what kind.) This way, it's easy to add new sorts of concrete products to the system without changing any of the code that uses those products.
18) Builder pattern Separate the construction of a complex object from its representation so that the same construction process can create different representations without having to modify the constructing object.
Hope you enjoy reading the book.
About the Author
Allen Holub has worked in the computer industry since 1979. He currently works as a consultant, helping companies not squander money on software by providing advice to executives, training, and design-and-programming services. He's authored eight books, including Taming Java Threads (Apress, 2000) and Compiler Design in C (Pearson Higher Education, 1990), and teaches regularly for the University of California Berkeley Extension. Find more information on his Website (http://www.holub.com).
6 comments:
Alan Holub is an idiot. I wonder how many projects have gone down in flames because someone with authority took him seriously. For example, this Holubism:
You don't say, "Give me this attribute so I can print it." You say, "Give me a printable rendering of this attribute" or "print yourself."
is especially stupid. It breaks the fundamental rule of separating data from its presentation. He had an article on Javaworld, IIRC, that said the same thing a while back, and he got ripped apart for it in the comments, and deservedly so.
I think your post is a little bit too harsh. While you may not agree with everything the author says, I wouldn't agree that he is an idiot.
I especially agree with numbers 5, 6 and 7. I continue to see many, many examples where objects are simply used to carry data to be queried via getXXX methods (thank you Java Beans) and manipulated by what is essentially procedural code.
Maybe on the surface the "Give me a printable rendering of yourself" seems stupid to you, but consider that the implementation could be delegated to some other package level class that knows how to create the printable version. I don't think it is prudent to dismiss this completely.
Just my 2 cents...
Hi,
Thanks anonymous and Paul for your comments.
I donot have courage to comment on author but i think i agree with the author in some way.
I read Holub's book last year and I found his book interesting, made me think over a few things - but in general I also found him too pedantic and extreme. For example, .NET may break good OO in some API's but on the other hand, you do not need to lookup in a book to see which Readers to use and which adaptors to apply to open up a file. I also read "Refactoring to Patterns" last year and generally find it more rewarding than the Holub one.
casper,
thanks for passing on your comments.
I happened to come across your review, and I'd like to toss into the mix that "print yourself" is indeed too simplistic a notion to be useful in the real world. The book talks extensively about the Builder design pattern, which is a practical way of separating the model and presentation code while remaining true to the notion of implementation hiding and encapsulation, and it's these last two concepts that are the important ones.
The problem with any list of "high points," such as the current one, is that they by necessity present things out of context. The notion of an object being responsible for it's own UI is a complex one, with lots of ramifications. As with any design principal, there are many trade offs when it comes to implementation, and decisions have to be made in the context of the problem at hand. Sometimes there simply is no "correct" answer.
More to the point, you really need to put some of the comments in this post into context to understand what I'm actually saying. I'd suggest that you read the book before coming to a conclusion.
-Allen Holub
Post a Comment