Archive for the ‘Misc’ Category

What is software architecture

Friday, December 30th, 2011

Practical definition

Many people have different interpretations of what software architecture actually means. Some people take it as the high level decomposition of the system (subsystems or physical distribution). However, a much better interpretation is simply “the most important design decisions”. What are important design decisions? If they are going to impact what you (or your customer) care the most, then it is important. Typically, if the design decision is going to impact the availability, performance, scalability, security, usability, manageability, maintainability, cost, then it is part of the architecture.

Examples

Below are some examples of architectural decisions:

  • Availability: how to build in redundancy in all the layers (storage, middle tier) and how to fail-over (e.g., client initiated vs virtual IP)? How to handle excessive load (e.g., QoS)? Selecting well proven products with strong support?
  • Scalability: how to scale (scale out or scale up) and load balance?
  • Performance: multi-threading, algorithm, processing in batches?
  • Security: encrypting data against exposure, using HMAC to check data integrity, secure communication, auditing?
  • Manageability: monitoring and operational control (e.g., logging, JMX)? Live upgrading (OK to upgrade just one node at a time in a cluster)?
  • Maintainability: automated tests, using a language, tools and frameworks familiar to the team, proper layering of the code (UI, service, data access layers)?
  • Cost: language, tools and frameworks familiar to the team, open source vs commercial products?

Specifying and maintaining the architecture

I find the best way to specify the architecture is to explain it in use cases (e.g., how to perform fail-over when a certain component fails or how to ensure security in a typical use case).

Also, specifying the architecture is just the first step. Some team members may make sub-optimal architectural decisions in programming without knowing it, or you may realize that your initial decisions can be further improved when you see the code. Therefore, as the architect, your work is far from over and you must keep the architecture (as implemented in the code) fit as the project goes.

A simple but highly useful feature request for DNS

Friday, July 15th, 2011

Most people believe that by having two Windows domain controllers can provide transparent fail over, i.e., if one DC fails, the clients will automatically use the other. However, this is not true. The client will simply use the first DC returned by the DNS. Similarly, if you use DNS to load-balance between multiple web servers, when one of them fails, some clients will still be directed to it.

To fix the problem, there is a very simple solution: enhance the DNS server to perform a health check against the resulting host of the resource record. For example, the administrator could specify the TCP port to connect to as in the imaginary syntax below:

  www        A      1.1.1.1    80     ; return this record only if we can connect to its TCP port 80
  www        A      1.1.1.2    80
  www        A      1.1.1.3    80

Of course, the health check could be more general, then you could use a script:

  www        A      1.1.1.1    web-check.sh  ; return this record only if the script returns true

where the IP would be passed to that script as an argument for checking.

It works for domain controllers too:

  _ldap._tcp.dc._msdcs.foo.com.   SRV  1.1.1.1  dc-check.sh
  _ldap._tcp.dc._msdcs.foo.com.   SRV  1.1.1.2  dc-check.sh

Finally, one might ask why implement this checking in the DNS server instead of the clients? The idea is that problems should be detected as early as possible to avoid bad effects downstream. In concrete terms, if a server is down but the DNS server (broker) still refers the clients to it, many clients will need to perform this health check themselves. But if the DNS server performs this health check, the checking is only done once, saving a lot of trouble downstream.

Architectural improvements for JVM to be enterprise ready

Sunday, May 30th, 2010

Time proven architecture for long running services

I’ve observed that once in a while our long running Tomcat instance will get slower and slower, until it (the JVM) is restarted. Obviously the Tomcat developers are experts in enterprise Java, why is it still happening and how to fix it? One could look for specific problems in the code, but a much better approach is to adopt a time proven architecture, particularly well-known in traditional Unix daemon processing:

  1. The master daemon process is started.
  2. The master daemon process spawns some child processes to handle client requests
  3. After handling a limited number of requests, a child process will terminate itself (or done by the master). The key point here is that the OS will free any resources (e.g., memory, file handles, sockets) allocated to that child process; there is no way to leave anything behind after its death.

This architecture ensures a long-running service without any degrading, even if the code is poorly written and has resource leaks.

How can Java support this architecture?

So, does Java support this currently? The answer is no. To do that:

  1. The JVM needs to support the  concept of isolated process.
  2. Objects created by the JVM itself and different a process must NOT be allowed to refer to one other, otherwise there would be no way to cleanly kill a process.
  3. The JVM must allow efficiently forking a process to quickly create a child process. This way, the master process can perform all kinds of lengthy initialization (e.g., Hibernate and Spring initialization), while it is still very quick to spawn a child in the initialized state.

Open letter to certification providers

Friday, May 21st, 2010

Dear certification providers,

In recent months I’ve interviewed three candidates with CCNP certifications and I was very disappointed to find that two of them didn’t know how a switch differs from a hub or how it learns the MAC addresses. My first reaction was my disappointment with the lack of integrity of the people and the general availability of brain dump or even real test questions. However, from a more positive view, this has stroked me to think about what we can do to help you improve the situation?

If we consider certifications as a service in the perspective of quality management, then we can clearly see there is a huge problem in it: the exam candidate is both a client and a user (and also a piece of client-provided material :-) ), but there are many other users of this service out there; they are the prospective employers, job interviewers, peers and etc. A key requirement in quality management is to measure if the users are satisfied with the service output. Obviously, as a prospective employer, I am very unhappy with the service output because the CCNP certificate is not reflecting the real expertise of the certificate holders. However, none of you are providing ways for unhappy users like me to provide feedback on your service output. Without such a feedback mechanism, I really don’t see how you can ensure the quality of your service.

Therefore, I’d request that you establish a mechanism to accept feedback. For example, provide a website to let me report on those certificate holders who obviously know little about the subject matter. Then follow up with investigation, re-certify as required and revoke their certificates. Just like a digital certificate whose private key has been compromised, such revoked certificates should be published on a website like a CRL.

This is about handling an individual incident. If there are a significant number of such incidents, you should escalate to become a problem (in ITIL term). It means that you must then identify the root cause and to plug the hole to prevent similar incidents, like introducing performance-based exams, reference-based certifications and whatever it takes to fix the problem and save your reputation.

TDD adapted for mere mortals

Sunday, February 7th, 2010

TDD adapted for mere mortals

I’ve been teaching and practicing agile for several years and there is definitely a problem with TDD: People find it very difficult to use. I believe there are certain points, either in the TDD itself or in people’s interpretation of it, that should adapted (at least for mere mortals):

Writing test before code

It is definitely a very good practice to interweave coding and testing. This is what we programmers want to do; we feel the urge to test run a certain piece of code as it feels complicated. However, writing the test before code is not a natural way in many cases. For example, let’s consider a BookService class. You’d like to implement its borrow(String borrowerId, String callNo) method. If you insists on writing the test first, you’ll have to think very hard what collaborators the BookService object will use. It is not only difficult, but most likely incorrect. A much more effective way is to write the borrow() method first, then you can see what collaborators it needs (e.g., a BookDAO, a BorrowerDAO, a system clock and etc).

Most TDD demos don’t have this problem because they work on classes that need no collaborators, for example, stacks, calculators.

Note that I am not advocating writing the complete code before writing the test; we should build the functionality in suitable steps. For mere mortals, try to implement the basic functionality first, then test it, then write more code and then more test.

My suggestion is to replace "writing test before code" with "interweaving coding and testing".

Take the smallest step that makes the test pass

I agree that we shouldn’t write too much code without test-running the code. If we do, it’s difficult to isolate the bug. But why always take the smallest step if we are pretty sure that it is going to work? The size of the step depends on the complexity of the code. We shouldn’t take too large a step (hard to isolate a bug), nor too small a step (waste of time).

The whole idea is a well-established principle in testing: Risk-based testing. That is, we should put more effort on testing high-risk code, and less on low-risk code. Programmer’s effort is the most scarce resource in software development projects. So, we should prioritize its use wisely.

My suggestion is to replace "take the smallest step possible" with "take the smallest step before you’re worried with the correctness of the code".

If you aren’t doing TDD, you aren’t professional

This is not defined in TDD, but many people believe it. I think this is against the agile manifesto which says we should value people over process. Forcing TDD into people’s throats is exactly the opposite. If people have tried but it doesn’t help them, they will simply not use it. It’s that simple. People should have every right to use whatever works best for them.

In fact, most programmers like testing: they feel the urge to test run the code if it gets complicated. It’s just that writing the test before code is so difficult and against their nature. Therefore, our process should work with their nature, not against it.

My suggestion is to replace "every professional programmer should do TDD" with "every professional programmer should keep looking for their own best practices".

TDD helps you design the API of your code

This doesn’t make much sense to me at all. The user requirement guides you in implementing your UI classes. When implementing the UI classes, you are guided to design the API of your service classes. When implementing your service classes, you are guided to design the API of your DAO classes.

The real design aspect of TDD is not about the design of the API, but to make sure your code is loosely-coupled and thus is easy to test.

My suggestion is to replace "TDD helps you design the API" with "testing helps make your code loosely-coupled".

 

Making your manual mocks resistant to interface changes

Sunday, January 31st, 2010

Making your manual mocks resistant to interface changes

Suppose that you’d like to unit test the code below:

 public class BookService {
    private Books books;
    private Patrons patrons;
    
    public void borrow(String patronCode, String callNo) {
        Book b = books.get(callNo);
        Patron p = patrons.get(patronCode);
        if (b.isOnLoan()) {
            throw new RuntimeException("already on loan");
        }
        b.addBorrowRecords(new BorrowRecord(p, new Date()));
    }
}

public interface Books {
    Book get(String callNo);
}

public interface Patrons {
    Patron get(String patronCode);
}

You’ll need to mock the two DAO objects: Books and Patrons. Usually I will hand-create these mock objects instead of using mock frameworks (in order to access the fields of the test case in a mocked method. For the other reasons, see Uncle Bob’s article). So, the test may look like:

 public class BookServiceTest extends TestCase {
    private Book b123 = new Book("123", "Java programming");
    private Patron kent = new Patron("001", "Kent");

    public void testBorrow() throws Exception {
        BookService bs = new BookService();
        bs.setBooks(new Books() {
            @Override
            public Book get(String callNo) {
                return callNo.equals("123") ? b123 : null;
            }
        });
        bs.setPatrons(new Patrons() {
            @Override
            public Patron get(String patronCode) {
                return patronCode.equals("001") ? kent : null;
            }
        });
        bs.borrow("001", "123");
        List<BorrowRecord> records = b123.getBorrowRecords();
        assertEquals(records.size(), 1);
        BorrowRecord record = records.get(0);
        assertEquals(record.getPatron().getName(), "Kent");
    }
}

The problem is that if you later add a method to the DAO interfaces such as:

public interface Books {
    Book get(String callNo);
    void add(Book b);
}

Your unit test code will break because you aren’t implementing the add() method. To avoid this problem,  the idea is to first create an (abstract) mock class implementing only the needed methods such as get(). Then use an automatic way to further create a subclass that provide all the dummy methods. To do the latter, one can use cglib. Here is an example:

public class BookServiceTest extends TestCase {
    private Book b123 = new Book("123", "Java programming");
    private Patron kent = new Patron("001", "Kent");

     public abstract class MockedBooks implements Books {
        @Override
        public Book get(String callNo) {
            return callNo.equals("123") ? b123 : null;
        }
    }
    public void testBorrow() throws Exception {
        BookService bs = new BookService();
        bs.setBooks(mock(MockedBooks.class));
        bs.setPatrons(new Patrons() {
            @Override
            public Patron get(String patronCode) {
                return patronCode.equals("001") ? kent : null;
            }
        });
        bs.borrow("001", "123");
        List<BorrowRecord> records = b123.getBorrowRecords();
        assertEquals(records.size(), 1);
        BorrowRecord record = records.get(0);
        assertEquals(record.getPatron().getName(), "Kent");
    }
    @SuppressWarnings("unchecked")
    private <T> T mock(Class<T> c) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(c);
        enhancer.setCallback(NoOp.INSTANCE);
        //Because MockedBooks is a non-static inner class, need to provide the outer instance
        return (T) enhancer.create(new Class[] { getClass() },
                new Object[] { this });
    }
}

 To make the code reusable in multiple test cases, just extract it into a base class:

public class ChangeResistantMockTest extends TestCase {
    @SuppressWarnings("unchecked")
    public <T> T mock(Class<T> c) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(c);
        enhancer.setCallback(NoOp.INSTANCE);
        return (T) enhancer.create(new Class[] { getClass() },
                new Object[] { this });
    }
}

public class BookServiceTest extends ChangeResistantMockTest {
    private Book b123 = new Book("123", "Java programming");
    private Patron kent = new Patron("001", "Kent");

     public abstract class MockedBooks implements Books {
        @Override
        public Book get(String callNo) {
            return callNo.equals("123") ? b123 : null;
        }
    }
&
nbsp;   public void testBorrow() throws Exception {
        BookService bs = new BookService();
        bs.setBooks(mock(MockedBooks.class));
        …
    }
}

Acknowledgement: I got this idea from the Scala mailing list.

Installing MIT Scratch on Kubuntu 9.10

Friday, January 1st, 2010

Installing MIT Scratch on Kubuntu 9.10

Below are the steps to get Scratch working, including playing audio (recording quality is still quite poor, but you can always record outside of Scratch).

Install PulseAudio

$ aptitide install pulseaudio pulseaudio-utils

Install the latest squeak

The Squeak package included in Ubuntu 9.10 can’t play audio (wav). Fortunately, the latest version (3.11.3.2135) works. So, go to http://www.squeakvm.org/unix to download the binary package. However, if you try to download the .deb package, it will say that you don’t have the permission. So, download the rpm install and then convert it:

$ alien Squeak-3.11.3.2135-linux_i386.rpm
$ dpkg -i squeak_3.11.3.2135-2_i386.deb

Install Scratch 1.4

Download the Scratch source from http://info.scratch.mit.edu/Source_Code. Unzip it and you will get the VM file ScratchSourceCode1.4.image. Before you can run it, you need to know that it relies on some "plugins" that are written in C language for each platform. So, download the source code to the plugins from that same page. Then compile them. The package contains three plugins: take one of the plugin called ScratchPlugin as an example:

$ cd ScratchPluginSrc1.4
$ cd ScratchPlugin/ScratchPlugin-linux/
$  ./build.sh
$ sudo cp ScratchPlugin /usr/lib/squeak/3.11.3-2135/so.ScratchPlugin

For the UnicodePlugin, you need to do some extra steps:

$ su aptitude install libpangomm-1.4-dev
$ su aptitude install libcairo2-dev
$ add an option no-stack-protector to the gcc command in the unixBuild.sh file:
       ….
       gcc -fno-stack-protector -fPIC -Wall -c `pkg-config –cflags pangocairo` *.c
       ….
$  ./unixBuild.sh
$ sudo cp UnicodePlugin /usr/lib/squeak/3.11.3-2135/so.UnicodePlugin

Running it

To run Scratch, type:

$ squeak ScratchSourceCode1.4.image

It should work.

open source web-based centralized console for tripwire

Sunday, December 6th, 2009

When using tripwire to monitor changes on multiple servers, it is common to have to review and accept changes on a daily basis. Logging into multiple servers to accept the changes is troublesome. So, I’ve created a  web-based centralized console to review and accept changes. It is GPL licensed and can be downloaded from http://centralwire.sourceforge.net. Hope it is useful to others.

Handling BLOB/CLOB in postgreSQL with JDBC/Hibernate

Friday, December 4th, 2009

Handling BLOB/CLOB in postgreSQL with JDBC/Hibernate

What is a BLOB/CLOB? It is a large object (binary for BLOB and char for CLOB). It is commonly used when you’re storing large files into the database as column values.

It was really a challenge to work with BLOB/CLOB and in the process I almost pulled my hair out. Below are the hard lessons learned:

  • Avoid using LOB if possible! If say, it is just a few KB in size, just treat it as a string or byte array.
  • You must NOT try to read the stream outside the transaction. Note that using the open session in view is NOT enough. Once the transaction is ended, even if the Hibernate session is still open, you still can’t read it (you’ll get the "invalid large object descriptor" exception).
  • You must NOT try to read a LOB twice in the transaction. The "pointer" can’t seem to be reset so you read past some portion, you can’t read it again.
  • I still haven’t figured this one out: If you repeatedly read a row containing a LOB in different transactions, it may cause the same "invalid large object descriptor" when you try to read it in a new Hibernate session.

Javablackbelt a rip off?

Sunday, October 4th, 2009

I always thought that javablackbelt was a non-profit community, but actually it is not. It is actually selling the questions people submit for profit! I think this is ethnically not right:

  1. It always advertises as a community, but actually it is a for-profit company.
  2. It calls the license copyleft, but actually it is not Gnu copyleft. It explicitly grants itself the right to sell the questions.
  3. It should highlight this term. Currently there is no obvious license displayed when people try to submit a question.
  4. This is unlike RedHat making money from open source software because that software is licensed by the authors to be freely available for anyone, so RedHat has to provide its own added value. If javablackbelt is going to sell the questions, they should share the profits with the authors.