The Tipping Point: Opening the Fudgates

We all have a tipping point. It is just that some people reach it sooner than others.

The Linux market is growing at 26% per annum, and we all know that more and more people are using tools like Open Office (32 million downloads), Thunderbird, and Firefox, and more and more people are using open standards like HTML and XML. But is there a tipping point at which people will suddenly move en masse to abandon outdated proprietary software and proprietary standards? Is there a point at which some hidden scale will swing in a new direction and users will begin choosing open source and open standards over proprietary software? Will there be a great grinding of wheels and squeaking of cogs as the world of software development seesaws away from proprietary solutions and toward freedom?

Right now, the major thing holding back open solutions are heavily sponsored outpourings of FUD: Fear, Uncertainty and Doubt. The irony, of course, is that the fudgates have been opened by people who are themselves fearful, uncertain, and doubtful.

The Freedom to Choose

Most people understand that open source and open standards provide users with freedoms that they can’t get from proprietary software. For instance, we like the following freedoms:

  • The freedom to choose a platform. If we choose a particular tool, computer language, or document format does it lock us into one platform? If we choose a proprietary solution then it probably does lock us into a platform, but if we choose open standards, then we usually get to choose our platform.
  • The freedom to choose a tool. Can we take our documents and use them with another tool if we don’t like the tool we are currently using? For compilers, this means writing to a standard like Java, C, Python, Perl, or C++, all of which work with multiple products from multiple companies. For word processing, this means using a standard such as HTML that can be read or edited with multiple editors.
  • The freedom to fix bugs, add features, or change features. In other words, did it come with source, and can we compile it? With open source, we always get the source and can recompile at will; with proprietary solutions, we usually don’t get the source and have to wait months or years for fixes.
  • The freedom to ship a product when the users need a new version. Who dictates product cycles? The manufacturer or the user? Are releases all about maximizing profits, or are they about meeting the needs of users? This involves both the freedom to ship small incremental bug fix releases, and the freedom to hold off releases when a product is not ready to ship. If a product is released as open source, then you can make a new build whenever you want and often there is no penalty for the developers in waiting until the product is ready.
  • The freedom to understand. We want to understand a product, to see how it was designed and therefore how best to use it. But often we can’t understand how a product works because there is no source code, and the documentation is bad. This is particularly irksome when working with developer API’s and runtimes that don’t ship with source. Proprietary solutions are usually closed solutions that ship without source.

As a developer, you know you are using an open solution if you are free to pick your development platform. If a team is working on a project, and each member of the team is free to work in either Linux or Windows, then the solution is open. The air is fresh. Users are free. But if one must work exclusively on either Windows or Linux then the solution is not open, the doors are locked, the air is fetid and close.

The Ties that Bind

Everyone can see the value in open source and open standards, open solutions are preferableto getting locked into a proprietary solution that benefits only the owners of a standard. If all this is so obvious, then why does anyone ever choose proprietary software? Why didn’t we reach the tipping point and choose freedom years ago? The answer, of course, is two fold. People choose proprietary solutions when:

  1. they are locked into them.
  2. the proprietary solution is significantly better than any open solution.

Everyone understands point one. We all know what it is like to be trapped inside a proprietary standard. You want to work on a particular platform but you can’t because you are locked down. You want to use a particular compiler or a particular editor, but you are locked into a proprietary standard. You want to fix a bug or add a feature, but you can’t because you don’t have the source. You want to understand how something works, but you can’t because you don’t have the source.

The Tipping Point

Despite the feel of its onerous and cloying fingers on their flesh, only hard core individualists will drop a proprietary solution in favor of an open solution just because of lock-in. Especially in the business world, people tend to be too pragmatic to choose freedom just for the sake of freedom. But if an open solution is as good as a proprietary solution, and especially if the open solution is free, then many will choose the open standard over the proprietary solution.

In the final analysis, the tipping point will be reached when a significant majority of open solutions compete with proprietary solutions in terms of quality. The question, of course, is just how far we are from that day. Has it possibly arrived already? Is it just around the corner?

Already Open Office is competitive with the big proprietary office suites. And Firefox and Mozilla are more than a match for proprietary browsers. Linux is a better server than any proprietary solution except possibly some of the biggest UNIX servers. Linux is frequently the best development platform, especially for multi-tier or network based applications. Even the beleaguered Linux desktop is fast becoming competitive with even the best in that field, such as the beautifully designed Mac desktop.

Linux still lags behind the Mac in terms of Multimedia, but the emerging NVU web authoring system is showing signs of potentially giving Dreamweaver a run for the money. For many people, Dreamweaver is the last tool binding them to proprietary software. But if NVU reaches maturity, then even Dreamweaver the last great freely chosenbastion of proprietary software, will at last topple. (Since Dreamweaver works with open standards, I don’t really care that it doesn’t ship with source, what bothers me is that it doesn’t run on Linux.)

What will happen on the day day when you boot up a Linux box and suddenly realize that it has solutions that are equal or superior to proprietary solutions in all the major application areas? Will that be enough to tip the scales and cause a rush to open solutions? For many people, such as myself, that day has already arrived. For others, the day is coming soon. But there are those who don’t want to see that day dawn. They will do anything to stop it.

The Fudgates Unleashed

Defenders of lock-in love to open the fudgates and let rumor and innuendo flow. They claim that people who like open solutions are:

  • Trying to ban the sale of proprietary software.
  • Are attacking the free market system.
  • Are, and here is the very pinnacle of irony, trying to limit your freedom to choose.

But of course truly open solutions do none of these things. They have only one purpose: to give you the freedom to choose.

If you are working on a project with a team, and you have to boot up a particular OS to get any work done, then you are locked down. You are pinned to the wall and the person who has you pinned is leisurely tossing darts in your direction to pass the time from inside his home built on stilts above the fetid swamps downstream of the open fudgates.
If, on the contrary, you can work on the project in either Windows or Linux, then the solution is open.

Rather than trying to prevent you from using any particular platform, supporters of open solutions want you to have the right to choose. If you want to choose Linux, then fine. You are working with an open solution. Go ahead and do what you want. And if you want to use Windows, that’s fine too, you have that right also. This is freedom. Any solution that locks you into either the Linux or the Windows platform is just an elaborate con job dressed up as technology.

Clearly open solutions aren’t about banning anything. Rather than attacking the free market system, they just make it more flexible, more free. Open Solutions aren’t about limiting freedom, they are about giving you more freedom.

The moment you hear someone talking about how free software is more expensive than consumer based software then you know the fudgates are open. When they start talking about how proponents of open solutions are trying to limit freedom, then you can feel the ground under your feet tremble because the sludge is pouring through the floodgates at such high volume as to shake the very foundations of the earth. That’s when you know the FUD has been unleashed upon an unsuspecting public and everyone is about to take a very smelly bath.

Summary

If you are quiet, and sit very still, you can feel the fresh air against your skin. Change is in the air. Not tomorrow, but soon. If we as developers and computer users can still select our own destiny, then the only real questions left are whether:

  • Open solutions will be released primarily as free software, thus ending the age when people pay money for software.
  • The big software firms will at last convert entirely to open source and open standards. As a result, they will belatedly allow paying customers the freedom to choose not a hobbled proprietary product, but a cross-platform and multi-tool standard.
  • Lawmakers will, at the last possible moment, awake from their self induced slumber and break up the big proprietary behemoths, thus allowing free competition.

The people who are creating open solutions don’t care which path is chosen. They are working only to ensure that open solutions arrive come FUD or high water. But still I wonder: will something be done to bring fairness back into the paying software market so that free market firms offering open solutions can compete against the giant proprietary behemoths who tramp the earth like aging dinosaurs looking for a fight on Skull Island?

J2EE Design Strategies Part IV

Enterprise Java Beans

Fine-grained vs. Coarse-grained Entities

One of the design patterns discussed by the J2EE tutorials from Sun is this topic of fine-grained vs. coarse-grained entities. The issue here is one of client access. Generally, you want to keep the amount of round-trips to the application server as small as possible. Shuttling data over a network connection in a distributed application is an expensive operation in terms of time. In general, you should avoid creating many small entity beans and accessing them directly from the client. For example, if you have a customer entity in your application, the customer likely has an address (or many addresses). You should not create an Address entity to handle addresses. Instead, you should create an Address dependent object (also known as a value object). A dependent object is a simple Java class that encapsulates information and typically consists of only accessors and a constructor.

To access a Customer’s address, the customer entity has a method that returns an Address dependent object to you. If Address was modeled as an entity bean, you would have to access it through its remote reference just as you do Customer. By passing back a dependent object, you can cut down on the number of remote method calls you must make (for example, for all the fields in the address). This is what is meant by coarse-grained objects.

Here is an example of a dependent object for address:

Listing 14: Example of an address value object

import java.io.Serializable;
public class Address implements Serializable {
    private String addr1;
    private String addr2;
    private String city;
    private String state;
    private String zip;
    public Address(String addr1, String addr2, String city, String state,
            String zip) throws ValidationException {
        if (zip.length() < 5 || zip.length() >10) {
            throw new ValidationException("Zip code format error");
        }
        this.addr1 = addr1;
        this.addr2 = addr2;
        this.city = city;
        this.state = state;
        this.zip = zip;
    }
    public String getAddr1() {
        return addr1;
    }
    public String getAddr2() {
        return addr2;
    }
    public String getCity() {
        return city;
    }
    public String getState() {
        return state;
    }
    public String getZip() {
        return zip;
    }
}

Dependent objects also provide a good place to house simple validation rules. In the example above, the constructor throws a ValidationException if the zip code is not formatted correctly. Note that all such code must appear in the constructor because there are no set methods (more about this shortly).

Another variation on this theme is to create bulk accessors and mutators. In this model, if you need to populate many of the fields of an entity, create a mutator that takes a value object as the parameter and make a single call, passing an instantiated value object. This way, you can make a single remote call instead of several.

Here is an example of a bulk accessor and mutator for Credit Card data.

Listing 15: Using bulk accesors and mutators

Credit Card Data class

public class CreditCardData implements Serializable {
    private String number;
    private String type;
    private String expirationDate;
    public CreditCardData() {
    }
    public CreditCardData(String number, String type, String expDate) {
        this.number = number;
        this.type = type;
        this.expirationDate = expDate;
    }
    public String getNumber() {
        return number;
    }
    public void setNumber(String number) {
        this.number = number;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getType() {
        return type;
    }u
    public void setExpirationDate(String expirationDate) {
        this.expirationDate = expirationDate;
    }
    public String getExpirationDate() {
        return expirationDate;
    }
 //-- more methods follow...
}

EJB using bulk accessors and mutators

public class OrderBean implements EntityBean {
    EntityContext entityContext;
    public String ccNumber;
    public String ccType;
    public String ccExpiration;
    public CreditCardData getData() {
        return new CreditCardData(ccNumber, ccType, ccExpiration);
    }
    public void setData(CreditCardData ccData) {
        ccNumber = ccData.getNumber();
        ccType = ccData.getType();
        ccExpiration = ccData.getExpirationDate();
    }
    //-- simple accessors
    public void setCcNumber(String ccNumber) {
        this.ccNumber = ccNumber;
    }
    
    public String getCcNumber() {
        return ccNumber;
    }

Immutable Value Objects

If you are using value objects (see the item above), you should ensure that they are immutable. Here’s why. If your value object is mutable (in other words, has mutator methods) and you pass a value object back from an entity, the client can call the setXXX() methods on the value object. However, the client is only changing their copy of the value object, not the values on the server. Because value objects are not remote objects, changes to the copy passed to the client will not be reflected on the server. So, to make sure this cannot happen, you should always make your value object immutable. If the user wants to make changes, they must create a brand new object instance and pass it back to the entity bean through one of it’s mutator methods.

Here is an example of changing the city of an address.

Listing 16: Changing the value of a dependent object

    Address a = ejbRef.getAddress();
    String newCity = "Atlanta";
    Addres newAddress = new Address(a.getAddr1(), a.getAddr2(), newCity,
            a.getState(), a.getZip());
    ejbRef.setAddress(newAddress);

Writing Proper Standard Methods for PrimaryKeys

This topic actually pertains to J2SE as well as J2EE. However, it is particularly important in the EJB context. Every primary key class must include both overridden equals() and hashCode() methods. However, creating these methods correctly is not a trivial manner.

equals()

To create a correct equals() method, you must adhere to the following conditions (taken from the J2SE specification):

  • It is reflexive: for any reference value x, x.equals(x) should return true.
  • It is symmetric: for any reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
  • It is transitive: for any reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
  • It is consistent: for any reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the object is modified.
  • For any non-null reference value x, x.equals(null) should return false.

Let’s investigate the implications of the above requirements. First, the method must be reflexive.

Reflexive

This requirement says that the object must equal itself. If you somehow violated this rule, then when you add this object to an unordered Collection, it would allow you to add it again. You generally shouldn’t have to worry about this property.

Symmetric

This property implies that two objects must agree with each other as to whether they are equal or not. This is most common when you override class, including some overridden nontrivial behavior, and want to still include an equality check with the parent class.

Consider the following class, representing an unsigned integer.

Listing 17: Example of a class with a well intentioned but broken equals() method.

public final class UnsignedInteger {
    private Integer uInt;
    public UnsignedInteger(Integer i) {
        if (i == null) {
            throw new NullPointerException();
        }
    }
    //-- broken equals()
    public boolean equals(Object o) {
        if (o instanceof UnsignedInteger) {
             return ((UnsignedInteger)o).uInt.equals(uInt);
        }
        if (o instanceof Integer) {
            return uInt.intValue() == (Math.abs(((Integer) o).intValue()));
        }
        return false;
    }
}

The problem with this class is that it is trying to interact with the Integer class. This violates symmetry because the Integer class knows nothing about this class, and will obviously never indicate that it is equal with any instance of an UnsignedInteger. To fix this problem, we need only remove the reference to the Integer class from the equals() method. In other words, this class should only try to determine if equality exists between two instances of this class.

Transitive

The third requirement states that is object a is equal to b, and b is equal to c, then a must be equal to c. Here is an example of a violation of this principle. In the listing below, we have created a simple immutable point class.

Listing 18: A simple immutable point class.

public class Point2D {
    private int x;
    private int y;
    public Point2D(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public boolean equals(Object o) {
        if (!(o instanceof Point2D)) {
            return false;
        }
        Point2D p = (Point2D) o;
        return p.x == x && p.y == y;
    }

    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
}

Now, we need to extend this class to account for 3D points.

Listing 19: A simple immutable 3D point class.

public class Point3D {
    private int z;
    public Point3D(int x, int y, int z) {
        super(x, y);
        this.z = z;
    }
}

Is it possible to create a correct equals() method for this class? Consider this first pass.

Listing 20: First (incorrect) pass at an equals() method.

    //-- violates symmetry
    public boolean equals(Object o) {
        if (!(o instanceof Point3D)) {
            return false;
        }
        Point3D p3 = (Point3D) o;
        return super.equals(o) && p3.z == z;
    }

The problem is that you might get different results if you compare a Point2D with a Point3D — 2D ignores the z dimension and 3D fails because the class type is always incorrect. One attempt to fix this would have the Point3D try to ignore the third dimension when doing the comparison. Now, we violate transitivity. Consider this example:

Listing 21: Second (incorrect) pass at an equals() method.

    //-- violates transitivity
    public boolean equals(Object o) {
        if (!(o instanceof Point2D)) {
            return false;
        }
        //-- if o is a Point2D, do an ignore-z comparison
        if (!(o instanceof Point2D)) {
            return o.equals(this);
        }
        //-- o must be a 3D point
        Point3D p3 = (Point3D) o;
        return super.equals(o) && p3.z == z;
    }

This version fixes the symetry problem, but introduces a transitivity problem. So, if you have these 3 objects:

  
  Point3D p1 = new Point3D(2, 3, 4);
  Point2D p2 = new Point2D(2, 3);
  Point3D p3 = new Point3D(2, 3, 12);
 

In this case, p1.equals(p2) and p2.equals(p3) both return true. However, p1.equals(p3) returns false. This is an indicator that the equals method is not transitive.

Unfortunately, there is no simple solution to this problem. This is a general problem in all Object-oriented languages, not just Java. The easiest way to fix this is to use composition instead of inheritance. In fact, that is exactly what the JDK does in several cases. For example, the TimeStamp class is a Date class with an extra field.

Here is a version using composition that avoids the problems of symetry and transitivity of the previous examples.

Listing 22: 3D Point build with composition instead of inheritance

public class Point3DComp {
    private Point2D point;
    private int z;
    public Point3DComp(int x, int y, int z) {
        point = new Point2D(x, y);
        this.z = z;
    }
    public Point2D asPoint2D() {
        return point;
    }
    public boolean equals(Object o) {
        if (!(o instanceof Point3DComp)) {
            return false;
        }
        Point3DComp p = (Point3DComp) o;
        return p.point.equals(point) && p.z == z;
    }
}
Consistent

This requirement states that if two objects are equal, they must remain equal unless (and until) one of them is modified. This is really little more than a reminder that mutable object’s equally can change over time as the contents of the object changes. This, of course, doesn’t apply to immutable objects. Generally, you should consider making objects immutable whenever you can because it simplifies the equality requirements.

Non-null Reference value

This requirement says that any object must not be equal to null. This is the reason that all equals() methods should begin with an instanceof check to make sure that the passed object is the of the correct lineage. You do not have to explicitly check to see if the argument is null — the instanceof operator always returns false if the first argument is null.

Building the Perfect equals()

Given the above requirements, here is a heuristic for building the perfect equals() method every time.

  1. Use == to check to see if you have been passed a direct reference to yourself.
  2. Use the instanceof operator to check the lineage of the object.
  3. Cast the object to the correct type.
  4. Check the equality of each field of the class. If any test fails, return false. Note that this will turn around and call the equals() method of the non-primitive fields of you class, so this can be time consuming. This should be done last after all the other (faster) tests have been passed.
  5. Make sure that your equals is symmetric, transitive, and consistent.
hashCode()

Like the equals() method, there are also very specific rules as to how to create a correct hashCode() method. In fact, any time that you override Object.equals(), you should override Object.hashCode() as well. The rules laid out by the J2SE specification are as follows:

  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
  • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.

The second condition is the one of most importance because it dictates how many of the collection classes define equality. Here is an example. First, let’s look at an example of what happens if you neglect creating a hashCode() method. Consider the Point2D class from above, which doesn’t have a hashCode() method. If you tried to key a collection item from this class, it would fail.

Listing 23: Trying to key a collection item with an invalid hashCode

public class TestHash {
    public TestHash() {
         HashMap map = new HashMap();
         map.put(new Point2D(12, 12), "my point");
         System.out.println("Here is the point:");
         System.out.println(map.get(new Point2D(12, 12)));
    }
    public static void main(String[] args) {
        new TestHash();
    }
}

When you run this application, it prints "null" instead of "my point". Why? Because the default hashCode() method (from Object) doesn’t correctly calculate the hashCode. All the keyed collections in Java use the hashCode to place items in the appropriate slot. If two objects that should be identical don’t generate the same hashCode(), they cannot be retrieved from the collection.

Here is a version of Point2D that does correctly override hashCode().

Listing 24: A version of Point2D that correctly implements the hashCode() method

public class Point2DHash {
    private int x;
    private int y;
    public Point2DHash(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public boolean equals(Object o) {
        if (!(o instanceof Point2DHash)) {
            return false;
        }
        Point2DHash p = (Point2DHash) o;
        return p.x == x && p.y == y;
    }
    public int hashCode() {
        int result = 7;
        result = 3 * result + x;
        result = 3 * result + y;
        return result;
    }
    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
}

Here is a reusable heuristic that allows you to correctly implement hashCode() for any class:

  1. Store a constant (prime) number in a variable (called result in the example above).
  2. For each field in the class that contributes to equals(), calculate a value for the field and add it to the result multiplied by a nontrivial prime number (3 in the above example)
  3. Return the result

Note that for arrays, you should iterate through the entire array to contribute to the result. You must resist the temptation of skipping fields to speed up the result because it will compromise your hashcode.

Antipatterns

Antipatterns are a response to the Design Patterns movement. If you can catalog a list of best practices and common design solutions, you can also catalog a list of worst practices and common but bad designs. Just like any architecture, J2EE won’t prevent you from doing something stupid, and in fact provides you with even more opportunities for stupid mistakes! To that end, this session presents a couple of very common worst practices that should be avoided like the plague.

"Uber Servlet" Antipattern

The first of the antipatterns is the "Uber Servlet" (also known as the "Fat Controller") pattern. This is an example of good intentions gone awry. The cause of this problem is the naive application of the Model-View-Controller design pattern discussed above. It is certainly a good thing to use the Model2 design pattern for web development (as embodied in Struts). However, if you try to use a single controller for everything, that single controller class becomes overly large, hard to debug, and starts growing all sorts of undesirable code to handle unusual circumstances. Even if you use a single controller for your MVC site, there is no rule that says that you can’t have any other servlets.

We had a client who was using this approach to manage every aspect of the application, using parameters passed to the controller to indicate what should happen. Because it was used for both normal processing and logon, the developers eventually created highly complicated logic that created a user session, immediately invalidated it, then re-created another one (there was some logic for doing this which escaped me then and now). Before they had finished, there were hundreds of lines of code (in a servlet that was already close to 5000 lines long) just to handle logging in. By changing logon to its own servlet, the entire application was simplified. The moral: don’t think that you can only have one master servlet. You can have as many as you need!

Notice that, even though Struts has a single controller, it’s controller does only one thing — map requests to actions, with its attendant form operations. If you use Struts, nothing says that you can’t create your own servlets to handle other jobs. In fact, it is probably a good thing that Struts handles this job for you and no others, because it encourages you to write other code to handle other stuff.

Finders that Return Large ResultSets

Another common misuse of the J2EE architecture has developers returning large result sets from entity bean finder methods. Especially if you just want a result set for display purposes, you should not use entity beans. When you create an entity bean, the application server must allocate resources for the beans. Thus, creating large numbers of beans generates a huge resource drain on the application server. Entity beans should only be used when you plan to update data, not display it.

If you need a large resultset to display some information, you should use a stateless session bean that connects directly to the database. These beans eat up far fewer resources than entity beans and will return the results much more quickly. In fact, if you need to update a large number of entities, you can write a stateless session bean that handles that directly with the database as well. Entities are designed for just that — small numbers of unique entities rather than large collections

Listing 25: Session bean that returns a list of Customer names

public class CustomerBean implements SessionBean {
    private SessionContext sessionContext;
    private java.util.List customerList;
    public void ejbCreate() {
    }
    public void ejbRemove() {
    }
    public void ejbActivate() {
    }
    public void ejbPassivate() {
    }
    public void setSessionContext(SessionContext sessionContext) {
        this.sessionContext = sessionContext;
    }
    public List getCustomerNameList() throws EJBException {
        Connection c = null;
        Statement s = null;
        ResultSet rs = null;
        try {
            c = getConnection();
            s = c.createStatement();
            RS = s.executeQuery("SELECT * FROM CUSTOMER");
            customerList = new Vector(20);
            while (rs.next())  {
                v.add(rs.getString("name"));
            }
        } catch (SQLException sqlx) {
            throw new EJBException(sqlx);
        }
        return customerList;
    }
    private Connection getConnection() throws SQLException {
        try {
            Context jndiContext = new InitalContext();
            DataSource ds = (DataSource) jndiContext.lookup(
                    "java:comp/env/jdbc/OrderEntryDS");
            return Ds;
        } catch (NamingException nx) {
            throw new EJBException(nx);
        }
    }
}

Summary

This session demonstrated a collection of J2EE best practices from a practical point of view. We looked at Web and EJB best practices and some J2EE Anti-patterns. If you would like to download the example from this presentation, go to http://www.thedswgroup.com/HTML/conferences.html.

For More Information


Some of the material presented here is adapted from my book Art of Java Web Development. It is guide to the topics required for state of the art web development. This book covers wide-ranging topics, including a variety of web development frameworks and best practices. Beginning with coverage of the history of the architecture of web applications, highlighting the uses of the standard web API to create applications with increasingly sophisticated architectures, developers are led through a discussion on the development of industry accepted best practices for architecture.

Described is the history and evolution towards this architecture and the reasons that it is superior to previous efforts. Also provided is an overview of the most popular web application frameworks, covering their architecture and use. Numerous frameworks exist, but trying to evaluate them is difficult because their documentation stresses their advantages but hides their deficiencies. Here, the same application is built in six different frameworks, providing a way to perform an informed comparison. Also provided is an evaluation of the pros and cons of each framework to assist in making a decision or evaluating a framework on your own. Finally, best practices are covered, including sophisticated user interface techniques, intelligent caching and resource management, performance tuning, debugging, testing, and Web services.

How do you sell Extreme Programming?

The thing I like about the Agile process is that it realizes this and tries to minimize the concept of a "release date" or "now it’s finished". Customers should embrace this as well, because they can stop spending money at almost any time and get a finished process.

And that got me thinking. We all know the story. A company needs a custom application done. They find a good consultant. Preferrably a Delphi consultant. After all, why would they choose any other tool? But of course, then the dreaded question comes: “How much will this cost and how long will it take?” No one wants to answer that one.

Developers, academics, business people, and probably a variety of wizards, kooks, and psychics have tried to solve this eternal problem. In my view, though, it isn’t an answerable question. I don’t think it is really possible to predict how much time (and thus how much money) a software project of any significance will take. Oh, sure, you can estimate, but of course your estimate is wrong. It will always be wrong. It seems to me that there simply are too many variables and too many unknowns for anyone to be able to predict with any accuracy the cost and scope of a given software project. Anything we do say is just pretty much a guess.

And we all know how it ends. The project invariably ends up costing more time and money than predicted, the feature set gets cut, the project gets shelved, or something not quite useful gets deployed. It doesn’t always happen that way. Clearly successful projects get deployed, but we’ve all heard statistics that outline the harrowing percentage of projects that fail. However, I think most of us would agree that estimating a software project is black magic at best.

(An aside: what I’ll be discussing below is custom business software, not shrink-wrapped software. Shrink-wrapped software is another beast altogether, and (surprise!) I have some thoughts on that as well).

As I said, I’ve been thinking on this. I think part of the problem is the “manufacturing” mentality of software development. Business is tuned into the idea of building and manufacturing things. They build cars and houses and bridges and iPods, so naturally, they want to build software. So, what do you do? You draw up some plans and you build it. You decide ahead of time exactly what you are going to build and you build it. Manufacturing processes are pretty well known, so you know what it is going to take to build this thing your want.

But software isn’t a bridge or an MP3 player or a television. It’s much more complicated than that. Now, a TV is pretty complicated, but its algorithmic. We know what it takes to build a TV. Once they are designed, they can be mass produced, and they actually have surprisingly little functionality for the end user. A software project is much different. It will probably have a large amount of functionality, but it will be unique to each customer. The process of actually manufacturing it can’t be predicted as it can with a car or a refrigerator.

So a customer wants a software solution, and so the approach is to look at it in one big chunk, as one thing to be done. But is that the best way for software to be built? I think we’d all agree that the “Specify it out, estimate the cost, go off and build it, uh-oh it will be late and over-budget” way of doing things isn’t working as well as we’d like. Maybe there is another way to look at things?

How about we think about doing it this way: When the customer says they want a specific software project done, they might try this: Start with a collection of basic, minimum requirements, build those, and then go from there, wherever things may lead. Incrementally add functionality, one feature at a time. Don’t even think about the next feature until the current feature is implemented and working. Deploy the application after each feature is completed, and let the “go with the flow” mentality determine what the next feature will be. (I suppose you can have a little list of features going, but think only in terms of incremental improvements and updates.)

Doing this will allow the customer to control the project much better. They can stop the project at almost any time and have a functioning system. They can specify features to match rapidly changing business needs. Things that they want today and would otherwise have written into a specification are things that they might not need at all in six months. The customer has a fixed budget? Then he gets a certain feature set commensurate with his needs and his budget. That feature set will be the most needed and important features. There may be other features the customer wants, and when more money is made available, the application is ready to have them implemented.

Now, I am fully aware that what I’ve just described is pretty much what Extreme Programming is. However, the thoughts that were running through my mind were about how to present this to a potential client. On the face of it, this all sounds crazy. Customers might be uncomfortable with the idea of not knowing precisely what is going to happen. But it seems to me that customers are going to be uncomfortable no matter what. In the old way, they were a bit uncomfortable at the beginning of the project and really uncomfortable at the end. This way, they are uncomfortable a bit at the beginning, but their comfort level rises as the project goes on as they see it improving and moving in precisely the direction they want and under a budget that is much more manageable. Its a win/win situation all around.

I could go on, but you all have probably read up on XP and what not. I guess my main thought here is that in order to serve customers better only if we can somehow convince them of the wisdom of a new approach.

How do we sell it?

Stuff that Bugs Me

For some reason, despite the fact that it’s the Christmas season, I’m feeling a bit grumpy. I don’t know why, but stuff has really been bugging me lately. So naturally, I have to fire up the word processor and list them!

  1. People who try to tell you that C# is better than Delphi. Now that Delphi 2005 is out, with its new language features, Delphi can easily hold it’s own against C#, and actually surpasses it in lots of ways.

  2. People who come on the newsgroups and act like TeamB “runs off” people who criticize Borland. This is silly. TeamB might disagree with your criticism but we don’t “run off” anybody.

  3. The use of “with” statements. That really bugs me.

  4. People who think that Borland has gone out of business

  5. The really bad support for streams in the FCL. There are no methods on the Stream class to copy from one stream to another, for crying out loud. Dealing with streams in .Net is just a pain in the ass when compared with the ease of using them in the VCL.

  6. Mail-in rebates for computer items. These things are a pain in the rear, and you invariably miss some key instruction and thus don’t get the rebate. I hate that.

  7. People who think that we are “forced” to buy stuff. There are actually people in the world who think that Microsoft forces them to buy Windows. Here’s a fact: it is against the law for /any/ company to force you to buy /anything/. Unless you live in some crazed totalitarian dictator ship, you don’t have to buy anything that you don’t want to buy.

  8. While we’re at it, people who think that Microsoft is some sort of dictatorial, evil empire bug me. All Microsoft can do is offer things for sale. They can’t and don’t do anything more than that. See #7 above for the response that virtually everyone in the world can have to Microsoft’s offer. The notion that Microsoft is some sort of governmental entity that controls people’s actions and dictates what people have to do is silly.

  9. I hate cryptic and semi-cryptic variable names like ‘lSt’ and ‘buf’. Jeez, work your fingers a little bit and use “Buffer”. And while you are at it, use capital letters in your variable names.

  10. People who type in all the same case, whether it be upper or lower. We have upper and lower case for a reason, people.

  11. Case-sensitive programming languages bug me. (Case is really bugging me today, eh?) It bugs me when people declare variable with the same name as their type, but different case.

  12. Code that tries to do three things in one line. Break out that code into multiple lines. It’s easier to read, and you’ll thank yourself when you go back and try to read it six months later.

  13. The fact that in .Net, the getters and setters for a property have to be in the same visibility as the property bugs me. I understand why, but it still bugs me. It also bugs me that they have to be prefaced by case-sensitive(!) prefixes.

  14. Okay, C# bugs me. It bugs me that all these C# dudes out there think properties and “partial classes” and all the other stuff Delphi has been doing for years is so new and cool. It bugs me that we’ve been doing object-oriented programming for fifteen years, and now tons of VB guys are doing C# and now think true object-oriented programming actually is cool now. It bugs me that C# programmers think that theirs it the “definitive” language against which all other languages should be measured.

And the really scary thing is that I quit there. I could have kept going. 😉

Using NUnit with Visual Studio 2005

This article describes how to use NUnit with Visual Studio 2005. In particular, I am using Visual Studio 2005 v 8.50727, which is similar to release candidate 1. This is a solid build of Visual Studio, but NUnit needs to be reconfigured to work with it smoothly. The solution to this problem is simple and fairly well known by this time, but I thought I would spell it out here, just so I would have an easily accessible written record of it.

I had the best luck with the most recent version of NUnit, which at this time is 2.2.2. This is called an iteration release, and it is dated Dec 7, 2004. Don’t confuse this release of NUnit with version 2.2.0, which was released on August 8, 2004.

Here is lightly edited a note from the NUnit web site: Iteration releases are works in progress. They are subject to change as we receive feedback and are likely to have more bugs than the latest production release. However, they may include new features and bug fixes that have not yet been released into production and are particularly useful for builders of tools that use or extend NUnit.

More out of habit than necessity, I avoided the Microsoft c:\Program Files directory, and instead installed NUnit into a directory called c:\bin\NUnit2.2.2. I do this because I need to call NUnit both from inside Visual Studio, and from the command line, and my life just seems to run more smoothly if I don’t install NUnit into a directory that has spaces in its name.

The next step is to open up the c :\bin\NUnit2.2.2\bin\nunit-gui.exe.config file in a text editor. You may want to choose an editor such as Visual Slick Edit, that provides syntax highlighting for XML files. In many editors, you will have to take an extra step to inform the editor that this file, which has an extension of .config, is actually an XML file. For instance, in Visual Slick Edit, choose Tools | Options | File Extension Setup, then press the New button.

You now need to find a section of the file called startup. This section of the file is commented out by default, so you need to remove the comments. As you surely recall, XML comments are like HTML comments, and begin with this signature: <!– and end with this signature: –>. This is the point where syntax highlighting can be helpful, as commented code shows up in one color, and ordinary code in another color.

You should now remove or comment out the existing code in the startup section and replace it with code that looks something like this:

<startup>
	<requiredRuntime version="v2.0.50727" />
</startup>

When specifying the version number, be sure to look in your c:\windows\Microsoft.NET\Framework directory and see what Framework you are actually using. As Microsoft draws near the ship date for Visual Studio, they are popping out releases like cars from an automated factory, and the version numbers spin by like an odometer on an autobahn. The number you want will begin with a v2.0. For instance, here is the directory listing from my system:

[D:\documents\web\codefez\hardcoded]dir c:\WINDOWS\Microsoft.NET\Framework

 Volume in drive C is unlabeled      Serial number is CC3C:3578
 Directory of  C:\WINDOWS\Microsoft.NET\Framework\*

10/04/2005   9:40         <DIR>    .
10/04/2005   9:40         <DIR>    ..
10/04/2005   9:40         <DIR>    v1.0.3705
10/04/2005   9:40         <DIR>    v1.1.4322
10/04/2005  12:34         <DIR>    v2.0.50727
10/04/2005  10:19         <DIR>    VJSharp

As you can see, the next to last listing, with a time of 12:34, is v2.0.50727.

At this stage, you should be able to run NUnit and begin testing a library that you created inside Visual Studio. In short, the change to the startup section is the only configuration step you need to take to use NUnit with Visual Studio 2005

It is, however, simplest if you can launch NUnit from inside of Visual Studio itself. The process for doing this has also changed. In the Visual Studio Solution Explorer, right click on the Library that you want to test and choose properties. In the picture below, I want to test NUnitDataTests2005, and so I right clicked on it.

In the Properties dialog, turn to the Debug page, select Start External Program, and use the ellipses button to choose the path to nunit-gui.exe In the Command line arguments text box, write in the name of the DLL that you want to test. In my case, it is called NUnitDataTests2005.dll.

Now when you press the run button in Visual Studio, NUnit should be launched automatically and your DLL should be loaded and ready to test. If you get an error about the format of your library, then you should go back to the startup section of your nunit-gui.exe.config file and try experimenting untill you hit on something that works. The option I have shown above, however, works for me on four different machines, and it has worked for many other people.

In this short article you have seen how to use NUnit inside of Visual Studio 2005. The steps involved are not difficult, but I have tried to lay them out clearly so that they will be documented for both myself and others.

On micro-optimizations

What’s a micro-optimization, you may ask? It’s applying a local-in-scope rule about optimization to your code without actually testing to see if it makes any difference to the performance of your application as a whole. Micro-optimizations are generally cast as never-to-be-broken rules, or even as items in some coding standards document.

Examples are easy to find: always using for instead of foreach, appending to a StringBuilder object instead of string concatenation, avoiding small methods to minimize the call time. Or, if you are a Delphi Win32 developer, never using TCollection, not using interfaces because of the reference counting, using other optimization tricks and tips.

Now, before you start huffing and puffing, I’m not advocating abandoning these optimizations, or saying that they are inherently evil, or anything like that. All I’m saying is that you should initially write code as clearly as possible. That implies that your code should be readable, simple and understandable. After all, your code gets written just the once, and then will be read many, many times.

Concentrate, therefore, on writing the clearest, simplest code that satisfies the requirements. Writing clear code gives you the best chance of creating provably correct software and of creating code that is easier to optimize. Writing clear code provides the best opportunity for enhancing maintainability. Far more money is spent on software maintenance than is ever spent on the original code. Clear code is generally more flexible and better able to adapt to future needs and changes. Consider using refactorings guided by software metrics to simplify your code. Consider using your skills as a developer to identify and remove code smells.

And it’s only after your code is written that you get to profile it to test its performance within the application. Only then do you get to analyze the hot spots in your application as a whole. Only then do you get to formulate a thesis ("replacing this simple-to-read foreach with a slightly harder to read for loop will improve the performance of my application as a whole") and then test it with the real application. Only then should you accept code changes that have a measurable change in your application’s performance. Only then should you reject failed theses and revert your code to the simpler-to-read version.

Of course, when you profile, don’t just profile the speed performance of your application. Profile the space requirements too, the memory pressure on the heap (the number and sizes of objects created and destroyed), the stress on the virtual memory system.

And remember that in order to refactor your code you must have unit tests to ensure that you don’t break functionality as you polish the performance.

Using Analogies in Software Development

I’ve done it, you’ve done it: when we’re talking to non-developers (aka, normal people), we sometimes use analogies to describe what we do. We use these analogies because they are helpful. Nevertheless, danger often arises when we infer too much about software development from our analogy.

When I worked for TurboPower and I had to explain what we did, I used to say that building software was like building a house. Yes, you could go out and chop down trees, cut the wood into planks and 2-by-4s, mix some clay and fire it into bricks, and so on, and then assemble them into your dream home, but in reality you don’t. You go to a wood merchant and buy pre-cut and planed wood. You go to the brick merchant and buy the bricks and mortar. So, I used to say, TurboPower is the brick merchant: people come to us and buy our bricks (that is, software libraries) and then build houses out of them. We had no control over what house they built or how they did it, and they chose our bricks because of their shape and color (design and API, if you like).

As an analogy it wasn’t perfect, but it got the idea across. But I’ve noticed something else as well: if writing an end-user application can be compared to building a house, then, the argument goes, we should use the same methodology in writing software as we do when building a house. We hire an architect to design the house by gathering our requirements for the house (bathroom next to the two spare bedrooms, outside faucet out back, room for a deck, Ethernet wiring, etc) and then to draw up the full design. The architect’s drawings then have to get approval from the local county planners, before the contractors arrive and start digging the foundations and taking coffee breaks.

That, I argue, is when the entire analogy breaks down. Building software is nothing like building a house. Why? Because software is (pretty much) infinitely malleable. Housing materials are not.

By creating the house design up front the architect can calculate loads, work out where pipes will go, balance the number of electrical outlets in a room, make sure doors can open fully, follow all the local house building rules, and all those fun things. Once the foundation is dug and laid, changing things can quickly get very expensive.

Software, on the other hand, gets expensive to change much less quickly and some changes will remain essentially free. (After all, we developers invented the notion of "feature-creep".) Yes, agreed, there is a point at which it’ll be too expensive to change some major foundational subsystem (example: after about 4 months into my last project, I began to wish I’d designed it to use smart clients), but you can tweak less major stuff ad nauseam. The user suddenly wants to track the hat size of their customers? No problem, we’ll add the extra column to this table here, tweak these stored procedures here to return it, add the new column to the business layer over there, and expose it as a field on this form just there. The cost and effort is minor compared to adding, say, another sink to an upstairs bathroom after that room has been tiled and finished.

Consider this also: if we break our software while testing it, it’s still there undamaged. Magic, eh? We can change it quickly and test it again. We can test all our design and implementation a dozen times an hour. On the other hand, testing a car’s resiliency to frontal crashes totals a car every time. Just imagine if we used a software-based approach to testing in designing a car ("let’s corrugate the chassis here and test it again." Bam! "Oh well, let’s make the corrugations less deep." Bam!), we’d bankrupt the automobile company in a day.

In other words, we shouldn’t approach the design and building of software like we do any other product. It’s not. It’s on another planet. It’s a different process altogether. If we treat software production as if it’s a traditional engineering discipline, we lose out on the great thing about software: it’s malleability and testability. Don’t take analogies too far.

Mono, .NET, GTK Sharp and Glade

This article explains the basics of using the Glade interface designer, and the simple task of hooking up a Glade interface to Mono based C# code. The overall purpose of these articles is to show how to use Glade to create cross-platform GUI applications that use a Delphi or Visual Studio.NET approach to Visual design.

The two previous articles in this series first introduced GTK#, then explained how to write simple code to handle signals. This article will complete the introduction to this subject by showing how to add two buttons to our main window, and how to respond to clicks on these buttons.

Visual Design in Glade: Horizontal Boxes

In Glade, one traditionally organizes a visual interface by using a set of containers similar to the layout managers found in Java. In this case, we will first put down a widget called a horizontal box. This tool will be used to control the layout of the two buttons that we place on top of this box. In other words, the box will own the two buttons, and help to ensure that they are laid out appropriately.

Go to the Palette and click on the Horizontal Box. Drop it on to the main window. You will be prompted to specify the number of columns that you need. Enter the number two. This will end up creating two GtkHBoxes, one for each of the buttons we intend to drop on top of these containers. When you are done, the box lies on top of the main window. The box is used for layout purposes, and thus has no specific visual representation other than some outlines provided by Glade to help you visualize the dimensions of the horizontal box.

Working with Buttons

The next step is to drop down the two buttons. Click on the button icon in the palette, then drop the button onto the left hand side of the designer.

You can see that the alignment of the buttons is not all we might hope for. In particular, we might want the two buttons to take up the entire work space, and to be distributed equally across it. In other words, we want the left half of the main window to contain button1, and the right half to contain button2. This arrangement is visible at the end of this article, in the last screen shot, showing the final state of our application.

To align the buttons correctly, we will to take two steps. First, we will optionally give each button a border of 5. This is done simply to improve the aesthetic appeal of our simple application. We should then be sure to set the Expand and Fill properties for each button to Yes. First click on the button you want to edit. Now turn to the Properties window. On the Widget page in the Properties window, you can see that there is a field called Border Width. Set its value to 5 for both buttons.

Now turn to the Packing page in the Properties window. Set the Expand and Fill properties to Yes. Be sure to repeat the process twice, first for button1, then for button2.

At this point, you might want to rename the buttons. I called the first button ButtonOne, and the second button ButtonTwo. You might also want to set their captions to Button One and the Button Two.

Setting Up the Button Click Signals

It is almost time to write the C# code for our application. First, however, we should set up the signals. In particular, we need to define the events that will be fired when a user clicks on ButtonOne or ButtonTwo. This is a two step process. First we define the events in Glade, then we write C# code for handling the events.

Select one of the buttons. Turn to the Signals page in the Properties window. Click on the ellipses icon on the Signals line, and select the clicked event. Press the OK button to complete the process.

Now rename the event to OnButtonTwoClicked. Complete the process by selecting the Add button. You will need to repeat the process for the other button. Don’t forget to press the Add button to bring things into the state!

The final step in this process is to save the program. Push the Save button in the main Glade window, and save your code under the name gtkstart06. This will produce two files, called gtkstart06.glade, and gtkstart06.gladep. Any valid file name can be used instead of gtkstart06. Note, however, that you will be loading the gtkstart06.glade file into your program. As a result, you should be sure that you specify the right name when loading the file, as described in the section called Writing the C# Code.

Examining the XML

Glade produces XML to define the actions you have performed inside its editor. If you are Delphi programmer, then you will recognize this XML as the equivalent of the DFM or XFM files produced by the Delphi visual designer.

You can see the XML found for our application in Listing 1. Please don’t panic when looking at this source. As explained in the previous articles in this series, it will be parsed for you automatically. I am showing it to you simply so you will have chance to study it. If it does not interest you, there is no reason why you cannot safely move on to the next section of this article.

Listing 1: The XML for the program we have been creating as it is found in the file called gtkstart06.glade.

<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
<glade-interface>
<requires lib="gnome"/>
<widget class="GtkWindow" id="MyWindow">
  <property name="visible">True</property>
  <property name="title" translatable="yes">My Window</property>
  <property name="type">GTK_WINDOW_TOPLEVEL</property>
  <property name="window_position">GTK_WIN_POS_NONE</property>
  <property name="modal">False</property>
  <property name="resizable">True</property>
  <property name="destroy_with_parent">False</property>
  <property name="decorated">True</property>
  <property name="skip_taskbar_hint">False</property>
  <property name="skip_pager_hint">False</property>
  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
  <signal name="delete_event" 
    handler="MyWindowDeleteEvent" 
    last_modification_time="Thu, 16 Dec 2004 17:13:38 GMT"/>
  <child>
    <widget class="GtkHBox" id="hbox1">
      <property name="visible">True</property>
      <property name="homogeneous">False</property>
      <property name="spacing">0</property>
      <child>
        <widget class="GtkHBox" id="hbox2">
          <property name="visible">True</property>
          <property name="homogeneous">False</property>
          <property name="spacing">0</property>
          <child>
            <widget class="GtkButton" id="button1">
              <property name="border_width">5</property>
              <property name="visible">True</property>
              <property name="can_focus">True</property>
              <property name="label" translatable="yes">button1</property>
              <property name="use_underline">True</property>
              <property name="relief">GTK_RELIEF_NORMAL</property>
              <property name="focus_on_click">True</property>
              <signal name="clicked" 
                handler="OnButtonOneClicked" 
                last_modification_time="Thu, 16 Dec 2004 18:26:53 GMT"/>
            </widget>
            <packing>
              <property name="padding">0</property>
              <property name="expand">True</property>
              <property name="fill">True</property>
            </packing>
          </child>
          <child>
            <widget class="GtkButton" id="ButtonTwo">
              <property name="border_width">5</property>
              <property name="visible">True</property>
              <property name="can_focus">True</property>
              <property name="label" translatable="yes">Button Two</property>
              <property name="use_underline">True</property>
              <property name="relief">GTK_RELIEF_NORMAL</property>
              <property name="focus_on_click">True</property>
              <signal name="clicked" 
                handler="OnButtonTwoClicked" 
                last_modification_time="Thu, 16 Dec 2004 18:27:39 GMT"/>
            </widget>
            <packing>
              <property name="padding">0</property>
              <property name="expand">True</property>
              <property name="fill">True</property>
            </packing>
          </child>
        </widget>
        <packing>
          <property name="padding">0</property>
          <property name="expand">True</property>
          <property name="fill">True</property>
        </packing>
      </child>
    </widget>
  </child>
</widget>
</glade-interface>

The basic structure of this file consists of an XML glade-interface section in which we nest first a widget of class GtkWindow, then two widgets of class GtkHBox, then two widgets of class GtkButton.

<glade-interface>
<widget class="GtkWindow" id="MyWindow">
    <widget class="GtkHBox" id="hbox1">
        <widget class="GtkHBox" id="hbox2">
            <widget class="GtkButton" id="ButtonTwo">
            <widget class="GtkButton" id="ButtonTwo">

Each of these widgets has various properties filled out in the manner specified by us when working in the Properties window. For instance, as shown in Figure 7, we set the Expand and Fill properties to Yes. The results are shown clearly in the XML:

          <property name="expand">True</property>
          <property name="fill">True</property>

You can also see the event handlers, or signals, that we defined:

            <widget class="GtkButton" id="ButtonTwo">
              // Code omitted here              
              <signal name="clicked" 
                handler="OnButtonTwoClicked" 
                last_modification_time="Thu, 16 Dec 2004 18:27:39 GMT"/>

Here you can see that there is a signal called clicked which will be handled by a method which we shall define called OnButtonTwoClicked.

As I said earlier, there is no need for you to actually parse this XML code; nor need you even look at it if you are not interested in it. However, it is often useful to understand this kind of code. In particular, it is nice to see that the visual tools produce a nice, simple XML file that you can store in CVS or other code repositories. Furthermore, the format here is so simple and straightforward that you can easily make small changes to your code by hand; there is no need to bring up Glade merely to change the name of a component, or to perform other simple tasks.

Writing the C# Code

It is at last time to write the simple C# code that will form the heart of our application. In a normal development cycle, you will be able to finish your work in Glade in just a few minutes. You will then spend most of your time writing C# code. But in this article, I dwelt on the Glade interface in some detail so as to make sure you understood how it works. Covering the code will be an equally important task, but it will take up much less space in this article.

Listing 2: The source code for the simple test application we have been creating.

namespace CodeFezSamples
{
  using System;
  using Gtk;
  using Glade;
  using GtkSharp;
  public class GtkStart06
  {
     ///////////////////////////////
     /// Import the widgets
     ///////////////////////////////
     [Glade.Widget]      
     Button ButtonOne;
     [Glade.Widget]      
     Button ButtonTwo;
     ///////////////////////////////
     /// Constructor
     ///////////////////////////////
     public GtkStart06 (string[] args) 
     {
             Application.Init();
             // Load the main window
             Glade.XML gxml = new Glade.XML ("gtkstart06.glade", 
               "MyWindow", null);
             gxml.Autoconnect (this);
             Application.Run();
     }
     // Called when main window closes
     public void MyWindowDeleteEvent (object o, DeleteEventArgs args) 
     {
             Application.Quit ();
             args.RetVal = true;
     }
     public void OnButtonOneClicked (System.Object obj, EventArgs e) 
     {
             String data = String.Format("ButtonOne {0}", ButtonOne.Label);
             Console.WriteLine (data);
     }
     public void OnButtonTwoClicked (System.Object obj, EventArgs e) 
     {
             String data = String.Format("ButtonTwo {0}", ButtonTwo.Label);
             Console.WriteLine (data);
     }
     ///////////////////////////////
     /// Main
     ///////////////////////////////
     public static void Main (string[] args)
     {
             new GtkStart06(args);
     }
  }
}

The code for this application begins with a Main statement, shown at the bottom of Listing 1. This block does nothing more than create an instance of our main class, called GtkStart06. Again, you can use any valid C# identifier to specify the name of your class.

After writing simple using statements to import the libraries we need, the next step is to import the two buttons that we defined inside of Glade:

  [Glade.Widget]      
  Button ButtonOne;
  [Glade.Widget]
  Button ButtonTwo;

We now have two instances of these buttons. If we want to work with them, we can write simple code such as the following:

ButtonOne.BorderWidth=10;

There is no actual instance of code of this type in our program, but I show this sample to you so that you can understand that ButtonOne is an instance of your button, and that you can execute code on this instance. To see this in action, you could insert this code into the end of the constructor just before the Application.Run statement, then compile and launch your program to view the result. More of this kind of code will be shown in later articles in this series.

As explained in earlier articles, we use two simple lines of code to parse the XML file and to connect to the events and controls defined by us while working inside of Glade:

Glade.XML gxml = new Glade.XML ("gtkstart06.glade",
  "MyWindow", null);
gxml.Autoconnect (this);

This is all you need to do to connect to the code defined in your XML file, and to set up the event handlers. All the details are taken care of for you automatically.

The final step is to create the three simple signal handlers that will define the events that occur when the user closes the main window, or clicks on either of the two buttons we have created:

   // Called when main window closes
   public void MyWindowDeleteEvent (object o, DeleteEventArgs args) 
   {
      Application.Quit ();
      args.RetVal = true;
   }
    
   public void OnButtonOneClicked (System.Object obj, EventArgs e) 
   {
      String data = String.Format("ButtonOne {0}", ButtonOne.Label);
      Console.WriteLine(data);
   }
   public void OnButtonTwoClicked (System.Object obj, EventArgs e) 
   {
      String data = String.Format("ButtonTwo {0}", ButtonTwo.Label);
      Console.WriteLine(data);
   }

As explained in the previous article, our first handler calls Application.Quit to ensure that the application itself is destroyed when the main window is closed. The next two handlers simply write text out to the console when either of the buttons are clicked. In particular, note the use of the ButtonOne.Label and ButtonTwo.Label properties. If we did not access these properties, there would be no need to import ButtonOne and ButtonTwo. More complex button handling code will be defined in future articles.

The final step is to once again compile and run the program. This is best done with a simple bash shell script:

export MONO_PATH=/usr/lib/mono/gtk-sharp/
mcs /unsafe -r gtk-sharp.dll -r glade-sharp.dll -r gnome-sharp.dll gtkstart06.cs
export MONO_PATH=

If you are working on Windows, there is no need for the code that sets the MONO_PATH, and you should probably write -pkg: instead of -r:

mcs -pkg:gtk-sharp -pkg:glade-sharp gtkstart06.cs 

After running this script, you should have a program called gtkstart06.exe on your hard drive in the current directory. Run the program by typing the following at the shell prompt:

mono gtkstart06.exe

After pressing either of the buttons, look back at the shell prompt from which you launched the application in order to see the output.

Summary

In this article you have seen the simple steps necessary to create a visual interface in Glade, and you have seen how to create C# code that can hook into the widgets and signals that you created.

The simple steps outlined in this chapter can be boiled down to the following four bullet points:

  • Drop down a Horizontal Box with two sections.

  • Place a Button in each section

  • Define clicked signals for each button.

  • Write C# code to handle the signals at run time.

I’ve gone over these steps in some detail to ensure that you understand how to perform them, and why each step exists. However, if you practice writing this kind of application a few times, you will find that it is a very easy process. After a few minutes practice, and assuming you cut and paste some code, you should be able to write an application of this type in five to ten minutes, or perhaps less.

It is easy to write code of this kind, and it runs smoothly in Windows and Linux. Glade interfaces can also be called from C, C++, Python, Perl, and other languages. This a powerful and easy to use technology that frees you from the tyranny of proprietary, single platform, APIs.

Creating DataModule-like components in .NET

Delphi’s DataModules were a useful programming tool because they provided a centralized place to define data schema and business logic which could then be referenced from multiple locations. Visual Studio .NET, however, encourages the programmer to place DataSets and Adapters on each individual page, resulting in decentralized and possibly redundant business logic. However, it is possible to roll your own DataModule-like components in .NET. Here’s how:

  1. Decide whether you want to have your custom DataSet component in the same project or in a class library. Keeping it in the same project is a little simpler, while putting it in a separate class library will result in a separate assembly that contains only data logic, making it more suitable to deploy as a business tier.
  2. Add a new Component to the target project 
  3. Add a Connection and DataAdapters to the Component, and generate a DataSet. The visibility of the Connection and DataAdapters will default to private, so make sure to change them as appropriate for your design.
  4. Once the DataSet has been generated, create a new class that descends from the DataSet subclass. The DataSet subclass name is the same as the name of the .xsd schema file.
  5. Add the following attributes to your DataSet subclass:
    1. [ Serializable() ]
    2. [ System.ComponentModel.ToolboxItem( true ) ]
  6. Add a property to the DataSet subclass that references the Component containing all the DataAdapters. Include logic either in the DataSet subclass constructor or in the property accessor to create a new instance of the DataAdapter container if needed.
  7. Optionally, to hide the base DataSet class, open the base .cs file with the same name as the schema .xsd file and change the ToolboxItem attribute from true to false. Changes made to this file will disappear every time the .xsd it is based on changes, so make the decision whether or not this step is worthwhile accordingly.
  8. Build the project
  9. You can now add the custom DataSet class to the Toolbar. When dragged into another project, the Visual Studio IDE will treat the DataSet subclass as if it is a DataSet; it will appear as a top-level item in the DataBinding dialog box and have the DataSet property editor. Additionally, all the custom business logic methods you added to the class will also be available in code. The DataSet schema will only be editable in the project containing the DataSet subclass, which is a natural result of centralizing your schema and logic. Be forewarned that adding such a custom DataSet to the Toolbar while it is still in development might cause more frustration than it’s worth, since Visual Studio will not be easily persuaded to detect changes to the DataSet schema, particularly in the designer.

Sample Code

using System;

namespace MyNamespace.MyDataModules
{

  [ Serializable() ]
  [ System.ComponentModel.ToolboxItem( true ) ]
// MyStronglyTypedDataSet is the name of the DataSet class
// automatically generated by Visual Studio .NET
public class CustomDataSet : MyStronglyTypedDataSet
  {

// CustomDataSetAdapters is the name of the Component class

// containing all the DataAdapters used to generate, fill,

// and update the DataSet.

private CustomDataSetAdapters _Adapters;
private System.ComponentModel.Container components = null;
public CustomDataSet( System.ComponentModel.IContainer container )
    {
      container.Add( this );
      InitializeComponent();
// Initialize DataSet properties here

_Adapters = new CustomDataSetAdapters( container );
    }
public CustomDataSet()
    {
// Initialize DataSet properties here

­_Adapters = new CustomDataSetAdapters();
    }
protected override void Dispose( bool disposing )
    {
if ( disposing )
      {
if ( components != null )
        {
          components.Dispose();
        }
      }
base.Dispose( disposing );
    }

// This property exposes the component class containing

// all the DataAdapters used to generate, fill, and update

// the DataSet

public CustomDataSetAdapters Adapters

{

get

{

return _Adapters;

}

}
public void BusinessLogicMethod1()
    {
// Custom business logic here
    }
  }
}

Ten Annoyances in Delphi 2005

These CodeFez editorials are fun. The best part is when I get comments from humor- and sarcasm- impaired people who take things far too seriously. I get a good laugh out of folks like that.

One of the common comments I get is that I am a “Delphi Bigot”. Well, that stands to reason, since that is the name of my blog. But somehow they fail to see the tongue-in-cheek nature of the moniker. Many miss the slight sarcasm, biting satire, and good-natured ribbing in some of my articles. Some have even gone so far as accuse me of being the “Borland Information Minister”.

So, in a effort to dispel the notion that I am a raging Borland Sycophant, this week’s column is entitled “Ten Annoyances in Delphi 2005”. This is probably a once in a lifetime experience, so arrive early, as supplies are limited!

So, without further ado, here they are:

  1. Those dang blue balls cover up line numbers. I would have loved to have been at that meeting. “Hey, we have this new line numbering feature. Let’s cover up the line numbers with blue balls!”

  2. No "Make Region of Selected code" option Code folding is cool, but not so necessary in Delphi. What is cool is folding regions. Unfortunately, there is no way to select a block of code and turn it into a {$REGION} Oh well. Actually, I’m growing fond of typing, scrolling down, and typing again.

  3. "Build All Projects" doesn’t have a shortcut key. Back in the day, CTRL-S, CTRL-F9 was good enough. Now, with assemblies, multiple projects, C# and Delphi in the same project group, why, a simple compile isn’t really good enough. Build All is the future!

  4. Select Tools|Options… Look at the horizontal scroll bar in the treeview control. Be annoyed. Argh. Double Argh! One of my pet peeves is non-resizable dialogs that we should be to resize. Things are better in Delphi 2005, but still have a way to go. (Once the holy war against non-resizable dialogs has been won, the crusade will move on to getting the IDE to remember the sizes of dialogs that have been sized.) Anyway, that dang horizontal scrollbar on the bottom of the Options dialog bugs the heck out of me. Why couldn’t size that treeview a few pixels wider to make that thing go away?

  5. I overshoot those dang tabs on the bottom by just a little bit, and my Windows taskbar pops up. Up and down and up and down goes my mouse. Tabs on the top, tabs on the bottom. Since I have my Windows taskbar set to auto-hide, one pixel too far and BOOM, up it pops, and I have to wait for it to go down. Can’t those tabs at the bottom be somewhere else? Anywhere else? (And while we are at it, could there be any more annoying feature than the Windows taskbar when it won’t recede? This happens all the time. And how about that application that pops up the taskbar, insisting on being paid attention. “I’m not going to stop blinking and I’m going to keep your taskbar popped up until you look at me!!!!’ Who thought this was a good idea?)

  6. No "Close All Open Files But Not The Project" option in editor I know this is considered blasphemy in the Delphi community, but I’ve taken to using the “Default” desktop with everything docked into one big window. This allows me to unpin the Object Inspector, Project Manager, etc., and bring them out on demand. Well, in my normal course of working, I frequently end up with tons of code editor pages open, and sometimes I’d like to close them all and just sort of start over with one page. Well, there is no way to do this except to hit the little black ‘X’ on all the code pages. “Close All” closes the entire project, and that’s not what I want.

  7. The "Highlight Current Line" feature is really annoying. I suppose some people like this, but I find it incredibly annoying. I like a dark background in my Code Editor, and there simply isn’t a color that I can choose for the highlighted line color that doesn’t make this feature bothersome in the extreme. It utterly obscures the text caret, so I have no idea where my typing will go. And to make matters worse, there isn’t one place to turn off the "Highlight Current Line" feature once and for all. You have to switch it off for every individual file type. Argh!

  8. And while we are at it, the bracket matching “feature” is really, really annoying. This one I truly hate, and I cant understand why anyone like this. Try this: Drop a button on a form. Double-click on the button. Type “ShowMess” an press CTRL-Space. Then select “ShowMessage” from the list. Now, is the cursor where it is supposed to be, right in between the parentheses? Huh? Are you sure? Move it around. Now are you sure?

  9. No way to get the IDE to easily open a plain ol’ *.pas file. If I am working on a Delphi project and click on the Open button, it should assume I want to open a *.pas file, not a .bdsproj file, or whatever. That’s what Open Project is for. And to make matters worse, the drop-down filter box has a selection named Pascal Project (*.pas) that doesn’t merely open a *.pas file, it opens it as a project! Don’t pick that one when you have to go through the annoying process of dropping down the combobox and selecting the *.pas filter. (More “while we are at it”. Is there anything more annoying on the Standard VCL pallete tab than the dreaded combobox? Who likes these things? Click, find the scroll thumb, scroll, scroll, scroll, find what you want, click on it. Oops! I clicked on the wrong one! Start over! There has to be a better way that this.)

  10. Class Completion isn’t keeping up with the times. As much as I hate to admit it, we Delphi developers have to make some concessions to the tyranny that is the Common Language Specification (CLS). One is the definition of property assessors. The CLS requires that all accessors begin with ‘get_’ and ‘set_’. (Is there a more commonly used, difficult to type, and utterly unnecessary character than the underscore?) Well, Class Completion doesn’t provide this when filling out property declarations, and I think it should.

There you go. See? I’m not a total sycophant!

Note to the humor impaired: The above article contains sarcasm, humor, and a touch of satire. Please read the definitions of those words carefully before commenting or sending emails. And by the way, this very notice itself contains that very stuff, too.

Note to Allen, Corbin and the gang: I love and admire you guys. You all are my heroes. Really. Seriously. No hard feelings, right?  Right?