Adept Software Development

Adept: (A)pplication (D)evelopment (E)nterprise to (P)ersonal (T)ransition. It is a system I am developing to leverage Enterprise developer skills to produce stand-alone software for other market segments. This is a general software development blog discussing issues about project, architecture, design and development. The emphasis will be in Java, but many of the issues will be more general. Almost all will be technical.

http://marringtons.com

Monday, August 29, 2005

JavaScript Events - Part 1 - Setting Events

This is part 1 of a 3 part series.
  • Part 1: Setting Events
  • Part 2: The Event Object.
  • Part 3: A General Usable Event Manager. I've just refactored the JavaScript events system for Adept. I initially chose to implement the menu system by generating HTML rather than by building objects. Bad choice. It highlighted the operational inconsistencies between 3 completely different ways to add an event to an element.

    Three Event Addition Methods

    1. In HTML as in <a onclick="myfunc">.
    2. As an Attribute as in element.onclick = myfunc;
    3. Using the DOM Model as in element.addEventListener( "click", myfunc, false);.

    The HTML Event

    You can set an event for an element directly in the HTML using the event name preceded by "on". The code generates a function and compiles the attribute value text as the function body. This means that you are not running in the same context as when you programatically attach an event, since your code is running inside a method body. One browser inconsistency is overcome by this method: IE generates function(){yourcode} while Mozilla generates function(event){yourcode}. This allows both event types to access the event object as event even though it is passed in in Mozilla and is a global for IE. Warning: Don't use this to reference the element firing the event. It works for Mozilla, but not for IE.

    Event Attribute

    In the pre-DOM world, attributes were just fields on the HTML element. For backwards compatability they still are and always will be (for HTML anyway). So,
    element.onclick = function() { alert( "click"); }
    

     

    will work. The problem is that a single element can only have one event function per event type. This makes it difficult to produce library type code for JavaScript.

    DOM Events

    If events are set using the addEventListener() method they are stacked and all events added are fired. Perfect, except that IE (as of 6) does not support this part of the DOM.

    Summary

    So, what are the problems?
    1. Event setting that's portable across browsers does not allow more than one event per type per element.
    2. addEventListener() is not platform independent.

  • Wednesday, August 24, 2005

    Coding Standards and Breaking the Rules - Part 3, Exceptions

    While we are talking about going overboard while following a standard, let's talk about exceptions. Exceptions were introduced late into the C++ standard and so for many years were virtually ignored. Existing code had other mechanisms, libraries did not use them and few developers understood them. Java was developed after that. The development team decided to implement and use (or dare I say overuse) exceptions.

    What is an Exception?

    What do you do if some code deep in the bowels of a system comes across a problem it can't handle? What, for example, should a routine to convert a string to a number do if given a non-numeric input string? I saw many exceptions in the days prior to exceptions. Some libraries set a global error number - a definite problem if you have multiple threads. I even worked on a C project not that long ago (1999) that passed an error structure around to each and every call in the system.

    Then came exceptions. Just create an appropriate Throwable instance and throw it. None of the standard contiguous code that follows will be executed until some other code further up the calling graph catches exceptions based on the type you threw. That is not strictly true. Each method up the calling graph can have a finally block that will execute no matter what exceptions have been thrown. This is especially good for closing resources.

    The theory is that code that does not know what to do with an error condition throws a named exception. Somewhere further up the call graph the code will know what to do or correct and will catch and deal with the problem.

    public int convert( String string)
      {
        if (! aNumber( string))
          throw new NumberFormatException( s+" cannot be made into a number");
      }
    ...
    public void process()
      {
        ...
        int result = 0;
        try
          { result = convert( entry); }
        catch (NumberFormatException numberFormatException)
          {
            /* if we can't get a conversion, make it large enough to work. */
            result = 1000;
          }
      }
    

     

    Notice that in the example, convert() does not know what to do if the conversion cannot be done. The calling method, however, knows what sort of default to apply - and does so. In the real world it should at least write the problem to a log for later evaluation.

    Problems with Exceptions

    1. Overuse: Current thinking is along the lines of 'if in doubt, throw an exception'. An exception is for an unexpected situation that cannot be dealt with where the problem occurred. Make sure you can't handle the problem immediately. If so, avoid an exception. Then consider how the calling code will handle it. In application code it is often the invoker who will deal with the problem. In this case there are often simpler methods that throwing exceptions to process the situation. If so, once again, no exception.
    2. Overuse: Yes, I know it is technically the same problem - but it's so prevalent that I have decided to repeat it. So, please read the item above again.
    3. Dangerous Program Flow: An exception causes program flow to jump out of line with no visual indication in the code. The lack of visual queues makes it difficult to be aware of when important operations will not happen.
      file = new AppFile();
      file.write( info);
      file.close();
      

       

      In the example above, if the write throws an exception then the file is not closed. If the code is called again it will fail because the file is open and locked.
    4. Insufficient Clarity: Exception pundits are quick to point out that the code immediately above should be written as:
      file = new AppFile();
      try
        { file.write( info); }
      finally
        { file.close(); }
      

       

      That's immediately more difficult to read. The natural program flow has been interrupted by the implementation need for an exception. I prefer the earlier version.

    Types of Exceptions

    To be accurate, this section describes the types of errors exceptions are designed to address.
    1. Fatal errors. Have you noticed that when Windows 'blue screens' you can't even reboot from the keyboard. The machine needs a hard reset. This is because the system did something that is totally unrecoverable. The code that caught the error cannot even trust the keyboard, so it displays as much as it can then freezes. In client server systems the situation can be even worse. If the server cannot trust the connection to the client, the client can't even be told how or why before the freeze. Needless to say that fatal errors should be rare, since they indicate fragility in critical single-source-of-failure code. An out-of-memory exception is the most common among applications servers. While a disk-full error can be handled, it is such a rare situation that cannot be corrected by the application that it is usually treated as fatal also.
    2. System errors. These are the errors that are out of our control. They include disk I/O failures, unexpected closed connections and the like. Many are so unusual that it is unlikely that the code attempts to deal with it. What does your code do if a disk write returns an IOException? The conservative approach would be to treat a disk write IOException as fatal since further writing is likely to corrupt data. Most systems just write such errors to the log and report a generic system error to the user. The question is do you attempt to write again or save the data elsewhere. Again the problem is rare enough that accounting for it in the code is often overkill. Unexpected connection closures (database, socket, etc) are also system errors. In most cases they are dealt with by logging the surprise and grabbing a new connection. The worst the user will experience is a slight delay. Of course if the problem isn't monitored there is a risk of an epidemic of closures and a slow and unresponsive application.
    3. Inability errors. These are errors when a piece of code us unable to process with the data provided. NumberFormatException is one of these. They are almost always checked exceptions thrown with the expectation that somewhere up the calling tree code will recognise the problem and know what to do. Never rethrow an exception or pass it up the call graph without considering if the code at this point knows what to do. GUI support will recognise NumberFormatException and know to return an error message to the user. If thrown during a file read the decision may be harder. The best we can often do is log the problem and provide a reasonable default value. Too many developers treat this as a system error.
    4. Programming errors. These should always be unchecked. They should not have happened and the code is not built to handle it. The best solution is to undo all actions and tell give the user enough information that they can give support a full picture. I usually return an error code that is unique in the log so that support can find logging around the time of the error. NullPointerException is the way-too-common example of this class of error.

    So How Do I Break the Rules?

    1. I always use unchecked exceptions for programming errors. Why complicate the code for situations that cannot be handled anyway.
    2. I use unchecked exceptions for problems I need to communicate directly to the user. Why have to explicitly use "throws" up a tree when the target is always the top?
    3. I only throw/catch exceptions when it is clearly the best or only way. In most cases an error condition will be more useful. If you look at my XML code in the Adept library you will see that it propulates and returns a Messages object. If there are no problems, the list will be empty. This is more useful than an exception in this situation because the code can accumulate problems rather than give up on only one.
    4. An expected condition is not an exception. I prefer:
      if (! open( file))
        tryAnother();
      
      to
      try
        { open( file); }
      catch (FileNotFoundException fileNotFoundException)
        { tryAnother(); }
      
      It's a lot more readable. My XML code works both ways to handle both sorts of clients. After processing you can ask it to throw an exception if errors were found.
    5. I do not consider exceptions part of the tiering system. I do not catch exceptions and rethrow them just to keep exception types within one tier.

    Monday, August 01, 2005

    Coding Standards and Breaking the Rules - Part 2, Beans

    Standardisation isn't just about styles. Very soon after the advent of Java, Sun introduced the concept of the bean. The original idea was to define components in Java. A component is a reusable building block. In its purest form you should not know or care even which computer a bean is running on.

    Computer independance implies an interface such as that defined for Corba or COM/DCOM. This means methods only, not direct data access. If a calling class asks for data it is a method call that could be serviced locally or sent down the wire to another computer.

    The bean provides the same facilities by convention, not by language restriction. The convention requires that data always be private and accessed by getter and setter methods. Groovy, a Java spinnoff that creates Java class files generates getter and setter calls whenever the data is accessed.

    Originally beans were created for reusable components - often SWING GUI - such as buttons. Later the concept was extended to server code and the EJB (Enterprise JavaBean).

    The militant took the concept of the bean and made it law:

    1. Thou shalt not allow outside access to data. Always make it private.
    2. Thou shalt always access data with getters and setters. No exceptions, heathen!
    3. Thou shalt burn in oil anyone who does not follow rules one and two at all times. Toss in some fries will you? I do so love those.

    The claimed benefits are almost universally believed today, and yet hold less water than the average funnel.

    1. Making data public is a security violation. Anyone could change it. Yep, that's true. Then why does everyone add setters to all data as a matter of course? And if you choose not to have public setters, how do you set the fields? You could load them in the constructor, but this quickly becomes unwieldy unless there are 6 or less fields to set. You could make the setters package private, but this is limiting in the wrong way. The C++ concept of 'friend' would be useful here.
    2. You can provide a consistent interface that will not change with implementation changes. Again there is a kernel of truth. A getter that retrieves data could do so from a field, make a call to a database, or cache data from an external source. Very cool, except that everyone assumes that a getter is retrieving from a field with minimal overhead. I don't know how often I have seen code that calls a getter multiple times in a method rather than calling it once and saving it in a local variable. Yes it's bad practice, but it's commonplace and has some real risks. If the getter is converted to a more complex retrieval (or down a wire as in COM), the calling method that calls it multiple times becomes very inefficient. I prefer a system that separates simple retrievals from the more complicated. See below.

    Class Differentiation

    I don't treat all classes the same. At a gross level, I divide classes into groups:
    1. Beans. These are classes that interact with other packages, libraries or frameworks that expect that standard bean protocol. Giving credit where it is due - the bean protocol is clear and works well.
    2. Data Transfer Objects. Commonly called DTOs or DAOs for Data Access Objects. When talking between sub-systems, tiers or layers, it's almost always necessary to pass specific information back and forwards. Because this information is passed between disparate groups they neither want nor need processing internals. Sometimes a single DTO can be used for multiple interfaces. Mostly this will lead to DAO classes that are only partially filled or relevant to the receiving class. I commonly make the DAO a static inner class of the owning logic class and use deep copy routines where possible to ease data transfer.
    3. Implementation Objects. These are the objects that do the work - be it define business logic or provide validation. For these items, being an object is just a convenience thing - allowing for working data encapsulation.
    4. Object Objects. Early OO design documention talked about object that represented a car, with object that extend that for a type of car. In the 'real' world of appplication development, it is not all that common to create objects that truly represent something.

    How I Break the Rules

    1. Beans. I don't, obviously. A bean has a rigid interface definition that must be adhered to if it's to work with outside components. I would go so far as to say that when I use beans, they are only beans. They're an interface object that does just that and only that - interface. Beans should use implementation and object objects to do the 'real' work. A clear separation of functionality is a clear and very useful architectural principle to apply. It would be acceptable for the bean to consolidate information and implementation from various parts of the system to provide the results required. A bean that responds to the press of a GUI button may validate and then act.
    2. Data Transfer Objects. The clear architectural imperative to separate functionality applies double to DTOs. This is because you may want to send a DTO down the wire or write it to a file or database. To help this, minimise the use of sub-objects and make sure they are also DTOs. If they are to be persisted or used remotely, make very sure they do not contain time and space sensitive data such as handles or security packets. One of the funniest I've seen was a system that kept a reference to a session in a DTO send to a JMS queue. Everything was fine until the system was restarted with items still on the queue. Then, kaboom. Back to breaking the rules... For me, a pure DTO has no methods whatsoever - just public data. I can hear the pundits screaming from here! But what benefit getters and setters? If you have both then you might as well have public fields. If you only provide getters and set in the constructor, then this is the same as using final public fields.
    3. Implementation Objects. In simpler cases the are often just a collection of static methods, such as the library Collections class. Often an implementation object is more complex where the client needs to call multiple methods on common data to produce the correct results. In these cases a new instance is created - but only for convenience. It provides a container for working information. If you accept the definition of an Implementation Object, then I do not break the rules. Methods are an action and often return a reference to the object so that calls can be chained:
      new ManufactureProcess()
        .rawMaterial( m).cut( c)
        .bend( b).paint( colour)
      
      More often they will be separate statements to account for optional operations.
    4. Object Objects. Remember your early training in OO. I treat data storage and retrieval the same for Implementation and Object objects. Firstly I make it private when I can, package private when it is only needed in that sphere and only public when I must.This isn't for security reasons - it just makes the class easy to use. Private and package private are implementation artifacts. When writing a client you need not have them cluttering the documentation nor feel you can use them inappropriately. So, what happens when setting data is a little more complex than copying its reference? It may be cached or it may require unit conversion. I'll make the field private and create a setter and getter, but using the same name as the field without prepending it with 'set'. This way I know that it's not a bean and that working with this field takes work. Oh dear, I can hear those pundits screaming again. What, they say, now every client that uses my class will need to be changed. That is exactly what I want. The writer of the client will have to investigate how the change effects their code. It all depends on the data lifetime that the client requires. They may be able to use the getter to retrieve one copy in the running of the program. More likely they will take a local reference and a single call outside all loops and passes. But, only the client writer can be sure of the best valid lifetime. It may be that they do have to retrieve it directly every time because the returned result is just that volatile. By using the same name for the data and the getter and setter methods, the changes made to the client are minimal and obvious.
    private int idleTimeInSeconds = -1;
    public int idleTimeInSeconds()
      {
        if (idleTimeInSeconds < 0)
          idleTimeInSeconds(
            Properties.get( "idleTimeInSeconds"));
        return idleTimeInSeconds;
      }
    public void idleTimeInSeconds( int newIdleTime)
      {
        if (newIdleTime <= 0  ||  newIdleTime > 1000)
          throw new Exception( "Oops"):
        idleTimeInSeconds = newIdleTime;
      }