This is probably old news, but I've decided that Java MVC architectures are really over valued. Lots of classes and generic interfaces and abstractions make the business people feel like they are professional and scalable, and that is why Java is used in business.
I think one of the motivating factors is that somewhere in the back of the mind of the CEO running the Java-based company is the thought that the code written there will someday have to be presented to other business types as part of a buyout or investment process, and that these investors will really be looking closely to see if everything is as abstract as is humanly possible. That's fine, but I'd rather spend five minutes writing concise code in a flexible language than spend fifteen writing rigid Java code.
As an experiment, I wrote a partially-complete program for a killing robot in Python (my recent favorite, after JavaScript) and in Java. Which code would you rather have your dev team/minions writing? (The actual slaying/maiming functionality has been left out)[1]
Python. killingRobot.py:
#! /usr/bin/env python3 import sys def slay(victim): """Slays the given victim""" print('Slaying '+victim) # system calls def maim(victim): """Maims the given victim""" print('Maiming '+victim) #system calls def slayAll(filename, action=slay): """Applies the given action to all victims in the given file""" try: f = open(filename, 'r') for victim in f: action(victim.rstrip()) f.close() except: print('Unable to open file') # slay or maim all victims based on user input if __name__ == '__main__': if len(sys.argv) > 2: action = sys.argv[1]; filename = sys.argv[2]; if action.lower() == 'slay': slayAll(filename, slay) elif action.lower() == 'maim': slayAll(filename, maim) else: print('Invalid action: use slay or maim') else: print('Give an action and a file name')
Now Java. We'll begin with the interface and implementing classes. personAction.java:
public interface personAction { //applies some kind of action to some given victim public void doAction(String victim); }
slayAction.java:
public class slayAction implements personAction { //slays the given victim public void doAction(String victim) { System.out.println("Slaying "+victim); } }
maimAction.java:
public class maimAction implements personAction { //maims the given victim public void doAction(String victim) { System.out.println("Maiming "+victim); } }
Finally, the program. killingRobot.java:
import java.io.*; public class killingRobot { //slay or maim all victims based on user input public static void main(String[] args) { if(args.length > 1) { String action = args[0]; String filename = args[1]; personAction pAction; if(action.equals("slay")) pAction = new slayAction(); else if(action.equals("maim")) pAction = new maimAction(); else { System.out.println("Invalid action: use slay or maim"); return; } slayAll(filename, pAction); } else System.out.println("Give an action and a file name"); } //applies the given action to all victims in the given file public static void slayAll(String filename, personAction action) { try { FileInputStream f = new FileInputStream(filename); DataInputStream d = new DataInputStream(f); InputStreamReader i = new InputStreamReader(d); BufferedReader b = new BufferedReader(i); String victim; while((victim = b.readLine()) != null) { action.doAction(victim); } i.close(); } catch(Exception e) { System.out.println("Unable to open file"); } } }
I won't bother comparing line counts since both of these programs could probably be shortened by better coders. The point is that Java annoys me. And what super-annoys me are these crazy attempts to make everything generic so it can supposedly work better and be scaled more easily. It's not easier or better, it's Java-er. Blech.[2].
Notes:
- System calls for slaying and maiming only available in Windows ME and 7 Beta
- Announcing the first ever Killing Robot Programming Contest. Write the most concise (fully-functional) killing robot program. Losing entries will be slain by the winning entry's killing robot program. Go ahead. Do it in Java. I dare you.
I'm afraid you didn't make the Java implementation complicated or abstract enough. Look at your main method, it's doing the type instantiation of personAction interface right there! Bad design, Andrew.
ReplyDeleteYou need a PersonActionFactory class, which would have a method getAction(String act) and would instantiate the appropriate PersonAction for you. Of course, it's obvious that PersonActionFactory should be a singleton. Boom! Two more design patterns to make your code even more abstract, which obviously makes it better.
import java.io.*;
public class PersonActionFactory {
public static PersonActionFactory pActFact = null;
public static personActionFactory getInstance() {
if ( pActFact == null )
pActFact = new PersonActionFactory();
return pActFact;
}
private PersonActionFactory() { }
public PersonAction getAction(String act) {
if ( act.equalsIgnoreCase("slay") )
return new SlayAction();
else if ( act.equalsIgnoreCase("main") )
return new MaimAction();
else
throw new PersonActionNotFoundException("can't " + act + " a person");
}
}
public class KillingRobot {
public static void main(String[] args) {
if(args.length != 2) {
System.out.println("Invalid action: use slay or maim");
return;
}
String action = args[0];
String filename = args[1];
personAction pAction;
pActFact = PersonActionFactory.getInstance();
try {
pAction = pActFact.getAction(action);
KillingRobot.slayAll(filename, pAction);
} catch (PersonActionNotFoundException e) {
e.printStackTrace();
}
}
public static void slayAll(String filename, PersonAction action) {
try {
FileInputStream f = new FileInputStream(filename);
DataInputStream d = new DataInputStream(f);
InputStreamReader i = new InputStreamReader(d);
BufferedReader b = new BufferedReader(i);
String victim;
while((victim = b.readLine()) != null)
{
action.doAction(victim);
}
i.close();
}
catch(Exception e) {
System.out.println("Unable to open file");
}
}
}
Abstracter daniel = new JediMaster();
ReplyDeleteAbstracter andrew = new Padawan();
andrew.thankForCommenting(daniel);
andrew.bowTo(new BowableTo(daniel));
/*
if I set up the CVS server and you start the ANT build, we should be able to ship this by sometime mid-2015. Good collaboration!
*/