Carreira Dev

2 dez, 2010

Certificação SCJD – Parte 04

Publicidade

Neste último artigo sobre SCJD, quero finalizar apresentando meu arquivo de decisões arquiteturais, com o qual fui aprovado quando prestei a prova. Vale a pena lembrar que as opções abaixo foram por mim decididas mediante os requisitos e as circunstâncias do meu projeto, não sendo aplicáveis para qualquer outro. O meu objetivo aqui é mostrar para os candidatos interessados um exemplo modelo para que seja usado como “template” – ponto de partida. Outra coisa importante é que as decisões documentadas podem de alguma forma ajudar ou oferecer um “norte” para que os candidatos possam fazer as suas em seus projetos. Volto a dizer que essa foi uma das provas para a qual eu mais tive que estudar, mas que também foi na que eu mais aprendi.

Continuo à disposição para qualquer eventual ajuda.

Design

Architecture

I decided to use 3-layer (GUI->BUSSINES->PESISTENCE->FILE.db) instead of 2-Layer (GUI->PERSISTENCE->FILE.db).

I decided to create a bussines layer between gui and persistence layer because:Loosely coupled Avoid coupling of the details of persistence in the gui layer.

  1. Centralization and encapsulation of business rules.
  2. Code reuse facilitates the addition of different types of client such as a web application.
  3. Independence between layers.
  4. Maintainable and extensible.
  5. Transparency in data access.
  6. Deploy between different host.

Implementation

  • The suncertify.db package implements persistence layer.
  • The suncertify.bussines package defines polymorphically bussines layer.
  • The suncertify.local implements local bussines layer.
  • The suncertify.remote implements remote bussines layer.
  • The suncertify.view implements view layer.

Designer Patterns

The following patterns were used:

  1. suncertify.db.Data implemented Singleton.
  2. suncertify.remote.RemoteRoomServiceImp implemented Adapter.
  3. suncertify.bussines.Room implemented Transfer Object.
  4. suncertify.remote.ServiceFactoryImp implemented Factory.
  5. suncertify.view.ConnectionWindow implemented Template Method.

Exception Handling

I decided to create and use object exceptions approach instead of return error codes because:

  1. Robust code.
  2. Separate the error handling from the application logic.
  3. Exceptional conditions can not be ignored because there must always be a catch handler.
  4. OOP approach Treated as an object encapsulating all the necessary information.
  5. Decreases the complexity.

I created an exception for each layer that was used to isolate the occurrences of exceptional conditions:

  • *Persistence Layer: suncertify.db.DataBaseException.
  • *Bussines Layer: suncertify.bussines.BussinesException.
  • *View Layer: suncertify.view.ViewException.

Server

Network RMI vs. Socket

I decided to use RMI because:

  1. Transparency and usability – communication mechanism is completely hidden by technology.
  2. Object based semantic – remote objects look and feel just like local objects.
  3. Protocol – there is no need to worry about designing protocol between client and server.
  4. I did not want implement any mechanisms for remote communication.

Database File Selection

I chose not to let the user choose or change the database file when connected remotely because:

  1. The assignment did not mention any requirement on the subject.
  2. Avoid increase the complexity of the code unnecessarily.

Shutdown Hook

I decided to implement shutdown hook with Runtime.getRuntime().addShutdownHook() because:

  1. Close the database file properly when the application is closed.

Persistence Layer

File Acess

I decided to implement database handler with just 2 classes:

  1. suncertify.db.Data implements mandatory interface and manages access to the file.
  2. suncertify.db.RecordManager utility class that encapsulates all details about the database schema.

I decided to use RandowAcessFile instead of separate DataInputStream and DataOuputStream classes because alow (it alows?) randow acess to file.

Hard-Code Database Schema

I decided to use hard-code database schema instead of dynamically load because:

  1. The assignment did not mention any requirement on the subject.
  2. The assignemnt did not mention the possibility of having other types of database files.
  3. Avoid increase the complexity of the code unnecessarily.

No Cache

I decided to always read the records directly from the database file instead of using cache approach because:

  1. The assignment did not mention any performance requirement.
  2. Easy understanding for junior programmers.
  3. Avoid increase the complexity of the code unnecessarily.

Database Exception

I decided to throw a RuntimeException (suncertify.db.DataBaseException) instead of encapsulate the errors occurred in the exceptions defined by the mandatory interface because:

  1. There were errors that made no sense to throw the exception defined by the mandatory interface.
  2. It was not possible to add new exceptions in the mandatory interface.

Magic Cookie

I decided to validate the magic cookie preventing the user  to enter an invalid database file.

The validation implemented was hard-code instead of dynamically because:

  1. The assignment did not mention any requirement on the subject.
  2. The assignemnt did not mention the possibility of having other types of database files.
  3. Avoid increase the complexity of the code unnecessarily.

Primary Key

I decided to use the file position as primary key because:

  1. The assignment did not mention any requirement on the subject.

I decided not to reuse the deleted primary key because:

  1. The assignment did not say it was mandatory.
  2. I decided not to make delete operation for the application.
  3. Avoid increase the complexity of the code unnecessarily.

Never Throw DuplicateKeyException

DuplicateKeyException defined in the createRecord(String[] data) method (mandatory interface) will not be thrown resulting from the choice not to reuse the deleted primary keys.

Create Record, Update Record and Delete Record Methods

  • I decided not to implement any validation in the fields.
  • I decided to fill white space fields with size less than that defined in the database schema.
  • I decided to ignore the character of the fields that far exceeded the maximum size defined in the database schema.

Reasons:

  1. The assignment did not mention any requirement on the subject.
  2. I decided not to make these operations for the application.
  3. I decided to implement blocking mechanisms properly as required in the assignment.
  4. I only supply basic implementation for these methods due to mandatory interface.

Find By Criteria Method

I decided to use 2 ‘for’ statement and String.startsWith() method instead of regular expression because:

  1. Easy implementation.
  2. Easy understanding for junior programmers.
  3. Avoid increase the complexity of the code.

Lock

I decided to use synchronized methods, Object.notifyAll() and singleton patter approach instead of java.util.concurrent API because:

  1. The assignment did not mention any performance requirement.
  2. Easy implementation.
  3. Easy understanding for junior programmers.
  4. Avoid increase the complexity of the code.

Lock Owner

I used the cookie approach to identify the lock owner because:

  1. It was specified in the mandatory interface.

Lock Cookie

I decided to use System.nanoTime() to generate lock cookie because:

  1. Simple and easy.
  2. Secure enough to distinguish one client from the others.

Error Message

I decided to separate all the error messages in a specific class (suncertify.db.PersitenceMessages) because:

  1. Facilitate maintenance.
  2. Facilitate future translations.
  3. I18N simple mechanism that does not increase the complexity of the code.

Singleton Patter

I decided to use the singleton pattern in database management class because:

  1. Ensure the creation of only one instance.
  2. Properly implement the lock control.

Businnes Layer

Bussines Exceptions

I decided to create a base exception class that represents all the errors occurred within the layer instead of creating several different classes because:

  1. Isolate and hide details of the errors internally occurred.
  2. Define a communication error protocol based on layer.
  3. Avoid creating many exceptions classes.

Error Message

I decided to separate all the error messages in a specific class (suncertify.local.BussinesMessages) because:

  1. Facilitate maintenance.
  2. Facilitate future translations.
  3. I18N simple mechanism that does not increase the complexity of the code.

Tranfer Object Patter

I decided to use the transfer object patter creating a class that wraps the fields of a room instead of using array of String in the signature of the methods.

Reasons:

  1. Make a code easier to read.
  2. Easy understanding for junior programmers.
  3. Improve performance when used in remote mode.

Bussines Methods

I decided not to provide methods to insert, update, delete and unbook because:

  1. The assignment did not say it was mandatory.
  2. Avoid unnecessary increase in code.

I decided to provide the following methods:

  1. getRooms get all rooms.
  2. search search room using criteria.
  3. book book a room.

I decided to make two separate search methods instead of one because:

  1. Make code easier to read.
  2. Easy understanding for junior programmers.
  3. OOP principles override over logic.

I decided to implement the AND criteria logic within the business layer instead of the view layer because:

  1. Avoid coupling of the details of criteria logic in the gui layer.
  2. Reuse in different types client such as a web application.

I decided to implement the OR and AND criteria logic with just one method, using an criteria object instead of two separated methods because:

  1. In this case, it made no sense, in my opinion, to separate and use overload because I see the search operation with OR/AND as being an unique operation.

Book Method

I decided to implement a validation that checks the availability of the room avoiding:

  1. Book override.
  2. Data inconsistencies.
  3. This is a business rule and should stay within the business layer.

48 Hours Rule

I decided not to implement anything about the “48 Hours Rule” because:

  1. The assignment did not say it was mandatory.
  2. Avoid increase the complexity of the code unnecessarily.

Adapter Patter

I decided to use the adapter pattern in remote service implementation because:

  1. Create a level of separation from the networking approach and application logic.
  2. Decouple implementation details of the RMI technology from the of application logic.
  3. Code reuse.

Factory Patter

I decided to use the factory pattern in remote service implementation because:

  1. Ensure that each remote client connected to the RMI server does not share the same business object.
  2. Proper identifier mechanism for lock owner.
  3. Reduce the number of remote objects that need be registered.

View Layer

GUI Texts and Error Messages

I decided to separate all the error messages in a specific class (suncertify.view.ViewMessages).

I decided to separate all the GUI texts titles, labels, mnemonics and tool tips in a specific class (suncertify.view.ViewTexts).

Reasons:

  1. Facilitate maintenance.
  2. Facilitate future translations.
  3. I18N simple mechanism that does not increase the complexity of the code.

Template Method Patter

I decided to use the template method pattern in a GUI super-class because:

  1. Define general skeleton of an algorithm in an operation, deferring some steps to be defined in sub-classes.
  2. Code reuse.

No MVC Patter

I decided not to use the MVC pattern in GUI constructions because:

  1. The assignment did not mention any requirement about display data throught multiples sources.
  2. In my opinion, it is an overhead to use the MVC and create all the necessary classes in so few GUI operations.
  3. Avoid increase the complexity of the code.
  4. The bussines layer encapsulates rules that can be reused in different types of clients, such as a web application.

No Background Threads

I decided not to use background threads to deal with the user events, leaving everything to be queued on the event dispatch thread because:

  1. The assignment did not mention any requirement on the subject.
  2. In my opinion, there is no operation currently available that needs to be executed in another thread.
  3. In my opinion, with current available operations, the user can not do anything in the system while performing some action. This may change depending on new business operations added.
  4. Avoid increase the complexity of the code unnecessarily.

Look And Feel

I decided only used default java 6 look and feel because:

  1. The assignment did not mention any requirement on the subjects.
  2. Avoid unnecessary increase in code.

Layout Managers

I decided to use the following layout managers:

  1. Default BorderLayout.
  2. FlowLayout.
  3. GridBagLayout.

Reasons:

  1. The assignment did not mention any requirement on the subjects.
  2. They were the ones I felt that fit better in the construction of graphical user interfaces.

Input Mask

I decided not to use any input mask, leaving the user type everything because:

  1. The assignment did not say it was mandatory.
  2. I decided to centralize the implementations of all fields validations in their relevant layer.
  3. Code reuse.

List Room GUI Startup

I decided not to load all the rooms in the presentation of the main GUI because:

  1. The assignment did not mention any requirement on the subject.
  2. Leave that decision to the user to load all the rooms or filter using some criteria.

Others GUI Functions

I decided not to provide insert, update, delete and unbook GUI functions because:

  1. The assignment did not say it was mandatory.
  2. I decided not to implement these operations in the business layer.
  3. Avoid unnecessary increase in code.

General

I decided not to implement anything that would solve the following situations:

  1. Lost locks.
  2. Dead lock.
  3. General lock on the database during the shutdown.
  4. Client crashes.
  5. Sorting columns.
  6. Paging data.
  7. Notify view layer about nonrepeatable read.

Reasons:

  1. The assignment did not mention any requirement on the subjects.
  2. Avoid increase the complexity of the code.

No Log

I decided not to use log because:

  1. The assignment did not say it was mandatory.
  2. Avoid unnecessary increase in code.

Design

No Code Comments

I decided not to write any code comments because:

  1. In my opinion, there was no awkward or complex code that needed it.