A journey to find those pieces of software or technology that facilitate productive and maintainable software development

Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Wednesday, May 4, 2011

Java to Scala in the pursuit of Intention

This is a response to Cedric Beust's From Scala back to Java

Cedric linked to a very interesting discussion of the migration challenge from Java to Scala and the hurdles that are holding people back or pushing them away. This is an essential discussion to be having as migration is the reality for most companies and developers considering Scala. Very few of us have the luxury of starting fresh.

"This situation is pretty shameful, to be honest. Scala is about seven years old and the absence of decent IDE support after such a period of time is absolutely unforgiveable, especially given the ambitions of the Scala team." -Cedric Beust From Scala back to Java

That statement concerns me deeply. It is contradicted by my experience with IntelliJ IDEA's Scala Plug-in. I use this plugin every day for my work and I find it covers the subset of Scala that supports direct class-based object-oriented (Java-style) programming nearly as well as IntelliJ does Java. The support goes deep as well as it supports most of the refactoring and static analysis work flows IntelliJ provides for Java. JetBrains' Scala plug-in also gets very close to fully supporting the very complex combinations of Scala features that give rise to internal DSLs.

"First, I’m not sure that the envelope needs to be pushed any further in Scala. A lot of potential users are routinely turned off by its excessive functional and academic aspects and its complex type system. The interaction between functional and object oriented features already feels pretty complex to handle, so I certainly don’t want the language to evolve any further. I hope that future efforts will be oriented more toward the libraries and the tools than the language" -Cedric Beust From Scala back to Java

I see this as another deeply troubling misconception about Scala and abstraction complexity in general. I am ashamed to admit that I shared this concern and even posted to that effect on this blog historically. Object-orientation was a huge mind-shift and jump in abstraction power over structured programming. Early criticisms labeled it as overly complex and unmanageable for teams. It is undeniable now that OOP has paid massive dividends to its adopters. The size of the OOP community is a testament to how accessible it has proven to be. I think the same is true of a fusion of OOP and FP as provided in Scala.

Scala's complexity is not complicated. It is a well into which you willingly dip as deeply or as shallowly as you like to be productive. This is another way of looking at Martin's Scala Levels.

What if different developers have different depths they dip to? How does this affect readability among developers? It could easily affect readability if developers go beyond their depth, but the same applies to inner classes and interfaces, runtime annotations, generics and reflection in Java. Chances are, if your team is uncomfortable reading code using these features, then they are equally unlikely to use them effectively in Java and will write obscure or incomprehensible code when they use them. However, effective use of these features yields shorter, more readable code that more clearly expresses it intent.

Abstractions give developers more tools to clearly express their intentions. Java's abstractions clearly help. When it appears that they don't it is simply a case of ineffective or novice application. The same is true of Scala, but its power in expressing intent is substantially magnified by a much richer set of abstractions. Java has a deep well of abstractions and gives a great deal of power to developer. Scala has a much deeper well of abstractions and gives an order of magnitude more power than Java for expressing intent directly.

Clear expression of intent is absolutely central to maintainable code. Scala is worth the work of learning and the cost of training to make your team more effective. It is worth it because it gives your team a considerable advantage over Java in expressing intent which will dramatically reduce maintenance cost over time.

I strongly suggest migrating from Java to Scala in the pursuit of intention.

Monday, August 24, 2009

Concise HOWTO's: Message from Java to Erlang

First create an Erlang module called server that receives messages in the format {Sender,Data} and echoes the Data portion back to the Sender. Then create a Java class called EchoClient that prompts for a node to connect to and prompts in a loop for messages to send. You will need OtpErlang.jar in your build classpath and runtime classpath. I found it in /opt/local/lib/erlang/lib/jinterface-1.5.1/priv/ on Mac OS X. I had to install Erlang from source on Ubuntu since the APT package is missing Jinterface.

Listing of server.erl:

-module(server).
-compile(export_all).

start() -> register(server,spawn(fun loop/0)).
loop() ->
    receive
        {Sender,Data} ->
            Sender ! Data,
            loop();
        shutdown -> ok
    end.

Listing of EchoClient.java

import java.io.BufferedReader;
import java.io.InputStreamReader;

import com.ericsson.otp.erlang.*;

public class EchoClient {
    public static void main(String[] args) throws Exception {
        OtpNode node = new OtpNode("java");
        OtpMbox mbox = node.createMbox("admin_gui");
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String defaultServerNodeName = "erl_node@" + node.host();
        System.out.format("Server Node to contact [%s]> ", defaultServerNodeName);
        String serverNodeName = in.readLine();
        if (serverNodeName == null || "".equals(serverNodeName)) {
            serverNodeName = defaultServerNodeName;
        }
        OtpErlangTuple serverPidTuple = new OtpErlangTuple(new OtpErlangObject[] {
                new OtpErlangAtom("server"), new OtpErlangAtom(serverNodeName)});
        while (true) {
            if (!node.ping(serverNodeName, 1000)) {
                System.out.println("Erlang node is not available: " + serverNodeName);
                System.exit(1);
            }
            System.out.print("Message (Hit Enter to send)> ");
            String message = in.readLine();
            if (message != null) {
                mbox.send("server", serverNodeName, new OtpErlangTuple(
                        new OtpErlangObject[] {
                                mbox.self(), new OtpErlangList(message)}));
                OtpErlangObject serverReply = mbox.receive(1000);
                if (serverReply == null) {
                    System.out.println("WARN: Timeout when receiving reply");
                } else {
                    System.out.format("%s replied : %s%n", serverPidTuple, serverReply);
                }
            }
        }
    }
}

Open an Erlang shell in the directory with server.erl by running erl -sname erl_node. From that shell compile and run the Erlang server module.

Listing of the Erlang shell interaction

$> erl -sname erl_node
Erlang R13B01 (erts-5.7.2) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.2  (abort with ^G)
(erl_node@alains_desktop)1> server:start().
true
(erl_node@alains_desktop)2> server ! {self(), hello}.
{<0.84.0>,hello}
(erl_node@alains_desktop)3> f(M), receive M -> {ok, M} after 100 -> {error,timeout} end.
{ok,hello}
(erl_node@alains_desktop)4>

Run the EchoClient Java program and either accept the default node or specify the name of another Erlang node you want to work with. Type messages in and see them echoed back to the EchoClient console.

Listing of the EchoClient Java program console interaction:

Server Node to contact [erl_node@alains_desktop]> [ENTER]
Message (Hit Enter to send)> Hello, Erlang![ENTER]
{server,erl_node@alains_desktop} replied : "Hello, Erlang!"
Message (Hit Enter to send)>

Sunday, August 23, 2009

Concise HOWTO's: Message from Erlang to Java

First create an EchoServer in Java that receives messages in the format {Sender,Data} and echoes the Data portion back to the Sender. You will need OtpErlang.jar in your build classpath and runtime classpath. I found it in /opt/local/lib/erlang/lib/jinterface-1.5.1/priv/ on Mac OS X. I had to install Erlang from source on Ubuntu since the APT package is missing Jinterface.

Listing for EchoServer.java:

 
import com.ericsson.otp.erlang.*;

public class EchoServer {
    public static void main(String[] args) throws Exception {
        OtpNode node = new OtpNode("java");
        OtpMbox mbox = node.createMbox("echo");
        OtpErlangAtom SHUTDOWN = new OtpErlangAtom("shutdown");
        while (true) {
            OtpErlangObject message = mbox.receive();
            System.out.format("%s received: %s%n", mbox.self(), message);
            if (SHUTDOWN.equals(message)) {
                System.out.format("%s shutting down...%n", mbox.self());
                break;
            } else if (message instanceof OtpErlangTuple) {
                OtpErlangTuple messageTuple = (OtpErlangTuple) message;
                if (messageTuple.arity() == 2 && messageTuple.elementAt(0) instanceof OtpErlangPid) {
                    OtpErlangPid sender = (OtpErlangPid) messageTuple.elementAt(0);
                    OtpErlangObject sendersMessage = messageTuple.elementAt(1);
                    mbox.send(sender, sendersMessage);
                }
            }
        }
    }
}

Once you have compiled and started the EchoServer you can communicate with it from the Erlang shell. First you need to start a new named node with erl -sname erl_node.

Listing of the Erlang shell interaction:

Erlang R13B01 (erts-5.7.2) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.2  (abort with ^G)
(erl_node@alains_desktop)1> net_adm:ping(java@alains_desktop).                   
pong
(erl_node@alains_desktop)2> {echo,java@alains_desktop} ! {self(),"Hello, Java!"}.
{<0.39.0>,"Hello, Java!"}
(erl_node@alains_desktop)3> % use f(M) to "forget" M (make it unbound)
(erl_node@alains_desktop)3> f(M), receive M -> {ok,M} after 100 -> {error,timeout} end.
{ok,"Hello, Java!"}
(erl_node@alains_desktop)4> {echo,java@alains_desktop} ! {self(),{tuples,can,be,sent,too}}.
{<0.39.0>,{tuples,can,be,sent,too}}
(erl_node@alains_desktop)5> f(M), receive M -> {ok,M} after 100 -> {error,timeout} end.
{ok,{tuples,can,be,sent,too}}
(erl_node@alains_desktop)6> {echo,java@alains_desktop} ! shutdown.
(erl_node@alains_desktop)6>
(erl_node@alains_desktop)7> {echo,java@alains_desktop} ! shutdown.                         
shutdown
(erl_node@alains_desktop)8> {echo,java@alains_desktop} ! {self(),"Are you there?"}.        
{<0.39.0>,"Are you there?"}
(erl_node@alains_desktop)9> f(),receive M -> {ok,M} after 100 -> {error,timeout} end.
{error,timeout}
(erl_node@alains_desktop)10>

Listing of EchoServer Java process output:

#Pid received: {#Pid,"Hello, Java!"}
#Pid received: {#Pid,{tuples,can,be,sent,too}}
#Pid received: shutdown
#Pid shutting down...

SyntaxHighlighter