Pages

Showing posts with label Design Patterns. Show all posts
Showing posts with label Design Patterns. Show all posts

Monday, April 22, 2013

A Theorical Look into Object/Resource Pool Pattern




Definition:
Sometimes our software projects need costly object creations (database connections, socket connections, large graphical objects etc.). This cost may be about time and/or memory. Those objects may also be needed to be created frequently. At that moment, Object/Resource Pool pattern comes to help.

Object Pool pattern:
  • Reuses unused costly objects without re-creating those objects (e.g. books in a library).
  • May create objects eagerly before they are needed, to manage application performance.
  • May limit created number of objects to manage application performance and user access.

Working principle:
Object Pool Class Diagram
Client requests an object (Reusable) from object pool. Object pool has a list of predefined reusables and gives an available one from pool. For the client's point of view, given reusable is a new object but it is probably (object creation strategies will be told later) a pre-created object with a new object's field values. For the optimum performance, client should notify object pool when reusable is no longer needed. Just in case client doesn't notify, object pool may define a timeout for each created reusable. Object pool must also have a synchronization mechanism for reusable serving, especially on multithreaded or multiuser applications.

When to use/Trade offs:
If objects are not costly, object pool pattern should not be used because this pattern needs clients to inform object pool (brings extra code complexity) and object creation management code (synchronization of pool, object creation limitation strategy etc.). This extra management code also brings a little performance loss. If performance gain of reusable object usage is bigger than extra management code performance loss, and application must frequently create those reusable objects, object pool pattern is recommended to be used.

Implementation Strategies:
    Object pool limit:
  • If memory is limited and/or maximum number of clients are needed to be restricted, an object number limit value may be defined for object pool (limited pool).
  • If there is no restriction, limit value is not needed (unlimited pool).
  • If all object pool list is in use, new objects may be created (expanding pool) or client may be enforced to waiting (fixed pool).
   Eager/lazy creation:
  • If application startup is performed infrequently and startup time is not very important, object pool list objects may be created at the startup (eager ceration).
  • If no restrictions exist, no objects are needed to be created eagerly (lazy creation).
  • Some number of objects may be created eagerly, others may be created lazily according to the application parameters (mixed creation).
    Empty object pool strategy:
  • If object pool is expanding, create a new object and return it.
  • If object pool is not expanding, return null or enforce client to wait until an object is ready to be given.
    Synchronization strategy:
  • Object pool should have a synchronization mechanism for object serving. Otherwise, especially on multiuser systems, pooling system may fail.
    Unused object strategy:
  • Usage of the pool objects may be lower than expected in some cases. Object pool may have a pool object removing strategy (i.e. descreasing object limit) for increasing performance.
    Returning object strategy:
  • Clients should return pool objects back to the pool after their job is completed. But pool code can't control this and poor client code may return pool objects. For this situation, object pool may have a timer mechanism for given but unused pool objects.

According to the project requirements, some of those strategies or mixed versions should be selected and implemented for object pool. But "reusing available objects" principle is the key and can not be changed for any implementation strategy.

Example Implementations will exist on the next post.

Wednesday, February 20, 2013

Layers of a Standard Enterprise Application





In a standard enterprise application which has a database and graphical UI (web or desktop), there are some typical layers which constitute the application. In this article we will mention those layers and give some instructions about them. 

The general diagram is as below:


There are some important properties about that diagram: 
There are vertical and horizontal layers. Vertical layers may be thought as general application service libraries which can paralelly work on all horizontal layers and independent from each other. However, a horizontal layer's subject of interest is only its neighbour (top and bottom) horizontal layers, and they work sequentially from top-to-bottom and bottom-to-top. Lastly, user can only interact with topmost horizontal layer. 

Horizontal layers:

  • PresentationEvery enterprise application has a UI, in fact graphical UI. This UI can be web or desktop based, which doesn't matter. The rule is simple. UI takes user action and sends it to the controller. And at the end it shows result taken from controller to the user. UI can be implemented according to MVC, MVP, MVVM or another approach.
  • ControlHandles business logic of the application. Takes info from user and sends it to DB layer (DAO or ORM framework) and vice versa. Abstraction type of controller may vary (a separate control and business layers for example)  according to the application parameters or development patterns (MVC, MVP, MVVM, ...) but the main idea remains the same.
  • Data AccessDatabase handling layer of the application. It may contain entity definitions, ORM framework or DB connection codes having SQL sentences, according to the abstraction decision. Its role is getting data from controller, performing data operation on database and sending results again to controller (if result exists). Database independence is a very important plus for this layer, which brings flexibility.

Vertical layers:

  • SecuritySecurity is a general concept, which includes user authorization, user authentication, user role management, network or SQL injection attack prevention, data recovery etc but we grouped that items generally as "Security". Those issues must be handled for each horizontal layer if you want to have a fully secure software.
  • Logging: Logging is very important for maintenance and reporting in enterprise applications. An easily configurable, parameterized, readable, flexible and correctly implemented logging layer for all horizontal layers is very useful for both developers and users. 
  • i18ni18n (internationalization) brings multiple language support and user interface text changing capability without rebuilding code. It may also have localization property which can handle number, currency and date formatting. So i18n provides flexibility on applications and should not be ignored.
  • Exception Handling: Exception handling may also be included in "Security" or "Logging" layers. We should not use only general exception classes or absorb all exceptions if we want to develop a quality software. We sometimes need our special exception classes with their specific behaviours for better security, logging and application performance.

If you design an architecture which has that layer structure considering software quality factors (which are told here), you will probably have a successful enterprise software application.

Wednesday, February 6, 2013

10 Groups of Software Quality Factors That Should Always Be Remembered





Flexibility and Extensibility
Flexibility is the ability of software to add/modify/remove functionality without damaging current system. Extensibility is the ability of software to add functionality without damaging system, so it may be thought as a subset of flexibility. Those functionality changes may occur acoording to changing requirements, or an obligation if development process is one of the iterative methods. Change is inevitable in software development and so, this is one of the most important properties of quality software.

Maintainability and Readability:
Maintainability is a little similar with flexibility but it focuses on modifications about error corrections and minor function modifications, not major functional extensibilities. It can be supported with useful interface definitions, documentations and also self-documenting code and/or code documentation. The more correct and useful documentation exists, the more maintainability can be performed.

Performance and Efficiency:
Performance is mostly about response time of the software. This response time should be in acceptable intervals (e.g. max. a few seconds), and should not increase if transaction count increases. And also, resources are expensive. Efficiency must be supported with resource utilization. As an exaggerated example, ability of performing a simple function only by using a 32 processor machine or 1 TB disk space is not acceptable. Optimal source/performance ratio must be aimed. 

Scalability:
A scalable system responds user actions in an acceptable amount of time, even if load increases. Of course more hardware may be added for handling increasing user transaction, but the architecture should not change while doing this. This is called vertical scalability. Ability of running on multiple, increasing count of machines is multiple processing. If the software can perform that type of processing, this is called horizontal scalability. A preffered scalable system should suit both of these methods.

Availability, Robustness, Fault Tolerance and Reliability:
A robust software should not lose its availabilty even in most failure states. Even if some components are broken down, it may continue running. Besides, even if whole application crashes, it may recover itself using backup hardware and data with fault tolerance approaches. There should always be B and even C, D .. plans. Reliability also stands for the integrity and consistency of the software even under high load conditions. So it is relevant with availability and scalability. An unreliable system is also unscalable.

Usability and Accessability:
User interfaces are the only visible parts of software according to the viewpoint of user. So, simplicity, taking less time to complete a job, fast learnability etc. are very important in this case. The most well known principle for this property is KISS (Keep It Simple Stupid). Simple is always the best. A usable software should also support different accessibility types of control for people with disabilities.

Platform Compatibility and Portability:
A quality software should run on as much various platforms as it can. So, more people can make use of it. In different contexts we may mention different platforms, this may be OS platforms, browser types etc. And portability is about adapting software that can run on different platforms, for being more platform compatible. In this sense, portability is also related with flexibility.

Testability and Managability:
Quality software requires quality testing. Source code should be tested with the most coverage and with the most efficient testing methods. This can be performed by using encapsulation, interfaces, patterns, low coupling etc. techniques correctly. Besides testability, a qualified software should be manageable after deployment. It may be monitored for e.g. performance or data usage status, or may enable developer to configure system easily. Creating a successful logging system is another very important issue about managability.

Security:
Security is a very important issue on software development, especially for web or mobile based ones which may have millions of users with the ability of remote accessing to system. You should construct a security policy and apply it correctly by leaving no entry points. This may include authorization and authentication techniques, network attack protections, data encryption and so on. all possible types of security leaks should be considered, otherwise one day only one attack may crash your whole applicaion and whole company.

Functionality and Correctness:
Functionality (or correctness) is the conformity of the software with actual requirements and specifications. In fact this is the precendition attribute of an application, and maybe not a quality factor but we wanted to point that as the last quality factor, for taking attention: Quality factors are not meaningful when we are talking about unfunctional software. First, perform desired functionality and produce correct software, then apply quality factors on it. If you can perform both paralelly, it is the best.

Thursday, October 18, 2012

Best Must-Read Books for Software Engineers





Here are the CodeBuild selection of must-read software engineering books. Books are grouped according to their content with some description.

  • Reference Books
These Robert C. Martin and Gang of Four books are very fundamental OOP resources for every software engineer.

    
  • Coding Perfection
These Steve McConnell, Robert C. Martin and Joshua Bloch books are very helpful with increasing your coding skills.

      

  • Refactoring and Patterns
Refactoring and patterns are very important issues of OOP, which brings quality and maintainability. These Martin Fowler and Joshua Kerievsky books are maybe the best references about this issue.

          

  • Pragmatic Programming
Andrew Hunt's and David Thomas's "pragmatic" approach to programming brings very important viewpoints to software engineering.

     

  • Project Management
There are many project management books in the market but  Frederick P. Brooks Jr. and Tom DeMarco presents very impressive important viewpoints to project management.


     

Monday, June 25, 2012

20 Subjects Every Software Engineer Should Know





Here are the most important subjects for software engineering, with brief explanations:

1.Object oriented analysis & design: For better maintainability, reusability and faster development,  the most well accepted approach, shortly OOAD and its SOLID principals are very important for software engineering.

2.Software quality factors: Software engineering depends on some very important quality factors. Understanding and applying them is crucial.

3.Data structures & algorithms: Basic data structures like array, list, stack, tree, map, set etc. and useful algorithms are vital for software development. Their logical structure should be known.

4Big-O notation: Big-O notation indicates the performance of an algorithm/code section. Understanding it is very important for comparing performances. 

5.UML notation: UML is the universal and complete language for software design & analysis. If there is lack of UML in a development process, it feels there is no engineering.

6.Software processes and metrics: Software enginnering is not a random process. It requires a high level of systematic and some numbers to monitor those techniques. So, processes and metrics are essential.

7.Design patterns: Design patterns are standard and most effective solutions for specific problems. If you don't want to reinvent the wheel, you should learn them.

8.Operating systems basics: Learning OS basics is very important because all applications runs on it. By learning it, we can have better vision, viewpoints and performance for our applications.

9.Computer organization basics: All applications including OS requires a hardware for physical interaction. So, learning computer organization basics is vital again for better vision, viewpoints and performance.

10.Network basics: Network is related with computer organization, OS and the whole information transfer process. In any case we will face it while software development. So, it is important to learn network basics.

11.Requirement analysis: Requirement analysis is the starting point and one of the most important parts of software engineering. Performing it correctly and practically needs experience but it is very essential.

12.Software testing: Testing is another important part of software engineering. Unit testing, its best practices and techniques like black box, white box, mocking, TDD, integration testing etc. are subjects which must be known.

13.Dependency management: Library (JAR, DLL etc.) management, and widely known tools (Maven, Ant,  Ivy etc.) are essential for large projects. Otherwise, antipatterns like Jar Hell are inevitable.

14.Continuous integration: Continuous integration brings easiness and automaticity for testing large modules, components and also performs auto-versioning. Its aim and tools (like Hudson etc.) should be known.

15.ORM (Object relational mapping): ORM and its widely known implementation Hibernate framework is an important technique for mapping objects into database tables. It reduces code length and maintenance time.

16.DI (Dependency Injection): DI or IoC (Inversion of Control) and its widely known implementation Spring framework makes life easy for object creation and lifetime management on big enterprise applications.

17.Version controlling systems: VCS tools (SVN, TFS, CVS etc.) are very important by saving so much time for collaborative works and versioning. Their logical viewpoint and standard cammands should be known. 

18.Internationalization (i18n): i18n by extracting strings into external files is the best way of supporting multiple languages in our applications. Its practices on different IDEs and technologies must be known.

19.Architectural patterns: Understanding architectural design patterns (like MVC, MVP, MVVM etc.) is essential for producing a maintainable, clean, extendable and testable source code.

20.Writing clean code: Working code is not enough, it must be readable and maintainable also. So, code formatting and readable code development techniques are needed to be known and applied.

Wednesday, March 7, 2012

2 Implementations of "Chain of Responsibility" Pattern with Java







Chain of Responsibility design pattern is needed when a few processors should exist for performing an operation and a particular order should be defined for those processors. Also the changeability of the order of processors on runtime are important.

UML represantation of the pattern is as below:


Handler defines the general structure of processor objects. "HandleRequest" here is the abstract processor method. Handler also has a reference of its own type, which represents the next handler. For this a public "setNextHandler" method should be defined and exactly the handler is an abstract class. 
ConcreteHandler define different representations of processors. At last, Client is responsible with creating required handlers (processors) and define a chain order between them.

Generally two diffent implementation may exist for this pattern. Difference is related with the "location of the chain routing business logic". Chain routing business logic may be either in Handler abstract class or ConcreteHandler classes, or both of them. Sample of first two approaches will be given below:

1. "Handler" has chain routing business logic:

  1. public abstract class Processor {
  2.     protected Processor next;
  3.     protected int threshold;
  4.     public void setNextProcessor(Processor p) {
  5.         next = p;
  6.     }
  7.     public void process(String data, int value) {
  8.         if (value <= threshold) {
  9.             process(data);
  10.         }
  11.         if (next != null) {
  12.             next.message(data, threshold);
  13.         }
  14.     }
  15.     abstract protected void processData(String data);
  16. }
  17. public class ProcessorA extends Processor {
  18.    
  19.     public ProcessorA (int threshold) {
  20.         this.threshold = threshold;
  21.     }
  22.     protected void processData(String data) {
  23.         System.out.println("Processing with A: " + data);
  24.     }
  25. }
  26. public class ProcessorB extends Processor {
  27.    
  28.     public ProcessorB (int threshold) {
  29.         this.threshold = threshold;
  30.     }
  31.     protected void writeMessage(String data) {
  32.         System.err.println("Processing with B: " + data);
  33.     }
  34. }
  35. public class Client {
  36.     public static void main(String[] args) {
  37.         Processor p, p1, p2;
  38.         p1 = p = new ProcessorA(2);
  39.         p2 = new ProcessorB(1);
  40.         p1.setNextProcessor(p2);
  41.         // Handled by ProcessorA
  42.         p.process("data1", 2);
  43.         // Handled by ProcessorA and ProcessorB
  44.         p.process("data2", 1);
  45.     }
  46. }

2. "ConcreteHandler"s have chain routing business logic:

  1. public abstract class Processor {
  2.     protected Processor next;
  3.     protected int threshold;
  4.     public void setNextProcessor(Processor p) {
  5.         next = p;
  6.     }
  7.     abstract protected void processData(String data);
  8. }
  9. public class ProcessorA extends Processor {
  10.    
  11.     public ProcessorA (int threshold) {
  12.         this.threshold = threshold;
  13.     }
  14.     protected void processData(String data, int value) {
  15.         System.out.println("Processing with A: " + data);
  16.         if (value >= threshold && next != null) {
  17.             next.processData(data, value);
  18.         }
  19.     }
  20. }
  21. public class ProcessorB extends Processor {
  22.    
  23.     public ProcessorB (int threshold) {
  24.         this.threshold = threshold;
  25.     }
  26.     protected void processData(String data, int value) {
  27.         System.out.println("Processing with B: " + data);
  28.         if (value >= threshold && next != null) {
  29.             next.processData(data, value);
  30.         }
  31.     }
  32. }
  33. public class Client {
  34.     public static void main(String[] args) {
  35.         Processor p, p1, p2;
  36.         p1 = p = new ProcessorA(2);
  37.         p2 = new ProcessorB(1);
  38.         p1.setNextProcessor(p2);
  39.         // Handled by ProcessorA
  40.         p.processData("data1", 1);
  41.         // Handled by ProcessorA and ProcessorB
  42.         p.processData("data2", 2);
  43.     }
  44. }

Friday, October 7, 2011

A Quick Reference to the Spring 3 DI Bean Configuration





Spring 3 DI (dependency injection) functionality which placed in "Spring Core" is very important for managing objects (or "beans") in enterprise applications.


Here is a quick reference for bean configuration of Spring DI:
Spring Bean Configurations 





You can get a bean in application by

manual:
ApplicationContext context = new ClassPathApplicationContext(new String[] {“application-context.xml”})
ViewManager viewManager = (ViewManager)context.getBean(“viewManager”);

annotation:
@Autowired
ViewManager viewManager;




Tuesday, August 16, 2011

Software Architecture Antipatterns : Swiss Army Knife Interface




Swiss Army Knife Interface is an interface class which has excessive number of method definitions. Architect/designer may design this interface to use for every need of the software, but this is a wrong approach and an antipattern. More than one interface must be designed using some design approaches.
Of course, "excessive number of methods" is a too general statement. Although most developer think that a handful number of methods (e.g. 8-10)  and some studies show that some magic numbers (7 plus/minus 2) are mostly enough, we can't say the maximum number of methods precisely. 

First of all, you must think that this interface will be implemented by a class and if the number of methods is excessive, there will be plenty of empty method bodies in implementor class. But this situation still can't determine the number of interfaces and number of methods in an interface.

The answer is hidden in the OOP SOLID rules. Single Responsibility ("S") rule of SOLID says that "every object should have a single responsibility", and Interface Segregation ("I") rule of SOLID says that "different types of functionalities should be placed in different interfaces". If an interface have more than one types of functionalities or defines more than one responsibilities, implemening that interface is meaningless because implementer class will not suit SOLID rules by implementing that interface. 

More than one Swiss Army Knife Interface may also exist in a software. This means more than one problem exist and must be solved. 

For another viewpoint, you can take a look at our another post about interface segregation principle:


Wednesday, August 25, 2010

5 Implementations of Singleton Pattern




This article introduces singleton design pattern and its 5 implementation variations (with C#).

Problem
At most one instance of a class must be created in an application.
Solution
That class (singleton) is defined including its own instance, and the constructor must be private.
Implementations
1. Lazy initialization, non-thread safe: This is the classical version, bot it's not thread safe. If more than one thread attempts to access instance at the same time, more than one instance may be created.
public class Singleton {
    private static Singleton instance = null;
    public static Singleton Instance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
    private Singleton() {}
}

2. Non-lazy initialization, thread safe: This is the simplest thread safe version, but it does not support lazy initialization.
public class Singleton {
    private readonly static Singleton instance = new Singleton();
    public static Singleton Instance() {
        return instance;
    }
    private Singleton() {}
}

3. Lazy initialization, thread safe: This version supports both properties, but has  performance problems. Once a thread uses singleton instance, the others have to wait because of lock.
public class Singleton {
    private static Singleton instance = null;
    private static readonly object lockObj = new object();
    public static Singleton Instance() {
        lock (lockObj) {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    private Singleton() {}
}

4. Double-check locking: An improved version of the third solution. Two null controls prevent lock waits for most time, but not always. Also, it does not work properly for Java because of Java memory management approach.
public class Singleton {
    private static Singleton instance = null;
    private static object lockObj = new object();
    public static Singleton Instance() {
        if (instance == null) {
            lock (lockObj) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
    private Singleton() {}
}

5. Nested initialization: A nested class is used for lazy initialization. This version is also thread safe, but a bit complex. For most situations, solutions 2 or 4 will be suitable according to performance parameters.
public class Singleton {
    public static Singleton Instance() {
         return Nested.instance;
    }
    private Singleton() {}

    class Nested {
        static Nested() {}
        internal static readonly Singleton instance = new Singleton()
    }
}

Usage: 
public static void Main(string[] args)
{
    Singleton instance = Singleton.Instance();
}