implementation

Production Best Practices

A programmer should not expose resources within a REST initiative in a “bottom-up” ad hoc manner. Bottom-up development is inherently driven by immediate project needs. For example, how you solve a specific problem with a specific implementation (often driven by the influence of existing applications and associated behaviors masquerading as true business requirements).

What happens when an organization defines and implements REST with the mindset described? The REST implementation simply becomes layered with more spaghetti code of a different form that does not improve business process flexibility. Consequently, a monolithic application in a different technology is implemented often with disappointing results.

To achieve success, a programmer should not define REST in a “top-down” manner. Top-down business process analysis can lead to either “analysis paralysis” – continual refinement of a model hoping to reach perfection (which never comes), or “Big-Bang” projects – trying to define and implement everything at once. Either approach usually creates disastrous consequences (a combination of “death march” projects, and cost, and schedule overruns).

What do organizations need to make progress? A coarse-grained business model driven by key business processes. Not all key business processes may apply but definitely a representative set of high-priority processes to start. Architects and business analysts should collaborate to build an applicable model by extracting key business processes to define a normalized set of functions. Next, group functions together based on behavioral affinity as a straw-man set of initial, target resource definitions.

Resultantly, we have a useful framework for the “real work” – detailed analysis, design, and REST implementation needed for our current set of prioritized projects. Based on business process (and project) prioritization, we identify the needed resources from our business reference model and formalize the definition for the prioritized resources. Ideally, each resource should be driven by requirements extracted from at least two separate processes. Designing a REST resource based on a single use case may result in a fragile, and narrowly defined implementation lacking the flexibility necessary to meet the next set of prioritized projects. Formalization efforts are likely to result in modifications to business architecture – which is fine! We can iteratively enhance the architecture as progress is made towards a successful REST implementation.

Booker Showers

Cloneable Interface Design

A cloneable interface design often requires a clear separation between a type and its implementation. Often it is unavoidable to provide a public clone() operation for such a type when the type is used as part of the state of an object.  A cloneable interface design relies on the following factors:

Cloneable Interface Design Forces and Facts

  1. Accessor methods in Java should return a copy of internal state variables instead of references to the internal variables – in order to maintain an object’s integrity
  2. When values given to constructors are to become part of the state of an Object and should be copied instead of just referenced.
  3. There are no constructors available in an interface declaration, so a “copy constructor” cannot be declared.
  4. The visibility of a clone() method needs to be public to allow arbitrary client classes to clone the object

Example of Problem:

public interface State {
//
// some operations
//
}

public class C { public C (State s) { 
state = new State(s); 
state = s; 
}

public State getState() { 
return state; 
}

protected State state; 
}

Solution:

public interface State extends java.lang.Cloneable {
        //
        // some operations
        //
public Object clone();
}

public class C { public C(State s) { 
state = (State)s.clone(); 
}

public State getState() { 
return (State)state.clone(); 
}

protected State state; 
}

Booker Showers
Rhythm Section

The Rhythm Section (Frameworks)

 

Intention

Getting applications up and running in the shortest amount of time is critical these days.  This involved reducing the learning curve and implementing many concrete and final classes.  The following paragraphs examine the importance of framework design.

Frameworks

Frameworks reuse both design and code. Aspects of a design, such as the kinds of objects, are easily described by code. Other aspects are not described well by code, such as invariants maintained by objects in an ensemble. The fact that aspects of a framework are not expressed well as code makes frameworks harder to understand than abstract classes. A design must emphasize its details of a at the expense of others. A framework concentrates on describing object that make up the program and how they interact.

Dataflow is de-emphasized, but the communication between object is emphasized. Since frameworks provide abstract algorithms, users of a framework usually ignore the details of these algorithms and concentrate on designing and combining objects. The concept of a framework is harder to understand than that of an abstract class. Abstract classes can be defined either by how to recognize them or how to use them. Unfortunately, there is no simple way to tell whether a set of classes is a framework, so frameworks tend to be defined on how they are used.

The important classes in a framework, such as of Model/View/Controller, are usually abstract. Like Model/View/Controller, a framework usually comes with certain concrete subclasses of the classes in the framework. No component library is perfect to derive new concrete subclasses of the abstract classes in the framework. A good component library is valuable in addition to the framework, the essence of a framework is not the component library, but the model of interaction and control flow among the objects.

Frameworks are informally defined early as a set of objects and how they interact. Most the object ­oriented frameworks are specified by informal documentation and a set of (usually) abstract classes that represent the objects. The classes give the operational specification of how objects in the framework work together.

Given a specification language for describing the behavior of a set of objects, a framework would be a function from the set to constrain the behavior. For example, the Model/View/Controller framework would be a function from the three objects in a MVC trio: the view has a function from the state of the model to an image to invariants like the image on the screen inside a view’s bounding box is its function applied to the state of the model, and to operation sequences like whenever the controller changes the state of the model, it performs the operation on the view, which will redraw the screen. Note that a framework can define both the invariant and the outline of the algorithm.

Frameworks rely on undefined properties of the objects, such as the function from the state of the model to the image. A framework is filled out by selecting objects according to how they define these properties. The objects in a framework often place additional constraints on each other. Views (controllers) often use specialized operations to read (change) the state of a model. The major problem with expressing frameworks in a programming language is that it is hard to learn the constraints that the framework imposes on a program. The major advantage of expressing a framework as a program is that the algorithms and data structure of the program are automatically reused by every instantiation of the framework. There is usually an abstract class for each component in the framework. The algorithms and data structures that are reused are usually defined by these abstract classes. Each subclass of the abstract class defines a kind of component that fits into the framework, and they inherit much of their implementation from their abstract superclasses. This makes it easier to develop a library of components that can be mixed and matched within a framework.

A framework would be described both operationally and in terms of the constraints that it places on its components. This would not only provide code reuse, but make it easier to learn how objects in the framework interact. A framework reuses analysis, design, and code. It reuses analysis because it describes the kinds of objects that are important and how a large problem should be broken down into smaller problems. It reuses design because it contains abstract algorithms and describes the component interfaces that the programmer must implement and the constraints that any implementation must satisfy. It reuses code because it makes it easy to develop a library of compatible components and because the implementation of a new component can inherit most of its implementation from an abstract superclass. All of these are important, though in the long run it is probably the analysis and design reuse that provide the biggest payoff.

A framework hides the parts of the design that are common to all instances, and makes explicit the pieces that need to be customized.

A framework is most valuable when the part of the design that is hidden is the part that programmers find hardest to understand.

A class that is not abstract is concrete. In general, it is better to inherit from an abstract class than from a concrete class. A concrete class must provide a definition for its data representation, and some subclasses will need a different representation. Since an abstract class does not have to provide a data representation, future subclasses can use any representation without fear of conflicting with the one that they inherited. Creating new abstract classes is very important, but is not easy. It is always easier to reuse a nicely packaged abstraction than to invent it.

A programmer usually tries to create a new class by making it a subclass of existing class, since this is less work than creating a class from scratch. This can result in a class hierarchy whose top­most class is concrete. The top of a large class hierarchy should almost always be an abstract class. As a programmer gains experience, they will then try to reorganize the class hierarchy and find the abstract class hidden in a concrete class. The result will be a new abstract class that can be reused many times in the future.

An example of a class that needs to be reorganized is View, which defines a user interface object that controls a region of the screen. A view might have many subclasses, but is concrete. A careful examination will reveal a number of assumptions made in a view that most of its subclasses do not use. The most important is that each view will have subviews. In fact, most subclasses of a view implement views that can never have subviews. Quite a bit of code in a view deals with adding and positioning subviews, making it very difficult for a beginning programmer to understand the key abstractions that a view represents. The solution is simple: split View into two classes, one (view) of which is the abstract superclass and the other (view WithSubview) of which is a concrete subclass that implements the ability to have subviews. The result is much easier to understand and to reuse.

http://wp.me/p2MYVz-3m

Booker Showers