The link to the source code in the previous blog didn't work. I put it in the wrong directory. It's fixed now. You can get the code here: scala-gps.zip
Sphere: Related ContentTuesday, August 28, 2007
Tuesday, August 21, 2007
Scala vs Lisp for GPS: Part I: Expressivity
Introduction Before I found Scala I was looking for a language with the following characteristics:
- Expressivity on par with Python or Lisp
- Performance on par with Java
- Has a REPL or at least an interpreter
- Compiled
- Object-oriented
- Large number of modern libraries and frameworks
- Cross platform, including think-client GUIs
- Open Source
- The Scala implementation is more explicitly structured. Some of the structure, such as the static typing, is forced by Scala. Others, such as using classes instead of conventions on list contents to distinguish between normal conditions and "executing conditions," are not forced by Scala but are simply easier and more natural.
- The resulting plan is a list of operators rather than a list of lists obeying a convention. This is straightforward because "executing conditions" are a special class of condition and are explicitly tied back to the operators they represent.
- The core algorithm in Scala is completely and explicitly devoid of mutable state. The Lisp solution makes only one small use of mutation in achieve-all, and that occurrence could easily be removed in the same was as it was from Scala. However, cons cells, and the lists they form, are mutable and therefore it is much more difficult to prove that the algorithm uses no mutable state.
- The Scala solution required fewer utility functions. This is due to both the richer standard library and case classes.
- The problem-definition DSL required significantly more code in Scala, especially in order to make it interpreter-friendly.
- The syntax of the problem-definition DSL in Scala is statically checked. For example, you cannot use preconditions in the place of the add list. Achieving this took a fair amount of work, and I almost just went with a looser version that was equally easy to type and read but less validated.
- In my subjective opinion, the Scala version is much easier to read. I find the fact that Lisp control structure like "if" implicitly return nil on failure if not "else" is provided to be quite confusing.
- At least for this problem (which didn't use macros), Lisp code could be almost directly converted to Scala.
- Scala implicits make an effective substitute for special variables (i.e. defparameter) in Lisp.
- Overall LOC count is too close to matter.
- Lisp development is far more interactive that Scala.
- The Scala compiler catches a lot of "stupid" mistakes that the Lisp compiler does not (but the Lisp compiler catches some, much more than Python, Ruby, et. al.), reducing the number of edit/run cycles by a fair margin.
- Case classes are really useful. They allow you to add structure to your program without going to all the work of implementing all the support methods, such as equals, hashCode, toString, and unapply for pattern matching. Lisp is worse than Java et. al. because it has four different equals functions (eq, eql, equal, equalp) all with subtle (and not so subtle) differences. In Scala, if you are wise and don't have to deal with Java libraries (hah!), you pretend eq (reference equality) doesn't exist (indeed, pretending references don't exist, and null doesn't exist, seems like a good idea to me). In fact, I find case classes so useful, I think I'm going to write a Python metaclass so I can use them in Python, too.
- I retract previous negative statements about pattern matching on lists. It's useful. I get it now. But I still wouldn't convert a string to a list just for pattern matching.
Posted by Erik Engbrecht at 7:19 AM 10 comments
Labels: AI, Lisp, programming, Scala
Friday, August 17, 2007
Syntactic Sugar for Composition/Delegation
Composition/Delegation is a common pattern in object oriented software. There are a lot of different definitions floating around for both composition and delegation, but basically it amounts to this, as demonstrated in Java code:
class MyStringList implements List<String> {
private List<String> backingList;
public MyStringList(List<String> backingList) {
if (backingList == null) throw new NullPointerException();
this.backingList = backingList;
}
public String get(int i) { return backingList.get(i); }
public boolean isEmpty() { return backingList.isEmpty(); }
// ... lots of other methods like the ones above
public void add(String s) {
if (s == null || s.length() == 0)
throw new IllegalArgumentException();
backingList.add(s);
}
// and some more slightly modified methods to complete List
}
So MyStringList is composed of backingList and it delegates most of its methods to it. Furthermore, in this case it is using backingList to implement the interface List
class MyStringList extends ArrayList<String> {
public MyStringList() {}
public void add(String s) {
if (s == null || s.length() == 0)
throw new IllegalArgumentException();
super.add(s);
}
// do something for the other add methods as required...
}
That's a lot less typing. It's also strongly coupled to ArrayList
class MyStringList implements List<String> {
private delegate List<String> backingList;
public MyStringList(List<String< backingList) {
if (backingList == null) throw new NullPointerException();
this.backingList = backingList;
}
public void add(String s) {
if (s == null || s.length() == 0)
throw new IllegalArgumentException();
backingList.add(s);
}
// and some more slightly modified methods to complete List
}
The delegate keyword tells the compiler that any methods from List
Posted by Erik Engbrecht at 12:36 PM 1 comments
Labels: Java, programming, Python, Scala
Tuesday, August 14, 2007
Business Engagement and IT Project Failure
CIO.com recently ran an article by the CIO of GE Fanuc regarding "functional engagement" (i.e. "the business" or more commonly "the users") and project failure. Michael Krigsman later posted a more succinct summary on his ZDNet blog. Here's a even shorter version:
- Make sure a single business-side has significant capability, responsibility, and authority for project success.
- Don't short-circuit important parts of the project
- Make that person understands the "laws of IT" and defends them to his peers, subordinates, and superiors
Enterprise platforms like Siebel, Oracle and SAP are not intended to be heavily customized. When going from a niche, custom application to Siebel, you need a strong functional leader to push back on every “Yeah, but” statement. They must start at zero and make the business justify every customization. Saying “no” to customization is bitter medicine for your business partners. They will make contorted faces and whine ad nauseum. But it is for their own good.Let's think for a moment. Your customer (internal or external) wants to spend millions of dollars implementing a CRM (or ERP, PLM, etc.) package. Earlier, it went to the trouble of building one from scratch. That probably means it considers CRM to be an extremely important part of its business, and it expects to derive a competitive advantage from having a shiny new system. The best way to be competitive is to copy what everyone else is doing, right? Also, repeatedly receiving "no" as an answer will really make your customer want to take an active role in the implementation, right? Hmmm....somehow I don't think so. Introducing a strong impedance mismatch between the organization and the software it uses is failure. Standing in the way of innovation is failure. Mr. Durbin wants you to fail. There is actually a simple, albeit occasionally painful, solution to this problem: don't buy an off-the-shelf application that neither meets the business's requirements nor can be cost-effectively extended to meet them. First, you have to understand your business processes and requirements. I mean really understand them, not just understand the official process documentation that no one follows. All those winces and "yes buts" are requirements and process details that absolutely must be understood and addressed. Second, you do a trade study. This is a key part of systems engineering. Replacing enterprise systems is expensive, often prohibitively expensive, so do a thorough analysis. Take some of your key users to training sessions and write down every wince and vaguely answered question, because those are all either issues that will stand in the way to delivering value or will require customization. Finally, keep your pen in your pocket. Don't be tempted to write checks, buy licenses, and sign statements-of-work before your really understand the product. Just ignore those promises of discounts if you get a big order in before the end of the quarter. The next quarter isn't that far away, and the end of the fiscal year may even be approaching. The discounts will reappear then. Instead, make sure the vendor really understands the requirements and business process, and structure any contracts in a way that they must be met or the vendor will face significant penalties. It's amazing what comes out of the woodwork when you do this. All of a sudden that 3x cost overrun from the original projection is sitting right there in front of your eyes in the form of a quote, all before you've sunk any real money into the project. The purpose of engaging "the business" in an IT project is not to create a personal shield for all the deficiencies in the system you are deploying. It is to make sure you identify those deficiencies early enough in the project cycle to avoid cost and schedule overruns. Sphere: Related Content
Posted by Erik Engbrecht at 10:45 PM 4 comments
Labels: innovation, IT, management
Friday, August 03, 2007
Minimal Software Development Process
It's not uncommon for me to find myself in debates regarding what constitutes a sufficient software development process. On one side, there are the Agile folks who argue that code-and-fix, with user representatives determining what should be fixed. Of course they have lots of rules to regulate the code-and-fix, some of which are quite sensible and some of which are quite dubious, to make it appeal to closet process engineers. On the other side you have old-school developers who believe in such rarities as requirements signed in blood and requiring human sacrifice to alter. Ok, so perhaps I'm exaggerating a little bit. But that's how it often feels. So I'm going to propose my own process that is every bit as simple as what the Agile crowd pushes while being more all-encompassing than traditionalists. Here it is:
- Define the problem
- Define the solution
- Apply the solution
- Validate the result
- Develop requirements
- Design and Code to the Requirements
- uhh....Test?
- Customer Acceptance Testing
- We need to rollout a corporate standard ERP system.
- We need to web-based foo tracking database accessible to the entire corporation.
- We need an automated workflow for the bar process.
- My old college roommate is an ERP salesmen and wants a new boat
- We have a ton of foo, but no one really knows where it is or if it's being used. So we keep on buying more foo, even though we probably have enough. The problem is when we find so foo, the people with the foo always claim that they need all of it, even though often times they clearly aren't using it. We have some data, but it's massive and impossible to interpret. We need a way to find unused foo and prove that it is unused so that we can transfer it where it is needed.
- Some cowboys in department X keep on ignoring the bar process. They think they are heros because it saves time and money upfront, but really they just end up creating costly, time consuming problems down the line (for me). I need a way for force them to follow the bar process, but it can't be too hard otherwise they'll convince upper management to let them ignore it.
Posted by Erik Engbrecht at 10:10 AM 2 comments
Labels: IT, Software Engineering