Software
Archived Posts from this Category
Archived Posts from this Category
I recently did a talk with a group of IT professionals on Agile Development practices. It must have not sounded like a normal Agile talk because the organizer came back and asked if I wanted to change the title for the transcript. The new title is “Software Simplicity: Doing More by Coding Less”. The basic premise is that, in aggregate, the biggest determinant of software quality is the number of lines of code required to meet a business function. Think of business and utility function as an asset and lines of code as a liability. I believe this for both the simple fact that more lines of code mean more bugs, and the more subtle fact that less lines of code reflects a more deft approach to software. Software is a craft where quality usually goes up when one hits the delete key because a better design has made bad form out of certain verbosity. Every line of code must prove its worth. Pack your apps with less, not more. To borrow from XP: YAGNI.
The theme of this talk arose from recent work I have been doing getting a large team up to speed on a relatively large project. The main challenge of the project was the number of people involved. I found two keys to success:
(1) Model a super clean application with a good application stack: The abstractions should be not too opaque (I still think SQL is a good thing), but not too thin (Something is wrong if I have to close a JDBC connection or pull a parameter from HttpServletRequest). My favorite is: Struts2, Spring, Spring Security, iBatis, running jetty under Maven. The code should be as minimal as possible and impeccably clean. You cannot elimate entropy in the process, but at least you can keep the energy state high and organized to start to positively influence the end state.
(2) Mentor mentors. Start with a small group. Work together. Lean from each other. Make the stated goal for the this prototypical team to produce work like it came from a single developer. Add more developers when the base of mentors can support it. Keep the mentoring cycle alive throughout the entire project.
Nothing magical, kinda boring. But it works.
0 comments Wednesday 04 Mar 2009 | btomasini | Software
I use EasyMock extensively to create mock objects for unit testing. The behavior verification is great for thoroughly testing an object’s interactions with other objects, known as collaborators. Sometimes, however, a mock cannot do all that is needed. Martin Fowler, in his article “Mocks aren’t Stubs”, identifies injected collaborators, or “test doubles”, as being mocks or stubs. Using EasyMock, it is possible to create an object which is both.
I recently ran into a scenario where I needed such a hybrid. Consider save method the following Struts action. This method handles both new and existing products, differentiated by the nullity of the id property of product.
Here is the class under test:
public class CustomerEditAction extends ActionSupport implements Preparable {
private CustomerDao customerDao;
private Long id;
private Customer customer;
public void setCustomerDao(CustomerDao customerDao) {
this.customerDao = customerDao;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public void prepare() throws Exception {
/* Sets up the id and the customer. Removed for brevity */
}
public String save() {
if (customer.getId() == null) {
customerDao.insert(customer);
setId(customer.getId());
} else {
customerDao.update(customer);
}
return Action.SUCCESS;
}
And here is the collaborating dao:
public interface CustomerDao {
List getAll();
Customer getForId(Long id);
void insert(Customer customer);
void update(Customer customer);
}
Testing the “update” case of the save method where product.getId() is not null with a mock object is simple, all we need to verify that the update method of product dao is called with the right argument.
The “insert” case is not as straightforward, and is a case where a simple mock is not sufficient.
This issue is with verifying the additional step of setting the id of the product to the action after the insert is performed. It is assumed that the productDao itself modifies the id of the product after inserting it into the database. Since a mock object is just an empty shell which follow scripted behaviors without any implementation, there is no way to use one to actually modify the product as the actual dao would. But without actually modifying the product passed as an argument to productDao, there is no way to verify that the id property of the action is set with the value from the id property of the product. The alternative is to use a stub in our test case instead of a mock, like the following:
private static abstract class StubCustomerDao implements CustomerDao {
static final Long ID = 9999L;
public void insert(Customer customer) {
customer.setId(ID);
}
}
The class is actually an inner class of my test class. It is abstract for a reason - keep reading for the explanation.
The resulting unit test for the insert case would be:
public class CustomerEditActionTest {
private CustomerEditAction action;
private StubCustomerDao customerDao;
private Long id;
private Customer customer;
@Before
public void setUp() throws Exception {
action = new CustomerEditAction();
/*
* Here we are creating a mock of our stub, a private inner class
*/
customerDao = createMock(StubCustomerDao.class,
StubCustomerDao.class.getMethod("getForId", Long.class),
StubCustomerDao.class.getMethod("update", Customer.class));
id = 1L;
customer = new Customer();
customer.setId(id);
action.setCustomerDao(customerDao);
}
/* Some tests removed for brevity */
@Test
public void testSaveInsert() {
reset(customerDao);
customer.setId(null);
action.setCustomer(customer);
replay(customerDao);
assertSame("result not success", Action.SUCCESS, action.save());
assertEquals("customer id is equals", StubCustomerDao.ID,
action.getId());
verify(customerDao);
}
@Test
public void testSaveUpdate() {
reset(customerDao);
action.setCustomer(customer);
customerDao.update(customer);
replay(customerDao);
assertSame("result not success", Action.SUCCESS, action.save());
verify(customerDao);
}
/* Stub class */
private static abstract class StubCustomerDao implements CustomerDao {
static final Long ID = 9999L;
public void insert(Customer customer) {
customer.setId(ID);
}
}
}
Switching from a mock to a stub for the insert method means that I am exclusively verifying state, and no longer verifying behavior. Asserting that the product id and the action have the correct value in their id property gives me reasonable assurance that the action is doing what I want it to do.
But why an abstract class for ProductDaoStub? Because I only want to use a stub for this one test method. It still makes sense to use a mock for calls to to the other methods of the class, like update and getForId. This is where the class extension of EasyMock really shines. With the class extension MockControl, mocks can be created from concrete types, like HttpServletRequest, not just from interface types like ProductDao. By default, a class mock causes all methods to be mocked. You can, however, specify that only certain methods be mocked, and the rest of the class methods are invoked in the class itself. I am using this feature to mock my stub. This gives me all of the power of a mock and the ability to carve out a stub for the one method which needs it. This table shows the effect:
| Method | interface ProductDao | ProductDaoStub | Mock of ProductDaoStub | Net Effect |
|---|---|---|---|---|
| getAll | unimplemented | unimplemented | unimplemented | unimplemented |
| getForId | unimplemented | unimplemented | mocked | mocked |
| insert | unimplemented | stubbed | unimplemented | stubbed |
| update | unimplemented | unimplemented | mocked | stubbed |
The full code can be browsed here and checked out with the following command:
svn co http://bentomasini.com/svn/repo1/demos/mockstub/tags/TAG-mockingAStub mockstub
Update: Fixed a bug in the unit test where the customer’s id was being asserted and not the action’s id. That kinda misses the whole point.
0 comments Wednesday 05 Mar 2008 | btomasini | Software, Java, EasyMock, JUnit
Howard Lewis Ship has added an IoC Overview document to the Tapestry IoC project. It’s goal is an important one, helping developers “get” IoC.
For me, “getting” IoC was a big event. It happened to me in early 2004 when I was working on a workflow engine for a large back office application for a bank. A friend of mine told me I should check out HiveMind (the predecessor to Tapestry IoC). Using it, I found I was able to develop more sophisticated, more testable code with less grunt work. The dots between object oriented design and application assembly were connected elegantly.
The document mentions that style of code that works best when using an IoC container:
When thinking in terms of IoC, small is beautiful. What does that mean? It means small classes and small methods are easier to code than large ones. At one extreme, we have servlets circa 1997 (and Visual Basic before that) with methods a thousand lines long, and no distinction between business logic and view logic. Everything mixed together into an untestable jumble.
At the other extreme is IoC: small objects, each with a specific purpose, collaborating with other small objects.
Using unit tests, in collaboration with tools such as EasyMock, you can have a code base that is easy to maintain, easy to extend, and easy to test. And by factoring out a lot of plumbing code, your code base will not only be easier to work with, it will be smaller.
The document ends with the concept that IoC does for object creation what garbage collection does for object destruction: takes it out of your hands and does it better (here is an older blog post on that same topic). I think the Guice project captures this concept the best when describing their @Inject annotation, calling it “the new new“.
0 comments Monday 12 Nov 2007 | btomasini | Software, Java, IoC, Tapestry
I recently started searching for a SOAP framework and took a look at Axis2. Actually, I looked at it twice. The first time I passed because the deployment model was too confusing. Only after evaluating the downsides of the other frameworks did I take a second look. I eventually went with it after I figured out how to get it to meet my two main requirements:
I put together a sample project which demonstrates a simple approach to Axis2. The application exposes a single web service for retrieving products from a catalog. The service has two methods: getAll, and getForId.
The sample project can be found at http://bentomasini.com/svn/repos/demos/catalog/trunk. To try it out, checkout the source and start the application by doing the following. Maven2 is required.
svn co http://bentomasini.com/svn/repos/demos/catalog/trunk catalog
cd catalog
mvn jetty:run
Now open http://localhost:8080/catalog. From there you can open the WSDL and run a few operations using the quasi-RESTful Axis2 interface. To call the service using SOAP, or to generate clients for various SOAP frameworks, I recommend using soapUI. Just create a new WSDL project using the WSDL URL linked from the home page.
The project’s service class, shown below, calls the injected dao and converts List<Product> to Product[]. SOAP frameworks choke on collections.
package com.bentomasini.catalog;
import com.bentomasini.catalog.Product;
import com.bentomasini.catalog.dao.ProductDao;
/**
*
* @author btomasini
* @since Jul 15, 2007
*
*/
public class ProductService {
private ProductDao productDao;
public void setProductDao(ProductDao productDao) {
this.productDao = productDao;
}
public Product[] getAll() {
return productDao.getAll().toArray(new Product[0]);
}
public Product getForId(Long id) {
return productDao.getForId(id);
}
}
The applicationContext.xml located in WEB-INF wires up the Spring bean and its dao:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="productDao" class="com.bentomasini.catalog.dao.impl.ProductDaoImpl"/>
<bean id="productService" class="com.bentomasini.catalog.ProductService">
<property name="productDao" ref="productDao" />
</bean>
</beans>
The method I used to configure Axis2 is key to keeping the project simple. It also requires some background explanation. The Axis2 folks have a concept that developers should package their web services in a new type of archive, an aar, and deploy that aar into a canned Axis2 web application. This makes me scratch my head and go “huh?” I don’t think most developers want to do this. I know I don’t. I simply want to build a web application, specify some services, and package my application in one single application archive - a war.
The good news is that developers don’t have to create aar archive files. Taking a look at the aar deployment model, we see that these service archives are deployed into WEB-INF/services. Alternatively, service archives can be exploded into a directory by the same base name. So WEB-INF/services/ProjectService.aar can instead by deployed by exploding its contents into the directory WEB-INF/services/ProjectService. The magic file in the archive is META-INF/services.xml. It defines the services to be deployed by Axis2. This file can contain a single service definition, or multiple service definitions inside of a service-group element.
We can do away with all of this hoo-ha by having a single services.xml for our entire project. Just pick a generic name for the directory, say “WebService”. Now we can put a single file in our project to define services: WEB-INF/services/WebService/META-INF/services.xml. Just put all of your service definitions in there and enjoy the simplicity. Here is the services.xml file from the sample project:
<?xml version="1.0" encoding="UTF-8"?>
<serviceGroup>
<service name="ProductService">
<parameter name="ServiceObjectSupplier" locked="false">
org.apache.axis2.extensions.spring.receivers.SpringServletContextObjectSupplier
</parameter>
<parameter name="SpringBeanName" locked="false">productService</parameter>
<operation name="getForId">
<messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
</operation>
<operation name="getAll">
<messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
</operation>
<excludeOperations>
<operation>setProductDao</operation>
</excludeOperations>
</service>
<!-- Add your second service here -->
</serviceGroup>
The service element configures our service for deployment and specifies a special ServiceObjectProvider which knows how to obtain the service from our Spring context. The name of the Spring bean is also provided. Each operation has an operation element and text marking it as an RPC method. In addition, our setProductDao method is excluded because it is only meant for use by our IoC container for dependency injection. Adding another operation or service is simply a cut-and-paste exercise.
The web.xml to load both Spring and Axis2:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>AxisServlet</servlet-name>
<servlet-class>org.apache.axis2.transport.http.AxisServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
</web-app>
That’s it!
0 comments Sunday 22 Jul 2007 | btomasini | Software, Java, Axis, Spring
There is a lot to like about Restlet, including even the the way they name their artifacts. You can check it out in their maven repository. Instead of just naming their jar restlet-1.0.1.jar, they name it with the full base package name: org.restlet-1.0.1.jar. That name better represents the actual name of the module. It also makes it easier to track down which class belongs to which jar, which can be helpful when you have to manually assemble a set of jars for a driver or other resource connector not in your main project.
I am going to adopt this convention for my projects from here on out, and hope other projects will as well.
0 comments Sunday 03 Jun 2007 | btomasini | Software, Java
This article on Slashdot got me thinking about learning Assembler. It’s crazy. Why spend the time to learn a language with I will never use directly in my career?
It is very much like the time in 5th grade when I took my entire BMX bike apart just so I could put it back together. (and discovered it had three extra parts
). I would really like to know how a computer actually works beyond the high level languages I work with.
Maybe I am interested in the challenge simply “because it’s there”.
This how-to looks like a good start: http://www.linuxdocs.org/HOWTOs/Assembly-HOWTO.
1 comment Sunday 25 Mar 2007 | btomasini | Software, Curiosity