Παρασκευή 21 Ιουνίου 2013

A few things about software design

While there are a number of frameworks for web development (JEE, Spring etc.) that provide Off-The-Shelf design guidelines to help developers structuring their code, standalone (desktop) applications lack one. It is unfortunate to see even very good developers having difficulties in designing their code and creating spaghetti code.
Software design should be simple. In this blog entry we present some simple guidelines to good design. The Model-View-Controller (MVC) software architecture will be used. Even though the examples are in Java, these guidelines can be easily applied to other Object-oriented programming languages.
  1. Software officially starts from the requirements (most of the time). You should seek for a formal document that describes what you have to do, or put them down to paper (or in electronic form). Start by identifying the domain objects; these represent entities of the real world most of the time. E.g. if you have to develop an electronic library system, then your domain objects would be: Book, Librarian, User, etc. Try to identify the attributes (fields) of each domain object, e.g. for the Book(ISBN, title, authors, pages) etc. Assuming Java as your programming language, you should create 3 packages: model, view, controller. Inside model, create a domainobjects sub-package and inside there create the domain objects as Plain Old Java Objects (POJOs) or Value Objects (VOs). These should only contain the attributes and getters/setters. They are the base of your application, the objects that hold and transfer your data. They should contain no processing logic, like e.g. extractMessageFromNetworkObject() or parseWsdl(). Think that you should be able to directly persist them to a database. This way you can populate them from different sources (database, network, web services) without any change to them.
  2. Then you should be able to populate the domain objects with data. This is the job of a controller. It could be a controller that parses a text file, or retrieves data from a database or a SOAP message etc. Ideally, it should be a utility class with static methods and no state. It should return a VO (domain object), e.g. public static Book getBookBy(String isbn); retrieves a Book record from the database and creates and returns a Book VO out of it.
  3. To display the book data to the UI (an HTML form, a JavaFX client etc.), the view class should call the above controller to retrieve the Book object or another controller which will prepare the data according to the wishes of the view. This controller should ideally return the required data; the view should only deal with the presentation of the data, not their processing.
  4. Some more guidelines that enforce encapsulation and low coupling. 
    1. Avoid dependencies to attributes as much as possible; e.g. assume a method that calculates the key of Book to be used by the e-Library application as the id (could be ISBN too but too slow). This could be a private method of the Book class (since it is private it doesn't matter much and doesn't violate the POJO discipline). This method calculates the key based on information from ISBN, the title, the authors and the category (e.g. science, history etc.). Instead of creating a method calculateKey() that depends on the attributes isbn, title, category, authors,  the method signature should be calculateKey(String isbn, String title, Category category, List authors) and you should pass the attributes as parameters to the method, where it is being called inside the Book class. If you need to refactor this method to another class, you only need to modify the callers to the method and you are done!
    2. Try to reduce dependencies among classes. Think twice before you create a new dependency to another class and take a minute to think of the consequences. Think what could be changed in the future and what the impact will be. You should be able to easily refactor your code. Keep it simple.
    3. Try to use design patterns but don't overdo it. Design patterns provide a clean design that most of the time can be proved a good choice for future changes of requirements. You choose which design pattern might be appropriate for your problem by its intent.
    4. Comment your code; use javadoc and ideally a Software Architecture/Design Document. Unecessary documented code is much better than no comments at all. There you describe your intent, things for other developers to pay attention to, source (e.g. URL) of your algorithm, TODOs, the design pattern you use (or use annotations) etc. Your code is self-explanatory only to you. Not everybody thinks your way. 

JCrete 2013


The JCrete 2013 open conference will take place from 19-22 August and there are still a few empty seats. So don't wait. Book now.
This is the only conference where you can:
  • meet Java Champions and geeks that share the same interests as you
  • learn about the latest technologies in the field
  • get hands-on experience directly from the experts by the swimming pool
  • participate in the organisation of the event (Open Spaces conference or unconference)
  • present your project, your experience, your expertise (all presentations are under Creative Commons-Attribution-ShareAlike 3.0 license)
  • explore Crete and enjoy the Mediteranean sea and sun
  • discover the unique Cretan hospitality and taste the most delicious Cretan cuisine
  • make friends
And as the best things in life, it is FREE!
    This year again we have some top participants/speakers like Java Champions Heinz Kabutz and Kirk Pepperdine, Maurice Naftalin (λ), Martin Thompson (Mechanical Sympathy), Sven Reimers just to mention a few.

    It is going to be an unforgetable event. GUARANTEED!

    UPDATE (5 Sep 2013)! Well, the event is over. It was the best of all we have organised till today. See you next year!

    Δευτέρα 3 Ιουνίου 2013

    Parsing a C/C++ struct in Java

    Assume you are a "lucky" guy that your Java application interfaces with a C/C++ application (e.g. a kind of server) which sends you some kind of TCP/UDP network messages you need to parse. An example such C/C++ structure is shown below:


    enum Gender { MALE, FEMALE };
    struct msg {
      #ifdef INTEL_STYLE
          UCHAR spare4:4;
          UCHAR octal:3;
          UCHAR bool:1;
      #else
          UCHAR bool:1;
          UCHAR octal:3;
          UCHAR spare4:4;
      #endif
      UINT uint;  
      char str[5];
      float flt;

      enum Gender gender;
    }


    If your C/C++ application runs on an INTEL (x86) based machine architecture, then you receive the bits as little endian (see INTEL_STYLE above), otherwise as big endian (e.g. SPARC machines). Note that the JVM is big endian, too. In the following we assume a big-endian architecture.
    In this blog entry we are going to see how you can parse such a message in your receiving Java application. 

    What will you need?

    • the javolution library to parse the C/C++ struct in Java
    • a calculator that handles binaries, hexadecimals and decimals (Windows, Linux and MacOSX already provide such calculators. However, they don't handle decimal point numbers, so this online converter will prove useful, too).
    The following table shows how the C/C++ data types correspond to Javolution Struct.

    C Java (Javolution Struct)
    UCHAR
    Unsigned8
    UWORD
    Unsigned16
    UINT
    Unsigned32
    byte
    Signed8
    short
    Signed16
    int
    Signed32
    long
    Signed64
    long long
    Signed64
    float
    Float32
    double
    Float64
    pointer
    Reference32
    char[]
    UTF8String
    enum
    Enum32

    Let's get started. 

    The following Java class represents the above C/C++ struct in Java:

    import java.nio.ByteBuffer;

    public class Message extends javolution.io.Struct {     
       private final Unsigned8 bool = new Unsigned8(1);     
       private final Unsigned8 octal = new Unsigned8(3);     
       private final Unsigned8 spare2 = new Unsigned8(4);
       private final Unsigned32 uint = new Unsigned32();

       private final UTF8String str = new UTF8String(5); 
       private final Float32 flt = new Float32();  
       private final Enum32 gender = new Enum32(Gender.values());  

       public Message (byte[] b) {         
           this.setByteBuffer(ByteBuffer.wrap(b), 0);     
       }
       
       public boolean getBool() {      
           return bool.get() != 0;     
       }
       
       public int getOctal() {         
           return octal.get();     
       } 

       public long getUInt() {                 
           return uint.get();
       }

       public String getStr() {             

           return str.get();         
       } 

       public float getFlt() {         
           return flt.get();     
       } 


       public Gender getGender() {
           return gender.get();
       }
     }

    enum Gender { MALE, FEMALE };

    Our Message class corresponds to the C msg struct. It extends javolution.io.Struct which is an implementation of the java.nio.ByteBuffer. This crash course about Java ByteBuffer provides useful background information. 
    The C/C++ struct starts with a UCHAR which corresponds to Unsigned8, i.e. one byte. The numbers after the colons (:) denote how many bits inside the byte represent each field of the UCHAR. Thus, octal:3 means that 3 bits represent the octal field. This in Javolution is represented by Unsigned8(3)

    UINT is represented by Unsigned32 in javolution, which is 4 bytes long.
    The string char[5] is represented by UTF8String(5)float by Float32.
    Finally, the enum is represented by Enum32.

    Let's create a unit test to test the above:

    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;

    import static org.junit.Assert.assertEquals;
    import static org.junit.Assert.assertTrue;

    public class MessageTest {

        private Message msg;

        @Before
        public void setUp() {
          byte[] bb = new byte[] {
            (byte) 0x90,  // 1001 0000

            (byte) 0x00, (byte) 0x00, (byte) 0x00, // alignment with previous!
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, // uint
            (byte) 0x48, (byte) 0x41, (byte) 0x4C, (byte) 0x4C, (byte) 0x4F, // str

            (byte) 0x00, (byte) 0x00, (byte) 0x00, // alignment with previous!
            (byte) 0x3F, (byte) 0xC0, (byte) 0x00, (byte) 0x00, // flt
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, // gender
          };
          msg = new Message(bb);
        }

        @After
        public void tearDown() {
        }

        @Test
        public void testMessage() {
           assertTrue(msg.getBool());         // 1 = true
           assertEquals(1, msg.getOctal());   // 001

           assertEquals(2, msg.getUInt());    
           assertEquals("HALLO", msg.getStr());
           assertEquals(1.5, msg.getFlt(), 0.0);   
           assertEquals(Gender.FEMALE, msg.getGender());   
        }
    }



    The first byte 0x90 corresponds to the binary value 1001 0000. The first bit (1) represents bool:1, the next three (001) the octal:3, and the last four (0000) spare:4.  
    Be careful of the alignment! 1 byte + 3 bytes (of alignment) and the next field (uint) starts at the 5th byte and not at the 2nd as you might have expected. 
    The next 4 bytes correspond to the uintThe next 5 ASCII characters correspond to the string "HALLO". Again, another alignment, and then the float field. The last 4 bytes represent the Gender enum which contains the value 1, i.e. Gender.FEMALE.

    Packed 

    However, your data might be packed, i.e. no alignment/padding is happening. To do this, you override the isPacked() method of javolution.io.Struct:

    public class Message extends javolution.io.Struct {
      ...
      @Override
      public boolean isPacked() {
          return true;
      }
      ...
    }

    Now your test case data should contain no padding in order to pass:


    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;

    import static org.junit.Assert.assertEquals;
    import static org.junit.Assert.assertTrue;

    public class MessageTest {

        private Message msg;

        @Before
        public void setUp() {
          byte[] bb = new byte[] {
            (byte) 0x90,  // 1001 0000
       //    (byte) 0x00, (byte) 0x00, (byte) 0x00, // alignment with previous!
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, // uint
            (byte) 0x48, (byte) 0x41, (byte) 0x4C, (byte) 0x4C, (byte) 0x4F, // str
       //    (byte) 0x00, (byte) 0x00, (byte) 0x00, // alignment with previous!
            (byte) 0x3F, (byte) 0xC0, (byte) 0x00, (byte) 0x00, // flt
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, // gender
         };
         msg = new Message(bb);
        }

        @After
        public void tearDown() {
        }

        @Test
        public void testMessage() {
          assertTrue(msg.getBool());         // 1 = true
          assertEquals(1, msg.getOctal());   // 001
          assertEquals(2, msg.getUInt());    
          assertEquals("HALLO", msg.getStr());
          assertEquals(1.5, msg.getFlt(), 0.0);   
          assertEquals(Gender.FEMALE, msg.getGender());
        }
    }

    Conclusion 

    This concludes what you need to know to parse a C/C++ struct in Java. However, keep in mind the following gotchas of Javolution:
    • All Structs should be declared final.
    • Javolution doesn't support nested structs; you need to flaten your C/C++ structs in Java. E.g.
    struct Identification { 
        byte b; 
        long l; 

    struct msg { 
        struct Identification id; 
        int i; 
    }

    should be represented by:


    public class Message extends javolution.io.Struct {     

       private final Signed8 b = new Signed8();     

       private final Signed64 l = new Signed64();     

       private final Signed32 i = new Signed32(); 
    ...
    }

    • Javolution array can only accept members of Struct.Member. The following will not work:
      private final Reference32[] refs = array(new Reference32[2]);

    and you need to replace it by:

      private final Signed32[] refs = array(new Signed32[2]);

    The following won't work neither:
      
    private final AStruct[] aStruct = array(new AStruct[2]);


    Happy parsing!

    (You may wish to write a parser to automatically parse the C/C++ source file and generate a Java java.nio.Struct file based on the above mappings. Please let me know).