Sunday, 6 June 2010

Object-Oriented Design Principles - Part 2

In the first part of this Object-Oriented Design principles series, I covered the Single Responsibility Principle (SRP). I had also covered the Liskov Substitution Principle (LSP) on a previous post. So let's move on to another Object-Oriented Design Principle.

The Open Closed Principle (OCP)

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification

We know that requirements will change, new requirements will come and we will need to change some existing code during the life of a project. However, when a change in one place results in a cascade of changes in other classes, that's a sign that the design is not quite right. Changes causing side effects are undesirable since it makes the program unstable, rigid and fragile where parts can not be re-used.

The Open Closed Principle target all problems described above. Being open for extension means that modules can be extended in order to make them behave in a new or different way. Closed for modification means that we should not change existing code unless that we are fixing a bug.

There were two proposed ways to achieve the OCP and both use inheritance:
  1. Dr. Bertrand Meyer, that coined the Open Closed Principle in 1988, proposes the use of inheritance. When a new feature or a changing on an existing feature is needed, a new class must be created, inheriting from the old one. The new class does not necessarily keep the same interface. 
  2. A few other authors redefined the OCP in the 90ies. Basically they suggested the use of abstract base classes and concrete implementations. The abstract class would define the interface that would be closed to modifications. The concrete classes would implement the abstract class interface (open for extension) and multiple implementations could be created and polymorphically substituted for each other. 
Nowadays, with the evolution of frameworks with dependency injection capabilities, a better approach would be having a client class pointing to an plain Java interface and inject the implementations. 

OCP is an old OOP design principle and is one of the most important ones, due to the problems it solves. It can be an interesting approach in cases where the bureaucracy of changing old code and deployment to the production environment is very high. Some companies may ask for code reviews, a long test cycle (non-automated), documentation, etc. With OCP, no existing code is changed and just new code is added.

However, in a more agile environment, good test coverage, IDEs that have good re-factoring tools (like Eclipse, Idea, etc) I wouldn't be too worried about changing classes and interfaces but this would not invalidate all the advantages of the OCP.

Source
http://en.wikipedia.org/wiki/Solid_%28object-oriented_design%29
http://en.wikipedia.org/wiki/Open/closed_principle
http://www.objectmentor.com/resources/articles/ocp.pdf
http://en.wikipedia.org/wiki/Design_by_Contract
http://en.wikipedia.org/wiki/Information_hiding

Thursday, 3 June 2010

Object-Oriented Design Principles - Part 1

Almost every developer that I know would be able to give a reasonable explanation about inheritance, encapsulation and polymorphism. However, there is much more to Object-Oriented Programming (OOP) than that. In order to come up with a good and clean design, we need to bear in mind some Object-Oriented Design (OOD) principles. Although many of these principles were already published in books and blogs, they are known to just a very small percentage of developers. I don't want to show my age here, but very rarely we find young developers talking about OOD Principles.

There are quite a few OOD principles out there, created/coined by different developers and academics, but I will be listing here just the OOD principles that I consider to be the most important ones.

The following 5 principles together are known by the mnemonic acronym "SOLID". They were first put together by Robert C. Martin (Uncle Bob) in the early 2000s and should be applied at class level. They are:

The Single Responsibility Principle (SRP)

There should never be more than one reason for a class to change. 

The SRP is the simplest OOD Principle and probably one of the hardest to get right. It is also one of the most violated principles.

Let's have a look at the following class:

public class TripItinerary {
public void addPlace(Place place) { ... }
public void removePlace(Place place) { ... }
public List<Place> getPlaces() { ... }
public void displayOnMap() { ... }
public Place findPlaceByName(String placeName) { ... }
}

The class above has 3 different responsibilities, that means, 3 different reasons to change:
  1. Store the places to be visited.
  2. Display the itinerary on a map.
  3. Finds a place by name.

Storing places on the itinerary may have rules like not adding repeated places, keeping the sequence that places will be visited, etc.
Displaying on the map may vary according to the map API being used like Google Map, Bing Map, Yahoo Maps, etc.
Find a place by name may involve calling a web-services to see if the place exists, if there are more than one place with the same name, checking the type of place (city, town, waterfall, monument, castle, etc).

Ideally we would have three different classes to do that, each one with its own responsibility.

public class TripItinerary {
public void addPlace(Place place) { ... }
public void removePlace(Place place) { ... }
public List<Place> getPlaces() { ... }
}

public class ItineraryMapService {
public void displayOnMap(TripItinerary tripItinerary) { ... }
}

public class PlaceService {
public List<Place> findPlaceByName(String placeName) { ... }
}

With these approach, we can change the internals of all classes without having the risk of breaking any of the behaviour of the other classes. Without this separation, the design becomes fragile and might break in unexpected ways when changed.

When thinking about a single responsibility, think cohesion at class level. Before creating a class, we need to define what its responsibility should be and the reason for its existence. Before adding any other public method to an existing class, check if this new method relates to the other public methods (the class interface). When creating public methods for a class, have them at least at a communicational cohesion level.

On the next posts, I'll be covering the remaining SOLID OOD principles.

Object-Oriented Design Principles - Part 2

Source
http://en.wikipedia.org/wiki/Solid_%28object-oriented_design%29
http://en.wikipedia.org/wiki/Single_responsibility_principle
http://www.objectmentor.com/resources/articles/srp.pdf

Tuesday, 1 June 2010

The Liskov Substitution Principle (LSP)

The Liskov Substitution Principle was initially introduced by Barbara Liskov in a 1987 conference keynote address entitled Data abstraction and hierarchy. LSP is also part of SOLID, a group of five Object-Oriented Design Principles put together by Robert C. Martin in the early 2000s. 

Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

The LSP's summary above looks quite obvious. If the calling code was written to use a base class, replacing it with a sub-class (inheritance) should make no difference to the calling code. That means, the calling code should not be changed and should be totally agnostic about which implementation is being used.

LSP's importance is noticed mainly when it is violated. If a subclass causes changes on the calling code, that means, the calling code needs to test which subclass it is dealing with (instanceof, casting, etc), the code is violating the Liskov Substitution Principle and also the Open Closed Principle. This violation causes high coupling, low cohesion and a cascade of changes.

Violation of Liskov Substitution Principle

public void drawShape(Shape s) {
if (s instanceof Square) {
drawSquare((Square) s);
} else if (s instanceof Circle){
drawCircle((Circle) s);
}
}

The Liskov Substitution Principle also imposes a few rules that the sub-classes must obey. It bears a certain resemblance with Bertrand Meyer's Design by Contract in that it considers the interaction of subtyping with pre- and postconditions

...when redefining a routine [in a derivative], you may only replace its precondition by a weaker one, and its postcondition by a stronger one.

This means the sub-classes must accept everything that the base class accepts (pre-condition) and must conform to all postconditions of the base class.

Example of a more subtle violation
public class Rectangle {
private int height;
private int width;

public Rectangle(int height, int width) {
this.height = height;
this.width = width;
}
public int getHeight() {
return this.height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWidth() {
return this.width;
}
public void setWidth(int width) {
this.width = width;
}
}

public class Square extends Rectangle {

public Square(int size) {
super(size, size);
}
public int getHeight() {
return super.height;
}
public int getWidth() {
return super.width;
}
}

In the code above, a Square IS A Rectangle. Note that a rectangle can have different sizes for width and height, but in a square, height and width must be of the same size. What would happen in the following code is executed ?

Rectangle r = new Square();
r.setHeight(5);
r.setWidth(6);

We should not allow this to happen since that would make the Square object invalid. In a square, height and width must always be the same. A quick fix for this would be to override the setter methods:

public class Square extends Rectangle {

public Square(int size) {
super(size, size);
}
public int getHeight() {
return super.height;
}
public int getWidth() {
return super.width;
}
public void setHeight(int height) {
super.height = height;
super.width = width;
}
public void setWidth(int width) {
super.width = width;
super.height = width;
}
}

Although this approach would fix the problem, is a violation of the Liskov Substitution Principle since the methods will weaken (violate) the postconditions for the Rectangle setters, which state that dimensions can be modified independently.

One interesting thing to note is that if we analyse the Rectangle and Square classes in isolation, they are consistent and valid. However, when we look at how the classes can be used by a client program, we realise that the model is broken.

Every time you get yourself adapting a sub-class so that it does not break or its state does not become invalid if used in the context of a super-class, this is a clue that the sub-class should not be a sub-class at all.

In this example, maybe a Square is not a Rectangle. Square should not have height and width to start with. It should just have size. And since a Square is not a Rectangle, it should never be used in a Rectangle context.

public class Square {
int size;

public Square(int size) {
this.size = size;
}
public int getSize() {
return this.size;
}
public void setSize(int size) {
this.size = size;
}
}

We can not validate a model in isolation. A model should be validated just in terms of its clients.

Source
http://en.wikipedia.org/wiki/Liskov_substitution_principle
http://www.objectmentor.com/resources/articles/lsp.pdf

Friday, 28 May 2010

Meet me in Florence this summer!

Have you already decided which conference to attend this year? Is it perhaps the Euromar?
Of all the people I know, nobody will be attending this event. I have examined the list of sponsors and exhibitors and there will be no representative of the software industry.
They used to attend the past Euromars and were unhappy. I myself have no intention of registering...
A Worldwide Magnetic Resonance Conference ???
Why have I chosen this apparently ignored occasion? I will not attend any conference at all this year, but I will try to be in town during that week (from July 4 to 10), so this could be a unique opportunity to meet me in person.
How can you contact me? Try adding a comment to this post. Your comment will be submitted to my moderation and will not appear (automatically) in public. If you insert your email address, I will contact you. If you have submitted a poster, write here the title, so I can find you directly at the conference.
Weather info: July can be very hot in Florence, but the "PalaCongressi" that helds the conference is quite comfortable. It is a sort of huge underground bunker, shielded from the heat.

Monday, 24 May 2010

Empowering your entities

The first thing I learnt when I started with Object-Oriented Programming was that an object should have state and behaviour. And indeed, that's how it was back then. However, since J2EE (Entity Beans) and other ORM tools like Hibernate, iBATIS, TopLink, JPA, etc, everything changed. We were so focused in mapping tables to objects, configure the relationships, lazy loading, eager fetching, primary keys and everything else that you can map and configure on the ORM tools that we simply forgot that those entities could and should also have some behaviour.

In general, for applications that use a database, the entities are the key focus of the application. They are the main components of an application's core domain and their names and methods should represent, and also help to define, a common language used by all members of the team and not just developers (See Ubiquitous Language - Domain Driven Design). 
 
Let's see a few situations where your entities could be empowered.

1. Default values / initialisation

Let's have a look at a fairly simple piece of code and see how many problems it may cause:

Listing 1.1
// Somewhere in the code 
DiscussionGroup dicussionGroup = new DiscussionGroup();
discussionGroup.setCreationDate(new Date());
discussionGroup.setLastUpdate(new Date());
discussionGroup.setAllowAnonymousPosts(false);

// Somewhere else in the code
if (discussionGroup.getAccess().equals(Access.PUBLIC) {
this.displayDiscussionGroupInfo(discussionGroup);
};

Members members = discussionGroup.getMembers();
for (Member member : members) {
     // Do something
}

This code above has the following problems:
  • creationDate and lastUpdate setters being called right after creation. Let's assume both attributes are mandatory on the database. Wherever in the code a DiscussionGroup is created, we need to remember to set them both. In Failing to do so, we will get an error when persisting the entity.
  • The check to verify if the discussion group is public may throw a NullPointerException if the attribute is not initialised.
  • Like the access check, the iteration over the discussion group members can also fail if the list of members is not initialised.
  • The calling code needs to know about the internals of the entity and cater for that, like setting values to mandatory fields and also do null checks for some attributes.

To solve the problems, just initialise all the attributes you can, I mean, the ones where a default value would make sense. Always avoid having getters returning null.

Listing 1.2
// DiscussionGroup.class
public class DiscussionGroup {
private Date creationDate;
private Date lastUpdate;
private boolean allowAnonymousPosts;
private Access access;
private List<Member> members;

public DiscussionGroup() {
this.creationDate = new Date();
this.lastUpdate = new Date();
this.allowAnonymousPosts = false;
this.access = Access.PRIVATE;
this.members = new ArrayList<Member>();
}
}

2. Operation that just involves an entity's attributes.

Look at the code below.

Listing 2.1
// OrderService.class
if (order.getTotal() > 0
&& order.getOrderItems().size() > 0
&& order.getAuthorizationDate() != null
&& order.getClient() != null) {
this.processOrder(order);
}

The if statement checks attributes from the order object so that it can decide if the order can be processed or not. Note that this logic is outside the order object, making the two classes tightly coupled and making a poor use of encapsulation. In this case, we could re-factor this code like that:

Listing 2.2
// Order.class
public boolean isReadyForProcessing() {
this.getTotal() > 0
&& this.getOrderItems().size() > 0
&& this.getAuthorizationDate() != null
&& this.getClient() != null);
}

// OrderService.class - Somewhere in the code
if (order.isReadyForProcessing() {
this.processOrder(order);
}

This re-factored code makes the code more expressive, easy to read and easy to test. This also makes the code to better represent the business rules.


3. Children manipulation

Look at the listings 3.1 and 3.2.

Listing 3.1
// Add an entry to a diary.
Diary diary = new Diary();
Entry entry = new Entry();
entry.setDate(new Date());
entry.setText("Today I went ... ");
diary.getEntries().add(entry);

Listing 3.2
// Remove an entry from a diary.
ListIterator<Entry> entriesIterator =
diary.getEntries().listIterator();
Entry entry;
while (entriesIterator.hasNext()) {
entry = entriesIterator().next();
if (entry.getDate().equals(someDateVar)) {
entriesIterator.remove();
}
}

The main problem with Listing 3.1 and Listing 3.2 is that the parent class Diary is exposing its internals, the entries. Once again, this is a major encapsulation breach. As a principle, the parent should never let a stranger manipulates its children without its consent. Besides all the code duplication that this may cause, in case that I want to add/delete entry in different parts of the application (for some reason), this also makes the code to be very fragile where the parent may break since it was not notified that someone changed its children.

This could be easily fixed if we add this logic to the parent class.

Listing 3.3
// Diary.class
public Entry addEntry(Date date, String text) {
Entry entry = new Entry();
entry.setDate(date);
entry.setText(text);
this.entries.add(entry);
return entry;
}

public Entry deleteEntry(Date date) {
ListIterator<entry> entriesIterator =
this.getEntries().listIterator();
Entry entry;
while (entriesIterator.hasNext()) {
entry = entriesIterator().next();
if (entry.getDate().equals(someDateVar) {
entriesIterator.remove();
break;
}
}
return entry;
}

The calling code would be like:

Listing 3.4
// Add an entry to a diary.
Diary diary = new Diary();
Date date = new Date();
diary.addEntry(date, "Today I went ... ");

// Remove an entry from a diary.
diary.deleteEntry(date);

Conclusion
Entities don't need to be just dumb classes with state and no behaviour. They should contain business logic that is related to their attributes and children. This will promote encapsulation, reduce code duplication, make your code more expressive and easy to read and also much easier to test.

Sources:
http://domaindrivendesign.org/
Domain Driven Design - by Eric Evans
Clean Code - by Robert C. Martin

Saturday, 8 May 2010

MVC and Multi-tier architecture

Over the years, working in different web-based Java projects, I noticed that there is a big confusion about the boundaries and overlaps between MVC, that is an architectural pattern, and a multi-tier architecture (also known as n-tier architecture). The main confusion is in identifying what is controller, what is model and what is application (business) tier. The results of this confusion, to name just a few, are:
  • Unclear design;
  • Poor re-usability (loads of copy and paste);
  • Non-cohesive classes and methods;
  • Business logic all over the place;
  • Difficult to test;
  • Difficult to measure the impact of changes and improvements;
  • And people's favourite, actions (if using Struts-like web frameworks) with hundreds, if not thousands of lines.  
I'll quickly refresh our memories about multi-tier architecture and MVC so that later we can see how they relate to each other.


Multi-tier architecture

Often called n-tier architecture, the multi-tier architecture is a logical way to separate the different responsibilities of your application. The most common multi-tier architecture is the three-tier architecture, which will be the one that I'll be focusing on.


The tree-tier architecture is divided in the following tiers:

  1. Presentation tier: It is responsible to interact with the user, displaying information and providing ways where the user can input data and perform actions. 
  2. Application tier: It is responsible for the coordination of the application, its business logic, decisions, calculations and evaluations. It executes commands, actions and moves data between the presentation and data tiers. It is also known as business tier, logic tier or middle tier.
  3. Data tier: It is responsible to retrieve and store data. Data can be stored in a database, xml, file system or even other system. It is also known as persistence tier.

Each tier must be as independent as possible from each other, where a good practice would be to provide interfaces as "facades" to each tier. Organising your classes according to these logical tiers would make the code more cohesive, loosely coupled, easier to understand and easier to test. This approach would also help to improve greatly the re-usability and would make changes to be more localised, minimising the impact on the rest of the code.

A multi-tier architecture would be for applications that access other systems (RPCs, webservices, etc), access multiple sources of data, or uses any sort of middleware.

MVC and Java MVC frameworks.

I will assume that people reading this post already know MVC so I'll give just a brief and generic description of how MVC and its variations like Model 1 and Model 2 work. If you need more information about it, please refer to the links at the end of this post.



The general behaviour of the MVC pattern is:
  1. User performs an action on the view (screen, page). This action can be anything like clicking a button, clicking a link, selecting an item from a drop down list, etc. Data may be submitted, in case of a form.
  2. Controller receives the request or event and invokes the model.
  3. Model will perform some business logic, persist or fetch some data.
  4. Model return the result of this operation to the controller. This result may include some data. 
  5. Controller, according to the result from the model, invokes the next view. The next view can be the same one that originated the request or a different one.
  6. View is rendered. The view may display any data returned from the model.
Java MVC frameworks like Struts, Spring MVC and alike are based on what we call MVC Model 2, that is a variation of the original MVC pattern.

Fitting MVC into a Three-tier Architecture

In a traditional java web application, View and Controller will belong to the Presentation tier and Model will belong to the application and data tiers.


So far so good, but when using Java Web frameworks like Struts, Spring MVC, JSF, etc, the catch is to be able to identify what is controller and what is model.  

Understanding the role of the "action" classes.

Struts was one of the first and one of the most used Java MVC frameworks. When it was released, back in 2000 (version 1.0 in 2001), many developers did not get the whole MVC Model 2 thing and very quickly started misusing the framework and sacrificing some important architectural patterns. The situation got worse when other frameworks also based on Model 2 were released, since the same bad old habits from Struts  were used to develop applications with frameworks like WebWork, Spring MVC, etc.

In Struts, when some action is performed on the page, an "action" class is invoked. This action class is probably the source of the whole problem. What exactly is this action class? I mean, what's the purpose of this class and where does it belong, taking into consideration the MVC pattern and the three-tier application?

Since the View is done by the JSPs, the Controller is done by the servlet (that is configured on the web.xml), many would answer that this class is the model. This would explain why we find so many actions with thousands of lines and full of business logic.

However, the action class DOES NOT belong to the Model.

All requests are handled by the same servlet (Front Controller design pattern), and then the respective action is called (Command design pattern). The result of this action will be the view to be displayed. So, in summary, what is the responsibility of this action class? The action is triggered by the view, does some thing and decides which view will be displayed next. This is exactly what a MVC Controller does, meaning that action classes are also part of the Controller, working almost as an extension or helpers for the main servlet.

When Spring MVC came out, one of the first things that I noticed was that they called the equivalent Struts Action class, "Controller". That's right. In Spring MVC, you create controllers instead of actions, what makes much more sense. However, even naming the classes as controllers, some developers kept adding business logic to them.


In summary, the action class must just invoke the model (could be a service, session bean, business object, etc.), get the result, set it into a context (session, request, etc) and invoke the view. Action classes should be small, clean and without any business logic, as a Controller class should be.

Component-centric frameworks and its "backing bean" classes

In component-centric frameworks like JSF, Tapestry, Wicket and alike, the pages (generally XHTML) have components that are bound to Java classes (known as backing beans in JSF). These components can be input texts, drop down lists, tables, etc, or even the entire page. Basically each component on the page can be bound to a Java class, that would behave like a model and sometimes controller for these components.The backing beans are responsible to hold the state of the components and also handle events, validation, conversions, trigger business logic, update/refresh other components, fire events, listen to events, etc.  

Now that we know that Struts Actions and Spring Controllers belong to the Controller part of the MVC, where do the backing bean classes (JSF like) belong to?

When we talk about component-centric web frameworks and also add AJAX into the mix, the line between controller and model becomes a little bit blurred.

The backing bean may handle navigation and in this case, it would act as a controller. When acting as model for its view component, although it is a model, it is a model for that specific view component. That means, the logic that this backing bean should perform would be related to rendering the view component or invoking other view components (events, re-render, etc) and not exactly application business logic, keeping this managed bean coherent. Any application business logic like making calculations, fetching or storing data, make a web service call, etc, should be delegated to a business class belonging to the application tier.

So in the case of a component-centric framework, managed beans would belong to the presentation tier, even being models for view components.


NOTE: All classes related to the java web frameworks like validators, converters, forms, etc, also belong to the Presentation tier.

Summary

When developing applications it is important to keep your code cohesive and loosely coupled. The first step is to make a quick analyses and define the logical tiers. In case of a web application with database access, it will not differ too much from a three-tier architecture. If integrating with other systems or accessing multiple data sources, application and data tiers may be broken down into more tiers.

When using Java web frameworks, regardless if they are page-centric (Struts like) or component-centric (JSF like), chances are that everything related to the framework (forms, converters, validators, actions, controllers, managed beans, etc) will belong to the presentation tier and should not have business logic. Business logic and data access should be delegated from the presentation tier to the application tier. This would allow us to keep our managed beans and actions (controllers) very small and clean.

In case of too much view logic (enabling/disabling components, populating tables and drop down lists, validations, etc), use helper classes for the actions and managed beans (see View Helper design pattern)   

For the model, application and data tier, they will be covered in future posts since they can vary a lot from application to application.


Source
http://en.wikipedia.org/wiki/Multitier_architecture
http://en.wikipedia.org/wiki/Model-view-controller
http://java.sun.com/blueprints/patterns/MVC-detailed.html
http://www.ibm.com/developerworks/library/j-jsf1/
http://www.javaworld.com/javaworld/jw-12-1999/jw-12-ssj-jspmvc.html
http://java.sun.com/developer/technicalArticles/J2EE/despat/
http://java.sun.com/blueprints/corej2eepatterns/Patterns/ViewHelper.html

Friday, 23 April 2010

Cohesion - The cornerstone of OO

Cohesion is probably the most important concept of Object-Oriented Programming since it promotes a good level of encapsulation, separation of concerns and responsibilities, re-usability and maintainability.

Definition


Cohesion (noun) : when the members of a group or society are united.
Cohesive (adjective) : united and working together effectively.
Cambridge Dictionary



In computer programming, cohesion is a measure of how strongly-related and focused the various responsibilities of a software module are.
Wikipedia

Cohesion at method level
  •  Coincidental (worst): Performs multiple operations and some times they are not related to each other. 
  • Conditional: According to an if statement, different attributes are modified or different values are set to the different attributes. 
  • Iterative: Several attributes (Array variables) are modified as a result of a looping.
  • Communicational: More than one attribute is modified according to only one input. 
  • Sequential: More than one variable (object) modification result in the change to only one attribute.
  • Functional (best): Method modifies fewer than 2 attributes. 

Cohesion at class level
  • Coincidental (worst): Methods grouped arbitrarily and have no significant relationship (E.g. Util classes with methods handling strings, lists, mathematical calculations)
  • Logical: Methods grouped because they logically are categorized to do the same thing, even if different by nature (E.g. grouping all I/O handling routine, all database selects, inserts, etc.).
  • Temporal: Methods grouped by when they are processed at a particular time in program execution (E.g. validates data, persist the data, create audit information, notifies user via email).
  • Procedural: Methods grouped because they always follow a certain sequence of execution. (Verify is user exist, performs login, write logs, retrieve user's detail)
  • Communicational: Methods grouped because they work on the same data (E.g. Insert, delete, validate, update a client entity).
  • Sequential: Methods grouped because the output of one method can be used as an input of other methods. (reads a file, process the file).
  • Functional (best):  Methods grouped because they all contribute to a single well-defined task. (parsing XML)

Applying cohesion in the real world

Depending of the type of software you are writing, you will need to compromise a little bit. It is not always possible to have all methods and classes at the highest cohesion level (functional).

If you are building a framework or a very generic part of your system, chances are that the majority of your classes and methods will be at sequential and functional levels. However, when writing a more commercial application, I mean, an application where there are business logic, database access, users, etc, there is a good chance that many of your classes and methods will be more at the communicational level.

In a more simplistic way, each class and each method should have a single responsibility. A technique that I use for that is to write a brief description (javadoc) for each class and method before writing the methods of the class or the body of the method. This forces me to think what the responsibility of the class or method that I'm creating is and as soon as I realise that the class or method is doing more than what I described, I know that I need to break it down in more classes or methods (private or public ones).

Some people use other criteria, like number of public methods per class or number of lines per method. This sort of metrics are helpful because it makes you re-analyse your code and can be a good indicator that something is not quite right. A class with many public methods is an indication that the class may be doing too much and does not have a single responsibility, having a low cohesion. A method with many lines is also an indication that this method may be doing too much. One of the problems with this approach as a cohesion measure is knowing how much is too much. Is 10 lines of code per method too much? What about 20? Is 10 public methods in a class too much? Number of methods per class or number of lines of code per method don't necessarily tells much about how cohesive the class or method is, but they can be used as a "smell detector". Thinking on a single purpose for each class and each method before you implement them will help you to keep your classes and methods small without much effort.

The more cohesive your code is, the more reusable, robust, easy to test and reliable it is. 

Source
http://en.wikipedia.org/wiki/Cohesion_%28computer_science%29
http://www.waysys.com/ws_content_bl_pgssd_ch06.html
http://en.wikipedia.org/wiki/Single_responsibility_principle