« April 2004 | Main | June 2004 »

May 27, 2004

When Only An Example Will Do

Listen to this articleListen to this article

Ever waded through seemingly useless JDK JavaDoc screaming "I know getBlah() returns a Blah but what do I actually do with one once I have it?! How do I use the swags of java.io classes? And what in the world would I ever want a StreamTokenizer for?

So maybe you're a smarty-wishbone-legs and know everything there is to know about using the JDK APIs but, there's always something new to learn.

Sometimes forums and newsgroups can be a great help but more often than not I don't feel like wading through 18 pages of discussion to find the answer. Sometimes I just want a succinct example.

Enter the Java Almanac. I've found it to be a good source of JDK examples. It generally seems to be pretty up-to-date with new examples added all the time and is a great starting point for developers who are new to Java and struggling to come to grips with the vast number of APIs.

May 26, 2004

Shake The Etch-A-Sketch

Listen to this articleListen to this article

Recently I've been treating my ideas as if they were drawn on an Etch-A-Sketch. A deceptively simple concept that has helped me let go of ideas that were leading nowhere but to which I had an emotional attachment that prevented me from considering anything else. Just shake and you're back with a clean slate. :-)

Business Rules Fallacy #1

Listen to this articleListen to this article

Remember the good old days when Crystal Reports was going to save the world? That's right. By about now (2004) every user on the planet would be writing up their own ad-hoc reports straight from the database. All they needed was the database schema and away they would go.

What? You mean your business users aren't doing this? Really? Say it ain't so!

No, the truth is it never really eventuated the way we (the IT industry) had envisaged. End users just don't get fully normalised data structures. FWIW, most people I work with probably don't understand why 25,000,000 + NULL == NULL so how did we ever expect users to? Oh and let's not forget the IT manager who has enough knowledge of the system to be dangerous. He has a big picture of the database schema on his wall and knows just enough SQL to build queries that do multiple table scans over the millions of rows of inventory data, causing the DBMS to not so quietly tell every other use of the system to please get nicked :-) The plain fact is that writing reports typically requires as much help from IT infrastructure as to make it an IT task.

So now that Business Rules are looking more cylindrical with that silver sheen each day, some of us naively believe that our so called "Business Users" should be able to code up/modify rules for direct inclusion into a production system all by themselves. To me, this is an even bigger problem than reporting.

All the problems that plague end-user reporting apply. Users don't understand our lovely, normalised, domain model. They surely don't understand why they get a NullPointerExceptions when adding numbers. And when it comes to knowing the difference between and and or you can forget it!

What's worse is that Business Rules are used directly by the application to "reason" on appropriate behaviour. By comparison, with the exception of the table scan problem and of course any bad decisions that might be made based on incorrect data, reporting seems rather innocuous.

Now, if I said to the man (and in this case yes it is a man) who writes the cheques, hey how about we don't test any of this code before we put it into production, I'd get the sack immediately. And quite rightly so I might add. Application components interact in subtle and non-obvious ways that necessitate large-scale unit/functional and integration testing. Business rules are no different. Actually they can be worse. We have many years of collective experience managing essentially procedural languages such as Java, C, C++, etc. Most developers I know think a lisp is a speech impediment and surely wouldn't know a prolog if they tripped over one :-)

Just like with reporting, we can try going down the path of writing views and buulding neato tools to try and make this stuff more like human readable languages and structures but when it comes down to it, like reporting, business rules require about the same (if not more) intervention from IT departments when end users write them as when the developers themsleves write them. The "best" tools in the world won't solve real problems with allowing end users the ability to directly modify business rules. I mean, glasses aren't much good if the patient is blind.

Business rule maintenence is and should be an IT responsibility. However, the rules must be representable in a way that makes it easy for an end user to verify the translation from written/spoken languages. Appropriate use of the lower-level JRules or OPSJ languages makes this a reality without the need for tools to render rules from/to "plain english". With a tiny bit of coaching, our business users are finding they can understand the rules sufficiently to know when we've made a mistake. In fact this iteration, our business rep has indicated he'd like to try his hand at writing one. No points for picking the irony in that.

May 19, 2004

re: Appeal To Authority

Listen to this articleListen to this article

I admit to having been influenced greatly by much of Martin Fowlers writing over the years. It's always thought provoking at the very least but this entry on his bliki made me do a "What The?"

"There is no way I (or any other software loud-mouth) has that much influence."

There is no way I can believe that he actually believes this. Clearly, people such as Martin do have that much influence. That's why they are employed by organisations such as ThoughtWorks. That's why they draw huge crowds at conferences. That's why developers the world over buy their books.

So maybe we could re-phrase that sentence? Perhaps it should read:

There is no way I (or any other software loud-mouth) should have that much influence.

But the fact remains that he (and other software loud-mouths) do and as a consequence lots of people will blindly do exactly what they say. The operative word here being blindly.

He is quite right though. People are selective when appealing to authority and people as a whole should take more responsibility for their own thinking.

May 12, 2004

Encapsulation vs Hiding

Listen to this articleListen to this article

It's becoming dull explaining the difference between Encapsulation and Hiding. Maybe universities need to teach English as part of their computer science courses?

v. encapsulated, encapsulating, encapsulates
v. tr.

1. To encase in or as if in a capsule.
2. To express in a brief summary; epitomize: headlines that encapsulate the news.

v. hide, hidden, hides
v. tr.

1. To put or keep out of sight; secrete.
2. To prevent the disclosure or recognition of; conceal: tried to hide the facts.

Encapsulation does not mean that my classes need to have a high proportion of private methods to demonstrate good OO. It means the methods and data on a class should be cohesive - share and participate in common purpose and responsibility. Encapsulation has little to do with making all fields private and adding respective getters and setters.

A class has certain well defined and cohesive responsibilities - think normalisation (1BNF, 2BNF, etc.) but for classes - and those responsibilities are, by in large, public. Read encapsulation. The implementation of those responsibilities is hidden. The fact that some of the implementation lies is private methods is incidental and occurs for clarity and maintainability. Too many private methods is often an indication that a class has too much or wildly varying responsibility.

May 03, 2004

Business Rules Goodness - Continued

Listen to this articleListen to this article

Continuing with the business rules examples thread, James looked at the examples of using logical to achieve a "compensating retraction" and asked me "so that's all very well and good but what happens if I'm not asserting a fact? What a happens if instead, I'm sending an email to my broker?"

My first reaction was that this is a separate problem. The fact that I was potentially sending an email based on the SellOrder seemed like an implementation detail that I didn't want cloduing the simple fact that, under certain conditions, I wanted to indicate my desire to sell.

After a little discussion, we came up with the following solution which, IMHO, elegantly maintains the atomicity of rules and the separation of concerns. I've taken some liberties with the syntax and I've not actually tried this in JRules but it does serve to demonstrate the concept:

rule BrokerInformedOnNewSellOrder {
    when {
        ?order: SellOrder();
        not SellOrderActive(order == ?order);
    } then {
        sendMessage("Sell stock");
        assert SellOrderActive(?order);
    }
}

As the name suggest, this simply informs the broker on any new SellOrder. The key here is that we introduce a new fact SellOrderActive. If we see an order that isn't active, we'll send a message and assert that it is now active.

(NB. sendMessage() isn't syntactically correct for JRules but you get the idea.)

Next we need to know what to do if the SellOrder is retracted (either explicitly or implicitly):

rule BrokerInformedOnRetractionOfSellOrder {
    when {
        ?active: SellOrderActive();
        ?order: SellOrder() from ?active;
        not SellOrder(?this == ?order);
    } then {
        sendMessage("No longer sell stock");
        retract ?active;
    }
}

This rule says that anytime we think we have an active order but the SellOrder itself no longer exists, retract it and send another message to the broker indicating that we no longer wish to sell.

As usual, I'll re-write this rule in JESS. Thanks go to the creator Ernest Friedman-Hill for clarification on the exact syntax:

(defrule broker-informed-on-new-sell-order
?order <- (sell-order)
(not (sell-order-active ?order))
=>
(sendMessage "Sell stock")
(assert sell-order-active ?order))

(defrule broker-informed-on-retraction-of-sell-order
?active <- (sell-order-active ?order)
(not ?order <- (sell-order))
=>
(sendMessage "No longer sell stock")
(retract ?active))

May 02, 2004

Planned Obsolescence Is Poor Design

Listen to this articleListen to this article

Or, interfaces are no excuse to build broken software.

I've ranted about this previously and I see the problem recurring so often I feel compelled to have another go but this time from a slightly different perspective.

Lets start by agreeing that it's best not to be constrained by someone elses API. They introduce constructs and ways of "doing stuff" that don't conform to my ideal. Assuming we do agree, it then follows that mocking out someone elses API is not only a bad idea but usually plain pointless.

Enter javas interfaces and C++ pure-virtual classes. They are truly wonderful things. You don't have to write any "real" code just to have one. No code means no tests required. And best of all, they provide functionality just the way you want it. They're the ideal black box. Not as ideal but potentially almost as good, are the methods themselves. Even concrete implementations can and should provide me the ideal functionality.

So what do I mean by "ideal"? Well, say I'm implementing a bit of code and all of a sudden I realise "doh! here I'm going to need to do X" where X is conceptually simple but implementation complex functionality. I have a few choices: I could go straight into implementing X; or; I could choose to "pretend" that X is actually implemented exactly the way I want it to be.To achieve this I can either add a method to an existing class or I could introduce an interface. Either way, the important point is that I want this thing to do what I need in the ideal way. I don't care that it doesn't exist yet. But I don't want my code polluted with knowledge of how it's actually going to be implemented. I just want to call it and have it do it's magic.

So we "stub" it out and push on. Eventually we finish our lovely piece of code. We stand back and it looks good. It's readable. It's understandable. But there's still that X we haven't yet nutted out. No problem. We can still test the class using mock objects so we can still maintain the illusion that X actually exists.

At some point we will feel the pain. We need to actually implement X so it can be deployed as part of the application. So now let's say that X really has the potential to be stupidly complex but for now we don't actually need to solve every possible case. We create a SimpleX or DefaultX or my much despised XImpl class. What we don't do is create a MockX class simply because it's "not the real thing". What does "not the real thing" mean anyway? It's there. It's working code. It does what I need. It may not be as flexible as I want it to be but it's NOT A MOCK!

And this is where the title of the entry hopefully becomes apparent.

As far as I'm concerned, every line of code I write IS PRODUCTION CODE. Period! If the customer was happy with the functionality of the system, they could disband the team and deploy the application right now and it would be production code. Let me repeat. EVERYTHING IS PRODUCTION CODE.

Code I write is rarely written with the intention of one day throwing it way! It's a production implementation of the limited functionality that I need this minute. If I need more functionality at some point, I'll add it. This may require me to intoduce more abstractions, more interfaces, more methods that potentially do as much as required to get the job done. I'm pushing the unimplemented bits out as far as needed so that my overall design continues to adhere to my ideal. This i's not to say it won't or can't be binned at some point but that occurs as a consequence of an evolving application. It happens to any piece of code whether I actually decided upfront that it was likely to be binned or not.

There is always The Law of Leaking Abstractions to consider. But. by way of the obligatory analogy, just because there is the chance someone might run into my car, shouldn't prevent me from actually driving. It just means I need to be vigilant and aware of what's going on around me when I do so.

And because I'm sure I won't have made any sense whatsoever up till now, I'll confuse you even more with a real example.

Take pico container. Hold for the moment your predjudices on IoC/Dependency Injection/etc. That's irrelevant to the point. The point is that pico container provides a very simple implementation of an interface. No bells, no whistles, no loading configuration from files. Everything is configured by code at run-time. But it does the job. It's just not as flexible as maybe I'll need down the track. But if it''s all I need right now, then it's, well, all I need.

Then I decide that what I need is something that can be configured from an XML file. Do I a) throw away all of pico container because it doesn't do what I need; b) cut and paste the pico container code into a new class, re-using as much as I can, or c) just simply add the new functionality (in this case by way of nano container)?

I'll let you be the judge but anyone who chose to have written pico container as throw away code because they knew one day they'd actually need to load configuration from files and therefore it was throw-away code deserves to be forced to program in binary for the rest of their natural life.

(BTW, I didn't write pico or nano container I'm just using them as part of an example. That's why it's called an example)

Yes, it is true that things aren't always ideal. But this is very rare in my experience and will only occur at the hopefully thin boundaries between your code and someone elses API! If this isn't the case, then WTF are you doing? It's your software. You created it. How is it that it doesn't at least pretend to do exactly what you want?

FWIW, This discussion is really a demonstration of how I choose to interpret XPs do the simplest thing that could possibly work.

I'll have to start blocking email from myself now!

Listen to this articleListen to this article

From: simon@redhillconsulting.com.au
To: simon@redhillconsulting.com.au
Subject: Re: Question
Date: Sat, 1 May 2004 09:12:29 -0400

Here is my icq list.
 
+++ Attachment: No Virus found
+++ MC-Afee AntiVirus - www.mcafee.com
  archive.zip

May 01, 2004

The Best Approximation Of The Least Crappy Solution We Could Possibly Build

Listen to this articleListen to this article

We (all?) strive to build great software but how many of us look back on code we wrote even as recently as 6 months ago and still think "wow that's some great software"?

Open up that CVS client and download some source code you haven't looked at for a while. Make sure to start with the project you thought was the "best thing you'd ever written." I'd be very surprised if your thinking on software development hasn't changed sufficiently in that time to make you whince when you see the "cool" things you were doing back then.

I look back on videos of me performing Aikido technique and the same thing happens. "Yikes!" I think to myself "I can't believe I used to think that was good! And to think I was teaching others that at the time!" My students learned long ago not to treat anything I say as gospel. To critically analyse what I'm teaching and understand it for themselves, not just parrot what I say. They know full well that it will probably change after a long weekend of contemplation.

We grow, we learn. Our thinking changes. In some cases it swings back and fourth like a pendulum trying to find that "sweet spot". So don't get down on others because they don't produce the code that you'd like. Similarly, don't be perterbed when your mentor/coach/teacher suddenly starts explaining to you, with all the enthusiasm of a child with a new toy, that yellow is the new brown.

Because we don't live in an ideal world, when it comes down to it, at any point in time we really are just doing the best approximation of the least crappy solution we could possibly build.

More Business Rules Goodness

Listen to this articleListen to this article

I've always loved the idea of rule-based applications but never really had the opportunity to build one. And I have to say I'm having a lot of fun using a rules engine on this project. Since we dumped the BAL in favour of the IRL in JRules, productivity has sky-rockected. FWIW, TDD and rules-engines are a perfect match (a fact I'll blog more about in the coming days). I'm in geek heaven! About the only thing I wish I had now was an IntelliJ plugin (like the AspectJ one).

So anyway, my intention is that step-by-step, I'll try and document my progress starting with a little of what I discovered today by way of a rather contrived example:

rule MessageIsGeneratedOnSignificantStockMarketIndex {
    when {
        ?index: Index();
        evaluate(index.value > 3000);
    } then {
        assert Message("Today the stock market rose above the psychological 3000 barrier");
    }
}

This example says that whenever the stockmarket index rises above 3000, we assert that it was a significant event. (Actually JRules has some other nifty stuff to do with associating timestamps with events but I'll blog about that another time.) The important thing to notice is the assert keyword. This asserts a new fact into the "knowledge base". This new fact will remain "forever" or at least until another rule retracts it.

Simple assertions such as this are great when you know that the asserted fact will always be true independent of the triggering condition. In the example, it will always be true that at some point in time, the stock market index rose to a significant level, even if the index drops again.

But what if we have a fact that only holds while the condition holds? In such a case, we'd need a "compensating" rule to retract the fact when the condition changed. This could get quite ugly. Thankfully, JRules provides a neat solution:

rule SellOrderRaisedWhenStockValueReachesMinimum {
    when {
        ?stock: Stock();
        evaluate(?stock.value >= 30);
    } then {
        assert logical SellOrder(?stock);
    }
}

This rule says that we will place a sell order for any stock that rises to 30 dollars. The key difference here is the use of the logical keyword. This tells JRules that the assertion onlyholds while the triggering condition holds. That is, while the stock value is at least 30 dollars, the sell order remains. However, if the stock value drops below 30 dollars, JRules will automatically retract the fact for us. What's even better is that if the assertion of the SellOrder causes other rules to fire and therefore assert more facts, all those that were declared as logical will all be retracted as well. How cool is that?!

In our application, probably >99% of all rules will use the logical form of assert. This allows quite complex interactions between essentially independent rules.

If you find yourself having to structure your rules with priorities and worrying too much about the interactions between rules, it's likely your individual rules are doing too much. Ensure your rules should be as atomic as possible. Seperate "inference" rules from "do stuff" rules". And don't be tempted to simply change the state (ie property values) of existing facts. Instead, always assert new facts (as we have done in the examples above).

I thought I'd also show you the same rules using JESS.

(defrule message-is-generated-on-significant-stock-market-index
(index (value ?value)) 
(test (> ?value 3000))
=>
(assert (message (text "Today the stock market rose above the psychological 3000 barrier"))))

(defrule sell-order-raised-when-stock-value-reaches-minimum        
?stock <- (logical (stock (value ?value)))
(test (>= ?value 30)) 
=>
(assert (sell-order (stock ?stock))))

You'll note that in JESS, the logical keyword is associated with the condition (or LHS) rather than the action (or RHS).

In many ways JESS provides a richer environment than JRules but I admit the syntax is less obvious to novice users.