August 30, 2015

Why “creative” EE developers are bad for business



In this article, I’d like to address an issue I’ve met in most companies I worked for so far: It’s apparently a common anti-pattern for management to expect and encourage their top enterprise developers to come up with preferably “creative” solutions. Here, I’d like to show why I think adhering to “common” solutions is actually preferable.

What is “good” software?

“Good” software, i.e. software which is a valuable asset for the development company that creates it, will typically adhere to these two characteristics:
  • It fulfils the requirements imposed by the customer, both functional and non-funcional.
  • It is maintainable.
For typical enterprise application development / customer software development, the “maintainability” factor cannot be stressed enough. Experience shows that maintaining existing parts of a software system (changes, bugfixes, additions based on existing functionality) takes up more time over the lifespan of a product than adding completely new functionality. Leading opinions in the field of software development prove this.

So, as a thought experiment, is it better to create a nearly-perfect product but with diminished maintainability, or a highly maintainable product with diminished overall functionality? Of course, neither of these situations is ideal. However, in case of a high level of maintainability, you still have the possibility to change, to adapt. This is absolutely essential especially in typical custom software development where “development” spans over many months, is hardly ever finished or if you plan to support your product afterwards. Especially in the case of agile software development, maintainability is key to be able to adopt to changing requirements.

What is “maintainable” software?

High software maintainability can be achieved by:
  • Increasing source code readability: making it easy to find out what a piece of code does.
  • Increasing source code extensibility: making it easy to adapt existing software and extending it.
  • Providing good documentation
  • Providing good software tests
In this article, we focus on source code readability and extensibility aspects. There are many articles elsewhere on the Internet which go into more details about how to provide “good” documentation or tests.

Both source code readability and extensibility are facilitated by adhering to common best practices for the programming language and the environment in use, such as globally accepted source code conventions and well-known design patterns.

This is the actual “engineering” process in software engineering: Identifying a common pattern to find a specific solution for a concrete problem. The more generic the underlying idea is, the easier it is for any third person to later grasp the concrete adaptations of the solution applied to match the concrete problem.

What is a “good” solution?

A good solution is based on generally accepted best practices and well-known patterns, but adopted just enough to match the specific problem. It should solve the concrete problem, not more (“overengineering”), and not less.

A solution which is based on commonly accepted best practices is expected to be generally accepted as well, which is critical for any piece of software developed in a team. Even more important, though, is the aspect of distribution of knowledge: a solution which is commonly accepted and commonly known facilitates any aspect of software maintenance management because less specific documentation, training, or even design discussions are needed because we use what has already been taught on and agreed on by the team and even potential new members of the team.

To sum up, such a solution has these characteristics:
  • It requires no or little specific documentation or training as the underlying ideas are well-known.
  • It requires less research and testing as the underlying design / technology is proven to be robust and effective.
  • It diminishes the need for discussions and lessens the risk of conflicts within the team as the underlying pattern is generally accepted as a “best practice”.
  • It makes the software / project / company more independent on the individual engineers which develop the software because knowledge about the underlying ideas is (ideally globally) widespread. Depending on individuals is a huge risk no sane company should take.
Let me give you some examples of applying a “good” solution vs. applying a “bad” solution. (These are real life examples of what I’ve seen in practice.)

Library usage

Example: Creating a custom Java library e.g. for Date conversion vs. relying on an existing (3rd party) library like e.g. Joda time.

There’s a huge, undesirable shift of responsibility towards your project: By building a library from scratch, you (i.e. your development team) is responsible for accuracy (testing!) and documentation of the library all by itself. As the library is developed “in-house”, no potential new member of the team is expected to have any prior knowledge of the library, thus the need for training is increased.

Think about it: Apart from developing the actual business software, can you really effort to stem an additional project to build an entire utility library? Probably not. In this situation, you better rely on existing products, using them as “black boxes”, i.e. without worrying about their accuracy or other aspects: as long as they prove their correct functionality through tests, you can just rely on their team to make its job. Ideally, you could even find a library which offers business support.

Technology usage

Example: Creating a custom solution for “dynamic” web UI generation through “static” technology vs. relying on existing solutions like e.g. PrimeFaces Extensions DynaForm.

If you feel like you have to “bend” existing technology near the point of “breaking”, e.g. when code readability and (IDE) tool support is diminished, you’re most likely on the wrong way. It then typically helps to either search for help online, hoping that someone knows a neat solution to solve the problem more or less elegantly within the existing technology; otherwise, you should even consider breaking out of the existing technology and build a sub-system based on another mature technology / library.

Using technology in a way which seems clever at first sight, but for what it is clearly not designed will most likely quickly get out of hands as soon as more advanced requirements come up and the solution gets more complex. At that point in time, it shifts from creating a sub-system to creating your own library, as described above, but typically without ever having clearly separated technology and business aspects of the solution, making it very hard to test and maintain, and requiring specific knowledge of both the business aspects as well as the application of the solution itself in order to work with the code base.

Having built your own little “framework”, and especially if it’s brittle, is especially frustrating for new developers, unable to bring in their own experience with mature technology, but required to dive in into your custom solution which will most likely not stand the test of time anyway.

Middleware usage

Example: Creating a custom mini-rule engine vs. relying on an existing rule engine product like e.g. Drools.

Re-inventing the wheel is always a no-go in software engineering. If there’s a solution which matches your requirements, go for it. It’s tested, it’s documented, it’s efficient, and there’s potentially even professional support, maybe it’s even open source. Even if you feel like the solution exceeds what you actually need as functionality, you’re on the safe side: If requirements change or extend, they are still most likely covered by the 3rd party product. Everything which holds true for relying on existing libraries or technology applies here as well.

But what if there is no “good” solution available?

Experience shows that failing to find a mature solution to what seems to be a common issue typically shows a lack of proper research rather than lack of actually available solutions. A technology ecosystem such as JEE is a huge field, and your team is not expected to hold knowledge about every aspect and every 3rd party extension out there. In this situation, always search for external help first, either online or through professional consultants / trainers.

If you really find yourself in a situation where you feel like you have to come up with your own solution there’s a trick which seems counter-intuitive especially for commercial software development companies at first, but which may pay out in the long run: Develop your solution, decoupled from any “business-specific” aspect, and make it open-source, publishing it on the Internet. Some of the many advantages of this approach include:
  • You get (free) feedback from external developers
  • You may even receive (free) contributions from external developers
  • You spread knowledge about your solution across the general public
  • You may even receive acknowledgement and gain reputation for the fine piece of software developed at your company

What is a “good” developer?

A good developer will acknowledge the need to create “good” software and that it needs to fit the definition described above, or a similar definition.

I really like the idea of distinguishing between a “programmer” and a “software engineer”. The former is someone who writes code which really requires no specific abilities or education. The latter, however, will, just as described above, transform “generic solutions to match a specific problem” which typically requires profound knowledge of the given technical environment and abilities acquired by personal experience.

What is the job of a “lead developer”?

A “lead” or “senior developer” will be even more aware of how to achieve maintainable software. He will help design software based on common best practices and advocate use of general design patterns within the team.

His role has thus the following characteristics:
  • He takes a “leading” role, but without making the team or the software product dependent on him.
  • He brings in his knowledge and experience, and these qualities will shape the outcome of the software product.
  • He takes responsibility for the input and advice he provides to the team.
This definition of a “lead developer” role perfectly matches an agile team (e.g. in Scrum), where no single developer is in charge of any part of the solution, but decisions are made in the team, and responsibility is held by the team in its entirety.

According to this role definition, it’s not the lead developer’s job to come up with his own solution to specific problems. As discussed above, this would actually harm the project, at least in the long run. Rather, the lead developer will help the team identifying common best practices to transform them into a matching solution to the concrete problem.

Conclusions

Encouraging developers to come up with “creative”, non-standard solutions increases dependency on individuals while decreasing maintainability and the overall life expectancy of a software product.

Advocating common conventions, best practices and refusing to re-invent the wheel, in contrast, are essential virtues of a good software developer, and essential to a lead developer. A software project adhering to these rules is more likely to create maintainable software, which defines return of investment in the long run. Still, the “Not invented here” anti-pattern is, in my experience, quite wide-spread in software development. As long as lead software developers are judged by the number and quality of “inventions” they make in-house, this is not likely to change. Of course, finding other ways to judge the actual performance of a developer by measuring his qualities as a true “software engineer” presents a challenge to software development management.

Eventually, I think, financial success proves how relying on open, generic and commonly agreed solutions pays out. As a software engineer, I like being part of a team which has come to this conclusion already.

Do you agree with what I wrote in this article? Do you have any additions from your own experience? This is my first proper “opinion” post on my blog, so please let me know what you think about it in the comments section below.


August 23, 2015

LambdaOmega 0.1 RC-1 released!



I’m happy to announce that LambdaOmega, a more concise Java collection and functional API, 0.1 RC-1 has been released and 0.1 RELEASE is imminent. In this blog post, I’d like to show you what’s in the current release and what is yet to come in the near future.

Update June 12, 2016: LambdaOmega 0.3 is now officially released. Read the update post here.

I kindly invite you to take a look at LambdaOmega’s GitHub repository to find the current project status and usage information, or take a look at the API docs if you’d like to dive in into the technical details.

What is LambdaOmega?

  • It’s a wrapper API to make usage of Java collections, lambdas and CompletableFuture more simple, concise and enjoyable, as inspired by Groovy and JavaScript / lodash.
  • It provides simple Ranges and 2d Vectors.
  • It perfectly fits unit tests where fluid, maintainable code is key.
  • It has a small footprint (JAR < 85KB) and no other dependencies.
  • It’s thoroughly tested (coverage > 80%).
  • It comes with human-readable documentation.
For more information, you may read my introductory blog post as well.

What’s currently part of LambdaOmega

A simple yet powerful List / Map API

The heart of LambdaOmega is the L class which is a wrapper for a Java List
L<Integer> myL = l(0, 1, 2);
and the M class with is a wrapper for a Java Map.
Map<String, Integer> map = m("a", 0).Insert("b", 1).i("c", 2).m;
As of now, both classes provide the complete functionality of their vanilla Java counterparts, but with enhanced method signatures and return types:
List<Integer> outcome = l(0, 1, 2).add(3, 4);
Where sensible, there are “immediate” and “terminal” variations of a method, returning either another wrapper or the final result:
L<Integer> modifiedList = l(0, 1, 2).Add(3).Add(4, 5);
The most commonly used functional operations (with lambda expressions) on Stream have been implemented on these wrappers:
List<Integer> list246 = l(0, 1, 2).Map(it -> it + 1).map(it -> it * 2);
Although inspired my Java Collection / Map, a new API has been built from scratch, allowing Map-like access on a L and List-like access on a M:
String c = m("a", 0).i("b", 1).i("c", 2).indexOf(2);
With version 0.1, the main work on L, M, the super class C, and their interfaces is finished.

Additional data structures: Ranges, vectors

The R class represents an int range. It’s basically syntactic sugar to create ranges using the Java 8 stream API.
List<Integer> list012 = r(0).to(3).list;
The V2 class represents a 2-dimensional vector = a 2-ary tuple:
V2<String, Integer> vector = v("a", 0);
With version 0.1, the main work on R and V2 is finished.

FunctionalInterface transformations

The F class is built to encapsulate and unify the 40+ implementations of FunctionInterface in Java, wrapping a common API around any FunctionalInterface implementation.
int two = f((Integer it) -> it + 1).call(1); // Function
int three = f((Integer x, Integer y) -> x + y).call(1, 2); // BiFunction
boolean yes = f((Integer it) -> it > 0).call(1); // Predicate
Currently, the basic 1- and 2-ary Function, Consumer, Predicate, and Supplier are supported.

Support for additional FunctionalInterface transformations is planned for future releases.

A better CompletableFuture API

The Promise class is a drop-in replacement for CompletableFuture. It streamlines its API and provides fixes for the API flaws discussed here.

With version 0.1, the main work on Promise is finished.

RELEASE plans

  • 0.1 RC-1 is out now
  • If there are any error reports, these will be fixed and incorporated into a RC2 at ~ August 30
  • 0.1 RELEASE will be available either at ~ August 30 (unless there’s a RC2) or ~ September 6.
The RCs really are just tags, not branches. Until the 0.1 RELEASE, no new functionality will be built in, only bugfixes. This makes managing this small project a lot easier.

Future plans

Future plans primarily consist of adding features to the existing API. As such, the existing parts of the API should stay stable.

V. 0.2: F++

  • Support for all FunctionalInterfaces and more transformations in the F class.

V. 0.3: S++

  • Fully implement S (Set)

V. 0.4: Final touches

  • Add more utility methods if sensible
  • Add more syntactic sugar for existing methods where sensible
  • Clean up minor disputed parts of the API
After that, there will probably be a version jump to 1.0, marking the API “finished”.

Please keep in mind that this is a private project of mine. I will work on it as long as I think it’s fun and useful. Any kind of feedback, encouragement and collaboration is welcome! Feel free to leave me a comment down below with any question, suggestion or general feedback you may come up with.

Update June 12, 2016: LambdaOmega 0.3 is now officially released. Read the update post here.

August 22, 2015

JSF / JEE enums best practices



Having discussed some general Java enum best practices in my previous blog post, I’d like to quickly add some enum best practices which specifically apply to a JSF / JEE environment. These stem from my own JSF experience.

When to use enums

In a JSF (or, more generally speaking, in a JEE) environment, you would typically use enums less often than in a simple Java SE application because in JEE, you generally want to keep some sort of runtime flexibility, which is exactly what we try to diminish when using enums, as shown in the previous article.

With enums, you have a set of values fixed at compile time. In a JEE environment, however, you typically want to be able to alter any set of values at runtime with CRUD operations. This enables you to extend the application without having to re-compile it, but rather add some DB entries.

Of course, you may also keep in mind that typically, creating and maintaining a full-fletched CRUD entity including classes, services, DB tables and DB entries means more effort than just creating an enum.

Here are some typical examples of when to use enums and when not:
  • Countries, states: Don’t use enums. Yes, political structures don’t last forever. Instead, you want to have a Country / State class and a set of predefined entities in a DB an application admin can alter using CRUD.
  • Some kind of category / tag like “genre” for books: Typical DB table use case.
  • Some “is-a-kind-of…” description like “type” of book (e.g. normal book, audio book, e-book): You wouldn’t use enums or a String value from a DB table either. Instead, use inheritance with an abstract Book as the parent class, and concrete subclasses. Use an appropriate O/RM mapping (e.g. JPA’s InheritanceType.JOINED) to map inheritance to the DB. This approach fits an object-oriented architecture most closely.
  • Gender (male / female / undefined): A typical use case for enums. You’ll never have to alter the predefined value set so make it compile time safe.
  • Payment type (credit card / invoice / PayPal,…): You may use enums here as you may expect that in order to alter the set of options, you’ll have to re-program parts of your application anyway.
  • Currency: A border case. If it’s just very generic like $, £, €, ¥, you could use enums as you might expect these currencies to outlive your application. If however you want to provide an exhaustive list of currencies, treat it just like geopolitical entities and keep them in a CRUD table. I would highly recommend this DB approach here.

How to use enums in JPA

If you use an enum, it will eventually just be a property of a bean and as such, will be mapped to the DB if the entity is.

JPA allows for two strategies here, determined by the value used with the @Enumerated annotation on the property in question:
  • @Enumerated(EnumType.ORDINAL): Saves the value’s #ordinal() to the DB (this is the default if value is omitted).
  • @Enumerated(EnumType.STRING): Saves the value’s #name() to the DB.
It’s critical that you don’t go with the default, but use STRING:
@Enumerated(EnumType.STRING)
private PaymentType paymentType;
In fact, using ORDINAL would make your O/R mapping extremely brittle as adding a new enum value somewhere in between existing values would mix up subsequent values, thus breaking the O/R mapping. On the other hand, of course, you never want to change an enum value’s #name() unless you really want it exchanged.

Removing an enum value of course requires a cleanup of existing DB data before bringing the application back online.

How to use enums in JSF

When it comes to enums, the excellent general-purpose JSF util library OmniFaces once again proves itself useful. Combining its functionality with standard JSF best practices, working with enums becomes really easy and straighforward.

The most typical use case for enums in a JSF application which I will cover here is to show all available enum values in a <select…> component, allowing the user to select one and set it as a model property. Here is the code required for that:
<o:importFunctions type="ch.codebulb.jsfenumbestpractices.model.PaymentType" />
...
<h:selectOneMenu id="paymentType" value="#{paymentController.entity.paymentType}">
    <f:selectItems var="item" value="#{PaymentType:values()}" 
                   itemLabel="#{msg['model.paymentType.'.concat(item)]}" />
</h:selectOneMenu>
  • <o:importFunctions> registers a class’s static methods as EL functions in the current page. In the example, we use this to access the PaymentType enum’s values() method with returns a PaymentType[].
  • We set the itemLabel to an I18N key registered in a messages.properties file. Note that you have to use String#concat() instead of + to concat Strings in EL 2.2+.
By using the standard I18N facilities, we can easily provide localization for enum values. Here’s an example messages.properties file:
model.paymentType.INVOICE=Invoice
model.paymentType.CREDIT_CARD=Credit card
model.paymentType.PAYPAL=Pay Pal
For the special case of a <seclectMany…> component, using the omnifaces.GenericEnumConverter additionally will make sure type information is preserved. See its documentation for more information.

Conclusion

That’s all there is to say about using enums in a JSF / JEE environment. By relying on a mature tech stack, enums aren’t anything special anymore; the actual critical aspect is their proper usage as determined by the application design.

If you feel like this article still lacks any important enum-related information, please let me know in the comments section. Other than that, this will probably me my last word on enum usage best practices for a long time.

August 16, 2015

Java enums best practices by example (part 3 of 3)


Pages: 1 2 3

Enum as a template

Let’s examine again this API which makes use of enum input parameters, thus adhering to “best practices”:
public static enum Format {
    PDF, EXCEL, CSV;
}
    
public static void formatFile(File file, Format format) {
    // do something based on format
}
Now, you may argue that this still violates the Open / closed principle: As we are constrained to using an enum value of Format, extending the formatFile(…) method for additional format support forces us to extend the Format enum.

If you really need this flexibility, but still keep the API clear and “don’t make me think” compliant, I propose a compromise to keep the enum API for simple cases, but keep it open for extensions.

Let’s assume we want to be able to provide a custom BaseFormat, but have a pre-defined set of formats available as an enum:
public static abstract class BaseFormat {
    public abstract void formatFile(File file);
}

// BaseFormat implementations…

public static enum Format {
    PDF(new PdfFormat()),
    EXCEL(new ExcelFormat()),
    CSV(new CsvFormat());
    
    public final BaseFormat format;

    private Format(BaseFormat format) {
        this.format = format;
    }
    
    public void formatFile(File file) {
        format.formatFile(file);
    }
}

public static void formatFile(File file, BaseFormat format) {
    format.formatFile(file);
}

public static void formatFile(File file, Format format) {
    formatFile(file, format.format);
}
Now, because an enum cannot extend a class, you would use it as a wrapper. Consider the two flavors of formatFile(…): You can either provide a Format enum (i.e. choose from a predefined format for convenience) or provide a custom implementation of a BaseFormat.

If you are actually able to extract the desired functionality to an interface, the templating is a lot simpler because both the enum and a hypothetical custom extension can just implement the same interface:
public static interface BaseFormat {
    public void formatFile(File file);
}

public static enum Format implements BaseFormat {
    PDF {
        @Override
        public void formatFile(File file) {
            System.out.println("PDF format");
        }
    }, EXCEL {
        @Override
        public void formatFile(File file) {
            System.out.println("Excel format");
        }
    }, CSV {
        @Override
        public void formatFile(File file) {
            System.out.println("CSV format");
        }
    };
}

public static void formatFile(File file, BaseFormat format) {
    format.formatFile(file);
}

Assuring enum value order

I’d like to discuss one last “enum best practice” here which covers these two quite common special cases:
  • you want to assure an inner order of the enum values;
  • you want to assure that for a given enum value, it matches a given #ordinal() number.
For example let’s imagine we have this enum:
public static enum Direction {
    NORTH, EAST, SOUTH, WEST
}
It’s desirable to have the values in this very order (N-E-S-W) when presented in a UI, and to make sure that our fellow developers don’t accidentally mess up the order when they modify / extend the enum (e.g. add intermediary directions).

You can assure this by simply adding an explicit ordinal field:
public static enum Direction {
    NORTH(0),
    EAST(1),
    SOUTH(2),
    WEST(3),
    ;
    
    int n;

    private Direction(int n) {
        this.n = n;
    }
}
In a unit test, you can then test that developers don’t forget to count up the field if they insert a new enum value.
@Test
public void testOrder() {
    Direction[] values = Direction.values();
    for (int i = 0; i < values.length; i++) {
        assertEquals(i, values[i].n);
    }
}
For enums with many values, this also helps the developer identifiying an enum value for a given ordinal if some circumstances force him to manually do this. Of course, use this technique of deliberately introducing redundancy only when really needed!

Conclusion

As I have written in the introduction, I think that enums really are a highly useful and powerful part of Java with the potential to significantly increase code readability and maintainability – if properly used. They both require and foster understanding the all-important difference of compile time and runtime checking, and when to apply which of them.

I hope this article made you discover new enum techniques or confirmed that you’re already doing it right. If you see potential problems with one of these practices or if you think that something is missing – please share your thoughts in the comments section below.

Update August 22, 2015: Read on: JSF / JEE enums best practices


Pages: 1 2 3

Java enums best practices by example (part 2 of 3)


Pages: 1 2 3

Enumify your input with enum reverse lookup

Making constants compile-time safe makes sense because they never change at runtime. But enums can and should also be applied to make case differentiations at runtime.

Let’s assume that we receive the file format at runtime through user input, which is a String. A naïve implementation would be:
public static void formatFile(File file, String format) {
    switch (format) {
        case "pdf":
            System.out.println("PDF format");
            return;
        case "excel":
            System.out.println("Excel format");
            return;
        case "cvs":
            System.out.println("CVS format");
            return;
        default:
            throw new IllegalStateException("Format not recognized: " + format);
    }
}
Even with Java 8’s new support for switch on String (rather than if / else ifs), this implementation is brittle. This is even more true if input is processed through multiple steps (a.k.a. method calls) in the same original form, infecting the whole API with a non-compile time safe data type. In case of a String being passed around, this anti-pattern is famously known as “Stringly typed” programming (as a pun on opposite “strongly typed”).

What you want to do is sanitize so-called tainted input. You want to do this as early as possible in your call chain and you want to make it, if possible, compile-type safe. Thus, enums are a perfect choice.

To turn any kind of runtime-determined data into an enum, the enum reverse lookup pattern is a known best-practice. Consider this implementation:
public static enum Format {        
    PDF {
        @Override
        public void formatFile(File file) {
            System.out.println("PDF format");
        }
    }, EXCEL {
        @Override
        public void formatFile(File file) {
            System.out.println("Excel format");
        }
    }, CSV {
        @Override
        public void formatFile(File file) {
            System.out.println("CSV format");
        }
    };
    
    private static final Map<String, Format> LOOKUP;
    
    static {
        Map<String, Format> map = new HashMap<>();
        map.put("pdf", PDF);
        map.put("excel", EXCEL);
        map.put("cvs", CSV);
        map = Collections.unmodifiableMap(map);
        LOOKUP = map;
    }
    
    public static Format getFrom(String input) {
        Format ret = LOOKUP.get(input);
        if (ret == null) {
            throw new IllegalArgumentException("Not a valid format: " + input);
        }
        return ret;
    }
    
    public abstract void formatFile(File file);
}

public static void formatFile(File file, String format) {
    Format.getFrom(format).formatFile(file);
}
Here, the mapping from user input to a compile time checked enum (the sanitizing) happens in one place, namely through a map-based lookup (the map can / should be final and immutable). This is highly performant, maintainable and testable. Remember to check for an invalid lookup in the static lookup function.

In the example, the solution is combined with previous best practice to use enum inheritance. Note that the client code (method formatFile(…)) is free of any input sanitizing / differentiation.

If that method would invoke another method, you would then of course use the sanitized, compile-time safe enum value in any subsequent API call.

…or with the strategy pattern on the input

Of course, if the input type is not a primitive or a Java core / third party type but a class you own yourself, you would use the object oriented strategy pattern to turn it into an enum rather than a static helper reverse lookup.

Let’s assume that in the next example, MyFile is loaded from a DB and we want to extract the file format information and make it compile time safe.
public static abstract class MyFile {}

public static class PdfFile extends MyFile {}

public static class ExcelFile extends MyFile {}

public static class CsvFile extends MyFile {}

public static enum Format {
    PDF, EXCEL, CSV;
}

public static void formatFile(MyFile file) {
    // use a helper method to extract Format from MyFile
}
Here, using enum reverse lookup or any other static helper method is not desirable because again, the Open / closed principle is violated as adding a new MyFormat subtype would imply a change to the lookup function.

Instead, use the strategy pattern with inheritance on the type itself:
public static abstract class MyFile {
    public abstract Format getFormat();
}

public static class PdfFile extends MyFile {
    @Override
    public Format getFormat() {
        return Format.PDF;
    }
}

public static class ExcelFile extends MyFile {
    @Override
    public Format getFormat() {
        return Format.EXCEL;
    }
}

public static class CsvFile extends MyFile {
    @Override
    public Format getFormat() {
        return Format.CSV;
    }
}

public static enum Format {
    PDF, EXCEL, CSV;
}

public static void formatFile(MyFile file) {
    Format format = file.getFormat();
}
Because the format transformation is defined abstractly on the base class, the developer is literally forced to provide a sensible file format for every new subclass. There’s no central, remote case differentiation anymore.

(By the way, the example of course is quite artificial and suspicious. You would rather just define formatFile() as a member method of MyFile and get rid of the enum altogether.)

Pages: 1 2 3

Java enums best practices by example (part 1 of 3)



Even with the new fancy additions to Java 8, enums stay one of the most useful – and most underestimated – features of the language. When applied correctly, they can increase code maintainability considerably. In this article, I’d like to present some common best practices which stem from my Java EE experience.

Enumify your constants!

First of all, it’s crucial to understand in which situation usage of enums is appropriate. I consider the following to be a general rule for Java software maintainability:

For case differentiations, constant fields are dead. Always use enums instead!

Consider the following implementation, making use of “classic” constant fields to distinguish some “file format”:
public static final int FORMAT_PDF = 0;
public static final int FORMAT_EXCEL = 1;
public static final int FORMAT_CSV = 2;

public static void formatFile(File file, int format) {
    // do something based on format
}
Compare this with an implementation which uses an enum to encapsulate the supported file format types:
public static enum Format {
    PDF, EXCEL, CSV;
}

public static void formatFile(File file, Format format) {
    // do something based on format
}
Just by examining the code which uses enums, the developer can say with certaintly what are valid values of the formatFile(…)’s format parameter. And, even more importantly, so can the compiler!

Enums shift information from runtime to compile time. They make a program crash early, and that’s a good thing. In the example, you just cannot compile formatFile(…) with an unknown, undefined format parameter (except null). To sum up:

Having information available at compile time means, that it is available:
  • For the compiler
  • For you, as the developer, by just looking at the code
Having information available at runtime means that:
  • It’s not available for the compiler. It can only be detected at runtime, requiring you to write additional tests.
  • It’s available for you, as the developer, only when you run the program (e.g. in a unit test) and debug it.
Java is a statically typed language and as such, it has a compiler which can statically check syntax constraints. This comes at a high price of flexibility, when compared with dynamically typed languages without compiler (such as Ruby). Let’s not waste this investment! Make use of compile time checking whenever possible to increase code robustness and maintainability. That’s the main lession learnt from proper enum usage.

As you can see, it never makes sense to use constant fields for case differentiations, they can and should always be replaced by enums. Still, having constant fields is a quite common anti-pattern. It doesn’t really help that unfortunately, it’s even quite widespread in some of Java’s core classes, e.g. in the old Swing classes. They’re actually quite good illustrations of the anti-pattern: Unless you’re lucky and the constant fields are declared in the same class as is the receiver of the constant, you just have no chance to find out what are valid constant values just by looking at the API. They truly are the implementation of the „magic number“ anti-pattern.

Enums are objects – strategy pattern on enum

Let’s again examine above example code we have just deemed “best practice”:
public static enum Format {
    PDF, EXCEL, CSV;
}

public static void formatFile(File file, Format format) {
    // do something based on format
}
Even though it’s now compile-time assured that the format parameter is within the set of valid parameter values, by taking a closer look at the method implementation, it is still not assured that it matches the actual value because implementation (inside formatFile(…)) and case differentiation (enum type definition) live independently of each other. This is a violation of the “Open / closed principle”: A change in one place (e.g. adding a new format) requires a change in another place (e.g. the formatFile(…) implementation. We have basically just shifted from a magic number to a magic enum.

This inconsistency exists because the code does not adhere to object oriented principles: As the Format enum is an object, it should be responsible for its own behavior. The formatFile(…) method thus belongs inside the Format enum!

There are actually three ways to achieve this. The most simple and naïve way is to implement a central method on the enum:
public enum Format {
    PDF, EXCEL, CSV;
    
    public void formatFile(File file) {
        switch (this) {
            case PDF:
                System.out.println("PDF format");
                return;
            case EXCEL:
                System.out.println("PDF format");
                return;
            case CSV:
                System.out.println("PDF format");
                return;
            default:
                throw new IllegalStateException("Format not recognized: " + this);
        }
    }
}
Actually, this is still unsafe in the very same way as the previous implementation, but at least, the logic now resides in the same (enum) class which also defines the case differentiation. For a developer, it’s thus more likely that he remembers e.g. to add another switch case branch to that method if he adds an additional format enum value. Also note that the default switch branch throws an exception. This is extremely helpful to make sure that even if an error only shows at runtime, it shows immediately.

Because enums support inheritance as well, you can make the individual values implement a common interface:
public enum Format {
    PDF {
        @Override
        public void formatFile(File file) {
            System.out.println("PDF format");
        }
    }, EXCEL {
        @Override
        public void formatFile(File file) {
            System.out.println("Excel format");
        }
    }, CSV {
        @Override
        public void formatFile(File file) {
            System.out.println("CSV format");
        }
    };
    
    public abstract void formatFile(File file);
}
This is fully object-oriented compliant, but it’s arguably also hard to read; even more so, if there were multiple methods implemented by the enum!

As a variation of this previous approach, you could delegate implementation to a separate class which is then wrapped by the enum:
public enum Format {
    PDF(new PdfFormat()),
    EXCEL(new ExcelFormat()),
    CSV(new CsvFormat());
    
    private final BaseFormat format;

    private Format(BaseFormat format) {
        this.format = format;
    }
    
    public void formatFile(File file) {
        format.formatFile(file);
    }
}

public abstract class BaseFormat {
    public abstract void formatFile(File file);
}

public class PdfFormat extends BaseFormat {
    @Override
    public void formatFile(File file) {
        System.out.println("PDF format");
    }
}

public class ExcelFormat extends BaseFormat {
    @Override
    public void formatFile(File file) {
        System.out.println("Excel format");
    }
}

public class CsvFormat extends BaseFormat {
    @Override
    public void formatFile(File file) {
        System.out.println("CSV format");
    }
}
This introduces more boilerplate code to write the individual classes, but it’s far more readably, plus you can split the individual implementations across multiple files to further increase readability. It's a bit less safe than the implementation on the enum value itself though.

To be honest, for very simple cases, I use the most simple version although not perfectly “secure”. For more complex cases (5+ enum values or 2+ enum methods), I use the latter approach.

Pages: 1 2 3

August 9, 2015

LambdaOmega: Java Collections, Lambdas & Promises simplified



Update June 12, 2016: LambdaOmega 0.3 is now officially released. Read the update post here.

Instead of a lengthy introduction, please read what LambdaOmega adds to a Java 8-based project:
  • Simple literal-like instantiation of Lists, Maps, and Ranges.
Map<String, Integer> map = m("a", 0).a("b", 1).a("c", 2);
  • Collection methods which feel familiar, but are far more powerful and concise.
List<Integer> zeroToSix = l(0, 1, 2).a(3, 4).addAll(l(5, 6));
  • A simple Lambda-driven API functional interface for straightforward application of the most widely used Collection functions, inspired by JavaScript lodash and Groovy.
Integer negative = l(1, 2, -1, 3).find(it -> it < 0);
  • A grand unified Collection API where a List is also a Map from int to T, and a Map is also a List of entries, and even a Function is also a Map.
L<String> xy = l("a", "b").PutAll(m(0, "x").put(1, "y"));
  • Convert everything into everything within Collections and Functions.
Set<Integer> set = l(0, 1, 2).toSet();
  • Promise: A drop-in replacement for CompletableFuture with a superior, more concise API.
new Promise<String>().completed(
    (it, err) -> {if (err == null) {return "success: " + it;} else throw new RuntimeException();}
);
  • A simple 2D vector (2-ary tuple) class.
V2<String, Integer> vector = v("a", 0);
  • Plus many helper functions and extras, as e.g. inspired by the Groovy language.
println("Hello Omega");
  • Small footprint (<75KB), no other dependencies.
  • Thoroughly tested.
  • Human-readable documentation.
Please head over to the GitHub repository to learn more about what LambdaOmega provides and how to use it.

Read on if you’re interested in its back-story.

Why would I use a 3rd party Collection API?

I’m a Java developer. I know that Java, both as a language and as a platform, has many strong parts. A concise Collection API is not one of them. When compared with other, more modern languages such as Groovy, working with the Java Collection API means bloated, redundant, potentially copy-pasted code.

Actually, quite a few Java core APIs are considered not good enough by some people; this has given birth to various 3rd party libraries such as Apache commons or Joda time.

I do firmly believe that concise code is a tremendous advantage in terms of productivity, readability and maintainability. Want to make less errors? Write less code. This is especially true for everyday / every minute tasks such as Collection manipulation. Coming back from Groovy, one has to admit that the Java Collection API, including their newest Lambda additions really is bloated and inconsistent.

The motivation behind OmegaLambda

On this blog, I recently complained a lot about the state of Java’s lambda API, especially in regard to Collections and the CompletableFuture / lambda API. But making complaints is not constructive. Making a change is far more constructive.

As briefly mentioned, the OmegaLambda library is primarily inspired by:
  • Groovy, which shows that it’s absolutely possible to make even a complex Collection API both more simple and more powerful at the same time.
  • lodsh, which shows that, at least in the JavaScript world, there actually is reason and acceptance to use a 3rd party wrapper API even for something as basic as Collection manipulation.

Oh, the library name has no further significance. I just couldn’t think of anything better than LambdaOmega.

So… is this a Guava clone?

No. Guava primarily serves two purposes:
  • providing Java 8-like stuff for projects stuck with pre-Java 8;
  • providing additional (Collection) utilities and data structures which are not present in vanilla Java.
This is not at all what LambdaOmega offers. Instead, this project provides simple wrappers for existing Java 8 functionality to make their usage more straightforward and enjoyable. Also, Guava has a much bigger footprint.

What about performance?

  • LambdaOmega doesn’t make use of reflection. It really just wraps Collection API method calls and should perform similarly to vanilla API calls.
  • However, intermediate operation on LambdaOmega collections will always create a new Collection much unlike vanilla Java collections which just operate on a stream. This may decrease performance for big collections.
Thus, even though LambdaOmega should perform OK in everyday situations, keep in mind that it is not and will never be built primarily for speed.

Again: Why would I use this?

Use LambdaOmega where you make intense use of Java’s collection API and keeping your code clean and concise is key.

One perfect usage scenario for LambdaOmega of course are JUnit tests which typically invoke lot of collection boilerplate code.

As a drop-in-replacement for CompletableFuture

Having dissected the CompletableFuture API of Java 8 in the previous blog post, I have located many inconsistencies in that API. As CompletableFuture promises make intense use of lambda expressions, I have included a drop-in-replacement for CompletableFuture named Promise in the LambdaOmega library.

This will turn the bloated, inconcise Java CompletableFuture API:
  intermediary terminal terminal (Runnable) A E
Construct from task static supplyAsync   static runAsync   X
complete listener thenApply thenAccept thenRun X X
completeExceptionally listener exceptionally        
Combined complete and completeExceptionally listener handle whenComplete   X X
Dynamic callback chaining thenCompose     X X
AND all combining static allOf        
AND both combining thenCombine thenAcceptBoth runAfterBoth X X
OR any combining static anyOf        
OR either combining applyToEither acceptEither runAfterEither X X

into the much cleaner Promise API:
  intermediary terminal terminal (Runnable) A* E
Construct from task static completeAsync   static completeAsync   X
complete listener completed completed completed X X
completeExceptionally listener completedExceptionally        
Combined complete and completeExceptionally listener completed completed   X X
Dynamic callback chaining then     X X
AND all combining static allOf**        
AND both combining and and and X X
OR any combining static anyOf**        
OR either combining or or or X X

*Synchronous / asynchronous is controlled by a boolean flag rather than by the method name.
**The flawed implementations of allOf / anyOf have been fixed.

Project status and future plans

The current status of the library is unstable / experimental / request for feedback.

Even though its core functionality is perfectly working already, there’s no stable release yet. I decided to share it on my blog nonetheless as I’m hoping to receive feedback before fixing the API.

Please let me know either in the comments section or over on GitHub what you think about this library. Do you think it is useful, useless, harmful, crazy, funny? I’m open to any kind of improvement proposals.

Current to-dos are:
  • Complete test coverage for indexed access on L and sequential access on M
  • Complete F (function) implementation
  • Add more Groovy-like collection functionality (http://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Collection.html)
  • Add more conversion methods
  • Properly implement S (Set).
I’ve started this project for my own pleasure and usage and to learn more about Java 8’s collection API. I will try to work on a complete, stable implementation in the near future, but I may as well leave it as it is for now. If you’re really enthusiastic about this library and you’d like to team up to get it finished, please let me know.

Update June 12, 2016: LambdaOmega 0.3 is now officially released. Read the update post here.