Header javaperspective.com
JavaPerspective.com  >   Advanced Tutorials  >   5. Best practice tips  >   5.4. Source code organization

5.4. Source code organization
Last updated: 1 February 2013.

Source code organization is important for the readability and maintainability of an application. The readability and maintainability depend on how you organize packages, how you distribute classes among them, how the code within the classes is written and how you use Javadoc and comments. This page gives out best practice guidelines that will help you organize your code efficiently.


5.4.1. Packages and classes

Before reading this section, you might want to read the tutorial Packages where I discuss package naming conventions.

A package defines a general purpose. For example, suppose that this website uses several classes to handle how users log in with a user name and password. It makes sense to put those classes in a package named com.javaperspective.tutorials.login and that package must only contain classes used in the login process. In fact, the key point is that classes should be logically grouped within packages, that is, a given package must only contain classes whose purpose is related to that of the package. If none of the existing packages is suitable for a new class, create a new package or create a sub package out of an existing package.

Every class should serve a single purpose. However, it's not always possible to have only single-purpose classes in an application and certain classes may have a limited set of purposes. Generally, if a class has two many methods, then it does too many different things. In that case, break up the class into smaller classes, each of which has its own purpose or limited set of purposes.


5.4.2. DAO layer

DAO stands for data access object. If your application uses JDBC to access a database, it is recommended to put all the code that interacts with the database in classes whose names end with the letters Dao. Those classes constitute the DAO layer. Basically, the classes belonging to the DAO layer provide methods that interact with the database without revealing their implementation. That way, if the data storage system changes (let's say you have switched to XML files to store the data), only the implementation of the DAO layer changes.

As an example, let's suppose that in order to handle how users log in to JavaPerspective.com, I'm using JDBC to access a table named Users containing all the registered users information in the columns NAME, PASSWORD, PRIVILEGE and ROLE. The code representation of a user is the class User shown below:

package com.javaperspective.tutorials.login;

public final class User {

   
private String name;
   
private String password;
   
private String privilege;
   
private String role;

   
public User(String name, String password, String privilege, String role){
         
this.name = name;
         
this.password = password;
         
this.privilege = privilege;
         
this.role = role;
   
}

   
public String getName() {
         
return name;
   
}
   
public String getPassword() {
         
return password;
   
}
   
public String getPrivilege() {
         
return privilege;
   
}
   
public String getRole() {
         
return role;
   
}

}

To handle users, I need a class named UserManager which provides at least the 3 following methods:Given that all these methods interact with the database, instead of implementing them in the class UserManager, I'm going to create a data access object named UserManagerDao in a sub package named com.javaperspective.tutorials.login.dao as follows:

package com.javaperspective.tutorials.login.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.javaperspective.tutorials.login.User;

public final class UserManagerDao {

   
public void addUser(String name, String password, String privilege, String role) {
         
Connection connection = null;
          PreparedStatement statement =
null;

         
try{
               
connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "dbaName", "dbaPassword");

                String st =
"INSERT INTO USERS (NAME, PASSWORD, PRIVILEGE, ROLE) VALUES (?, ?, ?, ?)";
                statement = connection.prepareStatement
(st);

                statement.setString
(1, name);
                statement.setString
(2, password);
                statement.setString
(3, privilege);
                statement.setString
(4, role);

                statement.executeUpdate
();
         
}
         
catch(SQLException e){
               
e.printStackTrace();
         
}
         
finally{
               
try{
                     
if(statement != null)
                           
statement.close();
                     
if(connection != null)
                           
connection.close();
               
}
               
catch(SQLException e){
                     
e.printStackTrace();
               
}
          }
    }
//addUser

   
public User loadUser(String name, String password) {
         
Connection connection = null;
          PreparedStatement statement =
null;

         
try{
               
connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "dbaName", "dbaPassword");
                statement = connection.prepareStatement
("SELECT * FROM USERS WHERE NAME = ? AND PASSWORD = ?");

                statement.setString
(1, name);
                statement.setString
(2, password);

                ResultSet rs = statement.executeQuery
();

               
if(rs.next())
                     
return new User(name, password, rs.getString("PRIVILEGE"), rs.getString("ROLE"));

               
return null;
         
}
         
catch(SQLException e){
               
e.printStackTrace();
               
return null;
         
}
         
finally{
               
try{
                     
if(statement != null)
                           
statement.close();
                     
if(connection != null)
                           
connection.close();
               
}
               
catch(SQLException e){
                     
e.printStackTrace();
               
}
          }
    }
//loadUser


   
public void removeUser(String name, String password) {
         
Connection connection = null;
          PreparedStatement statement =
null;

         
try{
               
connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "dbaName", "dbaPassword");

                String st =
"DELETE FROM USERS WHERE NAME = ? AND PASSWORD = ?";
                statement = connection.prepareStatement
(st);

                statement.setString
(1, name);
                statement.setString
(2, password);

                statement.executeUpdate
();
         
}
         
catch(SQLException e){
               
e.printStackTrace();
         
}
         
finally{
               
try{
                     
if(statement != null)
                           
statement.close();
                     
if(connection != null)
                           
connection.close();
               
}
               
catch(SQLException e){
                     
e.printStackTrace();
               
}
          }
    }
//removeUser

}

Here is the class UserManager belonging to the package com.javaperspective.tutorials.login:

package com.javaperspective.tutorials.login;

import com.javaperspective.tutorials.login.dao.UserManagerDao;

public final class UserManager {

   
private UserManagerDao userManagerDao = new UserManagerDao();

   
public void addUser(String name, String password, String privilege, String role) {
         
userManagerDao.addUser(name, password, privilege, role);
   
}

   
public User loadUser(String name, String password) {
         
return userManagerDao.loadUser(name, password);
   
}

   
public void removeUser(String name, String password) {
         
userManagerDao.removeUser(name, password);
   
}

   
// Possibly other methods that do not directly interact with the database
    // ...
    // ...

}



5.4.3. Class code organization tips

Class members must be declared from top to bottom in the following order:
  1. Constants
  2. Fields (variables)
  3. Constructors
  4. Methods
  5. Getters and setters
If there are several methods in a class (other than the constructors, getters and setters), they should be ordered in some way. Personally, I tend to arrange them in alphabetical order. Alternatively, you can group methods logically. What matters is that there should be some sort of ordering.

Avoid code duplication within the same class or across different classes. Duplicated code poses maintenance issues. If you duplicate code in two different locations, later on, you may well introduce modifications in one location and forget the other one.

You might have noticed that in the class UserManagerDao, at the end of each method (after the closing curly brace), I have added // followed by the name of the method. It is a recommended practice that helps locating the end of a long method when you scroll down the code.


5.4.4. Javadoc and comments

Although you may not always have the time to do so, you should systematically add javadoc when you declare classes and public methods in order to explain what they do. Additionally, you can add non-javadoc comments when necessary. If your code is well written (you have chosen names that speak for themselves for classes, fields, methods and local variables), then non-javadoc comments should be minimalistic. In fact, non-javadoc comments should only be added to explain what the code does not say.


You are here :  JavaPerspective.com  >   Advanced Tutorials  >   5. Best practice tips  >   5.4. Source code organization

Copyright © 2013 - 2016. JavaPerspective.com. All rights reserved.  ( Terms | Contact | About ) 
Java is a trademark of Oracle Corporation
Image 1 Image 2 Image 3 Image 4 Image 5 Image 6 Image 7