30 June 2011

IceFaces (JSF) issue with PopupPanel and cancelling

Soem of you might have had the issue that a popup panel would not reset it's values after you hit the cancel button. Typically the cancel button would have an immediate="true" flag to discard any validations.

As a side effect, though, it would not update the values of the components inside the form and the next time the panel is shown the values would remain the same (even if you've cleared them in the backing bean).

There are two solutions for this issue:
1. One is to bind the components to the backing bean using the binding attribute
2. Another is to use the code below

    /**
     * Return the parent form of the given component.
     * 
     * @param component
     * @return the parent form or null if no parent form is found.
     */
    public static UIForm getParentForm(final UIComponent component) {
        UIComponent parent = component;
        while ((parent != null) && !(parent instanceof UIForm)) {
            parent = parent.getParent();
        }
        return (UIForm)parent;
    }

    /**
     * Recursively traverse the {@link UIForm} and clear the data of all the components in it
     * 
     * @param uiForm the {@link UIForm} to clear
     */
    public static void clearSubmittedFormValues(UIForm uiForm) {
        clearSubittedFormValuesRecurse(uiForm);
    }

    private static void clearSubittedFormValuesRecurse(UIComponent uiComponent) {

        if (uiComponent instanceof UIInput) {
            // in case this is an input then clear it's value and mark it as "not submitted"
            UIInput uiInput = (UIInput)uiComponent;
            uiInput.setSubmittedValue(null);
        }

        // check all the immediate children of this component
        for (UIComponent component : uiComponent.getChildren()) {
            clearSubittedFormValuesRecurse(component);
        }

        // check any facets (in case this is a PopupPanel for example)
        for (Entry facetEntry : uiComponent.getFacets().entrySet()) {
            clearSubittedFormValuesRecurse(facetEntry.getValue());
        }
    }


I find the second solution somewhat easier and more clean, otherwise you would need to substantially modify the logic of your bean.

29 June 2011

Law of Demeter (LoD) or Principle of Least Knowledge

Have you heard of this principle? In case you haven't here is what I know about it.

Short intro

The whole idea is to make objects aware only about the properties of object they interact directly with. Unfortunately the reasons are not explained in very good detail and I've found only a few good examples of that. I will try to illustrate this issue with a simple example.

The simple example
Suppose we have two relatively independent entities such as a customer and a seller. They could easily be part of different libraries or modules in real life applications.

Suppose we handle a transaction. The customer would have a credit card and the seller would have a laptop (the item he is selling). Now to illustrate where we might have a conflict with the LoD principle :

class Seller{
    Account account;
    public void executePayment(Customer customer, int sumToWithdraw){
        // assume we get some status of the withdrawal in the form of a boolean
        boolean isWithdrawn = customer.getCreditCard().withdraw(sumToWithdraw);
        if(isWithdrawn){
            account.addSum(sumToWithdraw);
        }
    }
}

Notice the issues (aside from my bad choice of variable naming)? The typical LoD principle violation is the presence of more than one ".", e.g. the call an inner object.

Why? Why is this an issue
  • The first and most important problem is that the Seller class should not be interested in the specifics of the Customer class. If the customer had a method "withdrawMoney()" then the inner implementation would not matter and you would achieve better decoupling. Better decoupling would mean that you'd be free to change the way the user pays (via cash, via check) and this would not reflect the users of this class. Otherwise you would need to modify the Seller class each time you need to change the way of payment.
  • Another issue is the fact that you don't really know the specifics about the credit card manipulations in the Seller class. What if, in order to make a payment, the Customer had to firstly make a check about his current balance? You'd need to know this in order to make withdrawals from the credit card. Not only is this code not supposed to be in the Seller class, but it would mean potential duplications (in case other classes also use the same class). And with duplications comes the possibility of bad code change propagandation.

Solution

The solution is quite simple.

class Seller{
    Account account;

    public void executePayment(Customer customer, int sumToWithdraw){
        // assume we get some status of the withdrawal in the form of a boolean
        boolean isWithdrawn = customer.withdraw(sumToWithdraw);
        if(isWithdrawn){
            account.addSum(sumToWithdraw);
        }
    }
}

class Customer{

    CreditCard card;
    Cash cash;
    Check check;

    public void withdraw(int funds){
        if(cash.hasMoreThan(funds)){
            cash.withdraw(funds);
        } else if(card.hasMoreThan(funds)){
            card.withdraw(funds);
        } else {
            check.write(funds);
        }
    }
}

Now only the Customer class is aware of how the funds are extracted and handles any potential issues with them. The seller is completely unaware of what the logic behind this transaction is. This would mean the Seller would not be affected in any case if the code changes and it would also not have to know how the logic of extracting the funds should look like in the first place.

Side note

I personally believe that the measurement of how many dots a line has is not very accurate in terms of determining if there is a violation of the LoD. In some cases the logic should be able to go deep into the nested objects, but we should always be cautious to not tangle the different objects too much and also place the right logic in the right place.

This principle is more of an abstract idea, than an arithmetical rule.

References

Article in Wikipedia

Article by Dan Manges

28 June 2011

ToughWorks and company image

I've come across Martin Fowler's article on the three pillars ThoughWorks is built upon as a company. It's a very interesting article, I'd recommend everybody to spent some time reading it.

It made me think about what we do here in Bulgaria in the field of software development and consulting. Actually company culture as a whole.

In my short career I've worked for no less than 4 companies - large and small, purely Bulgarian and foreign. I've seen some attempts to enforce the company vision upon the employees, especially in large companies where the management likes to shorten the distance and make the whole company a single family.

Personally I think that a well motivated employee, that strongly believes in the company aims would have a massive boost to his/her productivity and vision. It's really very logical - we always tend to give our best when we personally believe in what we do.

Unfortunately it is quite hard to make people believe in something, especially if these people are intelligent, well educated professionals who like to think for themselves. It is even harder when this goal is not sincere - managers often tend to speak about ideals they don't personally believe in.

To make a long story short, what I think is that such an ideology should be very simple and easy to agree with. It must come from the management not only as an idea, but as personal goal. If a manager is personally aiming to achieve a certain idealistic goal it would make the job of communicating this ideal much easier. The goal itself must be very simplistic and idealistic, such as the three pillars mentioned in Martin Fowler's article. E.g. it would be really easy to find people that like to not only make money, but do something the right way and for the right purpose.

The idealistic goals of a company are something that makes people commit to something more than the usual 8 hour shift. It would make them more committed, more responsible and more interested in what they do.

This is a lesson most of the foreign companies have taught me, but few of the Bulgarian managers have been able to fully comprehend and communicate. It is a personal trait that I believe each manager should have and if not - should try to develop.

17 June 2011

Good warm up question for an interview

If you'd like to get the developer on the other side of the table to think in front of you ask him this very simple programming riddle:

How would you exchange the values of two variables without using a third one?

It really goes to show how a person thinks. Some people would start thinking of very complex solutions. other would freeze because the question seems to be very simple and the expectations of a quick answer would make them stall.

A quick tip for those of you who haven't thought of the answer yet - it involves 3 operations of addition and subtraction.



a = 5
b = 8

a = a + b
a = 13
b = 8

b = a - b
a = 13
b = 5

a = a - b
a = 8
b = 5

08 June 2011

IE7 and IE8, relative width (100%) and overflow


Another day, another possibility to see how different interpretation could IE have regarding a web page. Both Chrome and Firefox (and I am sure most other browsers) handle this issue properly, but IE has it's own idea about everything.

The issue

Suppose you have a layout with relative width (say a table with width of 100% nested in another that has a width of 50%) and you have a form field (text area, text box, etc.). If you were to enter an extremely long text most browsers would split the word, but IE wont. Instead it would expand the table to fit in the text.

Strangely this would sometimes even happen to separate words (not one long word).

The solution

Applying table-layout:fixed to all tables in the chain until the first non relatively sized container would fix the issue. I saw some suggestions to use the word-wrap: break-word; style, but in my case it was unnecessary.

Thanks to:
fplanque: dev blog, 456bereastreet.com and stackoverflow (as usual).