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

Tuesday, 18 August 2015

Thoughts on Architecture and Software Design

To be honest and fair, these are not my thoughts but great principles I have learnt in my programming career. Its a unassorted list of references that I keep going back to, when discussing architectural concepts with development teams. Penning it here as my own reference.

Service Oriented Design

Services are the building blocks of architecture. They need to be simple, self contained and designed for re-use; right from the start. Application features expose their data and functionality through service interfaces. Services communicate with each other only through the interface over the network (Http / Messaging). No other communication allowed - binary dependency, direct data store access, shared memory model and all other backdoor access should be disallowed. All services should be designed to be externalizable.

Design Paradigms

API Driven - Abstraction is the key component of providing an integrated service offering. Applications needs to be built on top of a rich API which assists down the line with integration with downstream and upstream systems and implementations can be changed without impact.
Scalable - Applications should be decomposed into small, loosely coupled, stateless building blocks that can be scaled independently. Architecture should always bear cost in mind and allow business levers to scale both horizontally and vertically as necessary.
Adaptive - Dont make applications more complicated than they should ever be. Follow the KISS principle. Look for Apple product design guidelines as an inspiration to make things as intuitive as possible.
Resilient - Protecting your organization's / customer's data is the first priority for applications. Applications must be able to absorb individual failures and provide a seamless degradation of service based on availability. Don't treat failure as an exception but as an event of regular happening.
Secure - Integrating security into applications should be a ground-up activity and not an afterthought. Enterprise level of authentication, access-controls and data encryption should be applied from basic design.

Continuous Delivery

Principles vs Practices - Best practices are subjective and depend largely on context, while principles are eternal and universal. The delivery lifecycle should be based on fundamental 'agile manifesto' rather than beating around on specific development practices. - http://simpleprogrammer.com/2013/02/17/principles-are-timeless-best-practices-are-fads/
Continuous business value vs Time-boxed iterations - The delivery should be based on providing continuous business value in the form of small functional releases rather than arbitrary time boxes. - http://kief.com/iterations-considered-harmful.html
Measurements and analytics - You really have to treat the software development process more like a relationship than like a factory. Instead of focussing on measurements and metrics, the emphasis should be given to trends and variance of the development lifecycle. - http://simpleprogrammer.com/2013/02/11/we-cant-measure-anything-in-software-development/
Philosophy on Estimations - The key is that you first accept that making accurate long-term estimates is fundamentally impossible. - http://blog.hut8labs.com/coding-fast-and-slow.html

Tuesday, 15 December 2009

Builder Pattern Abused

Everyone has read Joshua Bloch's builder pattern, which he has also described at his "Effective Java Reloaded" sessions at Javaone. However in this post, I am going to describe a misuse of this pattern, when used in conjunction with inheritance. 
When building a relational model, the biggest challenge is to maintain the integrity of inheritance and reduce the visibility of the properties completely. However if you need builders for this model, then you either have to create a class hierarchy of builders similar to the model itself or make all accesses protected (ugly #1) so that builders could appropriately initialize them. Making the properties less visible has at least two disadvantages though (1) you cannot make them final and ensure construction safe and (2) you'll end up copying the builders to more than one class (ugly #2) I recently came across a horrendous implementation of the hierarchy of builders where the author could not solve the above issues elegantly. So he had resorted to creating copy constructors (ugly #3) for the builders and also duplicating the methods for each of the builders. The following code snippet exactly reproduces the code, in an example class hierarchy and its builders.
abstract class Shape {
    private String name;
    private Dimension dimension;

    public enum Dimension {
        TWO_D, THREE_D;
    }

    public static abstract class ShapeBuilder {
        private String name;
        private Dimension dimension;

        protected ShapeBuilder copyOf(ShapeBuilder builder) {
            ShapeBuilder copy = createBuilder();
            copy.name = builder.name;
            copy.dimension = builder.dimension;
            return copy;
        }
        public ShapeBuilder name(String name) {
            ShapeBuilder bldr = copyOf(this);
            bldr.name = name;
            return bldr;
        }
        public ShapeBuilder dimension(Dimension dimension) {
            ShapeBuilder bldr = copyOf(this);
            bldr.dimension = dimension;
            return bldr;
        }
        public Shape build() {
            Shape s = createInstance();
            s.name = this.name;
            s.dimension = this.dimension;
            return s;
        }
        abstract Shape createInstance();
        abstract ShapeBuilder createBuilder();
    }
    // omitting getters for clarity
}
abstract class TwoDShape extends Shape {
    private double area;

    public static abstract class TwoDShapeBuilder extends ShapeBuilder {
        private double area;

        protected TwoDShapeBuilder copyOf(TwoDShapeBuilder builder) {
            TwoDShapeBuilder copy = (TwoDShapeBuilder) super.copyOf(builder);
            copy.area = this.area;
            return copy;
        }
        public TwoDShapeBuilder name(String name) {
            return (TwoDShapeBuilder) super.name(name);
        }
        public TwoDShapeBuilder dimension(Dimension dimension) {
            return (TwoDShapeBuilder) super.dimension(dimension);
        }
        public TwoDShapeBuilder area(double area) {
            TwoDShapeBuilder bldr = copyOf(this);
            bldr.area = area;
            return bldr;
        }
        public TwoDShape build() {
            TwoDShape s = (TwoDShape) super.build();
            s.area = this.area;
            return s;
        }
    }
}
class Circle extends TwoDShape {
    private double radius;

    public static class CircleBuilder extends TwoDShapeBuilder {
        private double radius;

        protected CircleBuilder copyOf(CircleBuilder builder) {
            CircleBuilder copy = (CircleBuilder) super.copyOf(builder);
            copy.radius = this.radius;
            return copy;
        }
        public CircleBuilder name(String name) {
            return (CircleBuilder) super.name(name);
        }
        public CircleBuilder dimension(Dimension dimension) {
            return (CircleBuilder) super.dimension(dimension);
        }
        public CircleBuilder area(double area) {
            return (CircleBuilder) super.area(area);
        }
        public CircleBuilder radius(double radius) {
            CircleBuilder bldr = copyOf(this);
            bldr.radius = radius;
            return bldr;
        }
        public Circle build() {
            Circle s = (Circle) super.build();
            s.radius = this.radius;
            return s;
        }
        @Override
        protected Shape createInstance() {
            return new Circle();
        }
        @Override
        protected ShapeBuilder createBuilder() {
            return new CircleBuilder();
        }
    }
}
abstract class ThreeDShape extends Shape {
    private double volume;
    // builder similar to 2DShape
}
class Cube extends ThreeDShape {
    private int side;
    // builder similar to Circle
}
Now extrapolate this class into an enterprise relational model consisting of 10-15 objects with nested hierarchies and you can imagine the amount of stupid code that's been written. If you haven't solved this problem yourself before, please stop here and think for a solution. The biggest issue here is, when you create a CircleBuilder and call the name() method, you are again expecting a CircleBuilder back and not a ShapeBuilder. Thankfully there is a generic implementation (partly under documented) which helps to solve problems of this nature. The modified code is given below
abstract class Shape {
    private String name;
    private Dimension dimension;

    public enum Dimension {
        TWO_D, THREE_D;
    }

    public static abstract class ShapeBuilder<S extends Shape, SB extends ShapeBuilder<S, SB>> {
        private String name;
        private Dimension dimension;

        @SuppressWarnings("unchecked")
        public SB name(String name) {
            this.name = name;
            return (SB) this;
        }
        @SuppressWarnings("unchecked")
        public SB dimension(Dimension dimension) {
            this.dimension = dimension;
            return (SB) this;
        }
        public T build() {
            T result = createInstance();
            result.name = this.name;
            result.dimension = this.dimension;
            return result;
        }
        abstract T createInstance();
    }
}
abstract class TwoDShape extends Shape {
    private double area;

    public static abstract class TwoDShapeBuilder<S extends TwoDShape, SB extends TwoDShapeBuilder<S, SB>>
            extends ShapeBuilder<T, SB> {
        private double area;

        @SuppressWarnings("unchecked")
        public SB area(double area) {
            this.area = area;
            return (SB) this;
        }
        public T build() {
            T result = (T) super.build();
            result.area = this.area;
            return result;
        }
    }
}
class Circle extends TwoDShape {
    private double radius;

    public static class CircleBuilder extends
            TwoDShapeBuilder<Circle, CircleBuilder> {
        private double radius;

        public CircleBuilder radius(double radius) {
            this.radius = radius;
            return this;
        }
        public Circle build() {
            Circle s = (Circle) super.build();
            s.radius = this.radius;
            return s;
        }
        @Override
        protected Circle createInstance() {
            return new Circle();
        }
    }
}
The only thing ugly about this code is that the builders themselves have to be cast to the generic implementation because of the type erasure. However this would be solved by the new "Type Inference" language feature that will be introduced in Java 7.