Wiki

Clone wiki

ipo / Home

I.P.O. library for Java

Context

In medium to large sized projects, the bigger the number of developers working on a project and the more they expand it, the less overall consistency it will have inside the parameters within which people are allowed to operate - i.e. automatic checks and enforced architectural constraints will still allow a certain amount of freedom which, given enough time and project expansion, will lead to a decay of (subjective) consistency. Conversely, the cost of maintaining consistency rises.

This loss of (subjective) consistency refers to patterns breaking down, architectures being eroded and increases in code complexity. Patterns and architectures can slowly but surely fade, intentionally or not, by:

  • breaking encapsulation and exposing fields / methods / classes
  • excessively growing the number of parameters within methods and the number of methods within classes
  • chaotically expanding dependency hierarchies
  • overusing APIs with no (or weak) compile-time type-checking such as reflection
  • etc..

Genesis

In this context, i have sought inspiration in the number one source of consistency in the universe - the universe itself - in the attempt to create a high-efficiency, low-cost and simple modus operandi which enforces itself from high-level architecture to low-level implementation and vice-versa. As i try to suggest below

consistency.png

there are several key aspects retaining consistency from micro-cosmos to macro-cosmos:

  • small objects are in orbit around big objects
  • gravity acts at all levels
  • simple objects connected by gravity form complex objects

These complex objects are configurations "found" by the universe to obey the laws of physics in a certain context. This process is consistent and constant, starting from the smallest perceivable building blocks, e.g. electrons, protons..

Consider the following chain of events:

  • an electron enters the range of a proton
  • the electromagnetic force holds the electron around the proton
  • the (Hydrogen) atom is born
  • this process solves the electrical imbalance of the proton's +1 and the electron's -1 electrical charges which cancel each other out in an atom

Therefore one could generically infer this process is a solution to a problem specified by an input, which i will attempt to prove by analogy below.

Systems Theory

If there is a conceptual bridge from universal forces to software engineering it will undoubtedly stem from systems theory. To match universal building blocks with systems theory building blocks was a trivial challenge thanks to the IPO model (Input-Process-Output) which can be matched, actor by actor, with the proton-electron (planet-moon, star-planet, galaxy-star) interaction.

ipo.png

  • user = proton
  • process = electromagnetic force / gravity
  • input = electron
  • output = atom

By definition, any problem can be solved by applying the IPO model at the highest level: a problem represents a need to implement a process that will take a certain (usually undesired) input and will produce (a usually welcome) output. Implementations usually exhibit an implicit fractal quality. This happens extensively in programming: methods (which take parameters and return values) within methods within methods... By applying the IPO model to the implementation itself this fractal quality becomes explicit. For example, an implementation of an algorithm could look like this:

fractal.png

The Java object model exhibits this fractal consistency and method level programming is the clearest application of IPO modelling.. However, the two qualities seem to meet with greater than expected difficulty especially in these fast paced times, which is the reason why this IPO library was born.

Proposed advantages

1. A robust IPO framework for Java

2. Solid type-checking

3. Increased consistency and modularity

4. Extraction of widely used patterns and operations into readily implemented processes for easier reuse

5. Intuitive IPO alternative to the ubiquitous (arguably inverted) OPI or PIO models

i.e. A method call usually looks like method(parameters), hence the PI in OPI/PIO

The IPO model implemented by this library proposes fluent code such as:

// asserts the output value is equal to 8
Input.from(64.0).to(sqrt).assertEquals(8.0);

// produces the square root and then prints it
Input.from(64.0).to(sqrt, Process.PRINT);

// filters out and prints palindromes
Input.from("bla", "like", "ahaha").to(palindromeFilter, Process.PRINT);

// takes the current time from the internet and prints the response
Input.from("http://currentmillis.com/time/minutes-since-unix-epoch.php").to(Process.REQUEST, Process.PRINT);

6. Object-Oriented alternative to Aspect-Oriented Programming

Input<String> url = new Input<String>("https://currentmillis.com/time/minutes-since-unix-epoch.php") {

    @Override
    protected void onStart(Process<?, ?> process, boolean isFirstProcess, Object inputValue) {
        // TODO Auto-generated method stub
    }

    @Override
    protected void onEnd(Process<?, ?> process, boolean isLastProcess, Object inputValue, Object outputValue) {
        // TODO Auto-generated method stub
    }

    @Override
    protected void onThrow(Process<?, ?> process, Throwable throwable) {
        // TODO Auto-generated method stub
    }
};

7. Monitoring-ready

Input<String> url = new MonitoredInput<String>("https://currentmillis.com/time/minutes-since-unix-epoch.php") {
    @Override
    protected void onMonitoredEnd(Process<?, ?> process, boolean isFirstProcess, boolean isLastProcess, long inputCreationTime, long processStartTime, long outputCreationTime) {
        System.out.println(process + " finished after " + (outputCreationTime - processStartTime) + "ms");
    }
};
url.to(Process.REQUEST, Process.PRINT); 

8. Self-enforcing pattern

The ouptut of a process wraps and encapsulates the actual (private) output value which means it can only be read by another process. Here is a simplified UML diagram:

IPO library pattern.png

Examples

Filter<String> palindromeFilter = new Filter<String>() {
    @Override
    protected boolean accept(String string) {
        for (int i = 0; i < string.length() / 2; i++) {
            if (string.charAt(i) != string.charAt(string.length() - i - 1)) {
                return false;
            }
        }
        return true;
    }
};

// One way to do it
String[] array = { "bla", "aha", "yes", "apapa" };
Input.from(array).to(palindromeFilter).to(Process.PRINT);

// Another way to do it
Input.from("bla", "aha", "ahaha").to(palindromeFilter, Process.PRINT);

Getting started

References

Useful links

Updated