Archive for January, 2009
By three methods we may learn wisdom
Jan 31st
First, by reflection, which is noblest;
second, by imitation, which is easiest;
and third, by experience, which is the bitterest.
- Conficius
(I loved the quote. As seen in Up the Yangtze)
Practice makes perfect
Jan 23rd
I’ve finally brought down the TumblrJ service class to it’s easiest use. The cool thing with this design is that for 99% of use cases, you can use the defaults, and for those times when you’re in a bind or need finer grained control over the construction of the objects, you can do that as well. Here it is:
Read all:
TumblrService service = new TumblrService("myblogname");
TumbleLog log = service.read();
Read with a filter:
TumblrReadOptions readOptions = new TumblrReadOptions();
readOptions.setType(TumblrType.REGULAR);
TumblrService service = new TumblrService("myblogname");
TumbleLog log = service.read(readOptions);
Well, you get the idea. Basically, no more configuration of the TumblrHttpReader, TumblrHttpOptions and TumblrJProperties. No nonsense defaults are used and hidden inside the TumblrService class.
Unit testing ehcache (Take #2)
Jan 23rd
My solution works, but there was something smelly in there. I wasn’t satisfied with the way I was checking to ensure that the cache had actually been accessed. Given that the notification interface doesn’t define a method to find that out, I had sort of tricked it ….
Well, I obviously couldn’t leave it at that. So the solution to a better smelling cache unit test lies below (tip: use the Statistics information that’s right there on the cache, but I hadn’t noticed)
import junit.framework.Assert;
@Test
public void testCache() throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
DataFacade dataFacade = (DataFacade) context.getBean("cacheInjectedDataFacade");
TestCacheListener listener = new TestCacheListener();
Cache cache = dataFacade.getCache();
cache.getCacheEventNotificationService().registerListener(listener);
dataFacade.getData();
Assert.assertEquals(ListenerStatus.ELEMENT_ADDED, listener.getLastStatus());
Assert.assertNotNull(cache.get(DataFacade.CACHE_KEY));
listener.resetLastStatus();
Assert.assertEquals(listener.getLastStatus(), ListenerStatus.RESET);
dataFacade.getData();
Assert.assertEquals(1, cache.getStatistics().getCacheHits());
Thread.sleep(2500);
dataFacade.getData();
Assert.assertEquals(ListenerStatus.ELEMENT_ADDED, listener.getLastStatus());
}
Also, remember to reset your cache through cache.removeAll() between tests (through the @BeforeTest) or else your cache hits won’t jive.
Using TumblrJ to write posts, read credentials and running the unit tests
Jan 19th
Some more progress with the api. This post will be about writing a post using the API, then reading a users credential information and I’ll finish off with the specifics on running the unit tests.
All code examples will focus on using the code through Spring, but this can all be done without Spring very easily (i.e.: Instead of building your instances through DI, just build them in the code yourself).
Writing
Same as with reading Tumblr information, you’ll need to:
- Setup an instance of the TumblrService class
- That class in turn needs a properly configured ITumblrReader instance. Since there’s only one implementation of that interfae, you’ll use TumblrHttpReader
- That in turns needs a TumblrConnectionOptions object with at the very minimum the name of your Tumblr log.
The small difference with here is that the write() method needs to be given a Credentials object to work.
Therefore, the Spring configuration would look something like:
<beans>
<bean id="tumblrJProperties" class="org.mikem.tumblr.api.util.TumblrJProperties"/>
<bean id="connectionOptions" class="org.mikem.tumblr.api.http.TumblrConnectionOptions">
<property name="name" value="${logname}"/>
</bean>
<bean id="reader" class="org.mikem.tumblr.api.http.TumblrHttpReader">
<property name="tumblrConnectionOptions" ref="connectionOptions"/>
<property name="properties" ref="tumblrJProperties"/>
</bean>
<bean id="credentials" class="org.mikem.tumblr.api.util.Credentials">
<property name="email" value="${email}"/>
<property name="password" value="${password}"/>
</bean>
<bean id="service" class="org.mikem.tumblr.api.TumblrService">
<property name="reader" ref="reader"/>
</bean>
</beans>
In the above configuration, you’ll need to replace the ${} variables with your own values.
A test case to go with this configuration would then look something like:
@Test
public void testWrite() throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("test-spring-context.xml");
TumblrService service = (TumblrService) context.getBean("service");
Credentials credentials = (Credentials) context.getBean("credentials");
RegularPost post = new RegularPost();
post.setBody("Test post");
post.setPrivatePost(true);
post.setTitle("Test post title");
TumblePost savedPost = service.write(post, credentials);
Assert.assertNotNull(savedPost);
Assert.assertNotNull(savedPost.getId());
}
Simple enough! Notice that for now, only RegularPost has been tested.
Reading credentials
The Tumblr api offers a way to pull out all the relevant information for a user. To get that information, and using the same Spring configuration outlined above, you’d do something like:
@Test
public void testReadAuthenticationInformaiton() {
ApplicationContext context = new ClassPathXmlApplicationContext("test-spring-context.xml");
TumblrService service = (TumblrService) context.getBean("service");
Credentials credentials = (Credentials) context.getBean("credentials");
User user = service.getUserInformation(credentials);
Assert.assertNotNull(user);
Assert.assertTrue(user.getUserTumblelogs().size() > 0);
}
Check out the User object to see the wealth of information returned by Tumblr.
Running the tests
The unit tests found in the source code are tightly coupled to Tumblr itself, and by extension a users log, email and password. Therefore, so that everyone may run the tests on their own log and with their own credentials, all tests are devised to be configured against a file called private-test-config.properties. That file should be found on the classpath.
The contents is straightforward enough:
logname=mylogname
email=myemail
password=mypassword
If you look at the @Before method of the BaseServiceTest class, you’ll notice the call to that file. Again, if the file isn’t present on the classpath, the tests will fail miserably. I haven’t checked that file in for obvious reasons!
Unit testing ehcache
Jan 17th
I just had to write some unit tests to make sure my caching mechanism was working properly. Obviously, there are better ways to do this, but for what I needed, it was ample. Any suggestions are definitely welcome.
Setup
We’ll start with a simple service class in which all caching manipulations are done from. The class is kept simple so as to not obfuscate what I’m really trying to show.
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;
public class DataFacade {
private static final String CACHE_KEY = "mykey";
private Cache cache;
public String getData() {
Element element = cache.get(CACHE_KEY);
if (element != null && element.getValue() != null) {
return (String) element.getValue();
} else {
String data = "lama";
cache.put(new Element(CACHE_KEY, data));
return data;
}
}
public Cache getCache() {
return cache;
}
public void setCache(Cache cache) {
this.cache = cache;
}
}
Spring Setup
Now, we need to write a test to ensure that the cache is being hit and expired properly. To do this, we’ll need to setup a test listener that will be injected into the Cache object used by the service class. Using spring, this is pretty easy, but we can also hand code it.
We’ll need a spring context configuration file somewhere in the classpath.
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="cacheInjectedDataFacade" class="org.mikem.DataFacade">
<property name="cache" ref="cache"/>
</bean>
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache-config.xml"/>
</bean>
<bean id="cache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<ref local="cacheManager"/>
</property>
<property name="timeToIdle" value="2"/>
<property name="timeToLive" value="2"/>
<property name="eternal" value="false"/>
<property name="diskPersistent" value="false"/>
<property name="cacheName" value="org.mikem.lamacache"/>
</bean>
</beans>
The things to watch out for here are:
- We’re not using a ehcache.xml confguration file. All config is done through spring.
- The package names should be changed to reflect where your own DataFacade is
- Notice the timeToIdel and timeToExpire properties on the cache bean. More on that later
Unit test and the cache event listener
Now we’re ready to write the unit test related code. We’ll first need an implementation of the net.sf.ehcache.event.CacheEventListener interface. That implementation should look like the following:
public class TestCacheListener implements CacheEventListener {
public static enum ListenerStatus {
RESET,
DISPOSED, ELEMENT_EVICTED, ELEMENT_EXPIRED, ELEMENT_ADDED,
ELEMENT_REMOVED, ELEMENT_UPDATED, REMOVED_ALL,
};
public ListenerStatus lastStatus;
public ListenerStatus getLastStatus() {
return this.lastStatus;
}
public void resetLastStatus() {
this.lastStatus = ListenerStatus.RESET;
}
public void dispose() {
this.lastStatus = ListenerStatus.DISPOSED;
}
public void notifyElementEvicted(Ehcache arg0, Element arg1) {
this.lastStatus = ListenerStatus.ELEMENT_EVICTED;
}
public void notifyElementExpired(Ehcache arg0, Element arg1) {
this.lastStatus = ListenerStatus.ELEMENT_EXPIRED;
}
public void notifyElementPut(Ehcache arg0, Element arg1) throws CacheException {
this.lastStatus = ListenerStatus.ELEMENT_ADDED;
}
public void notifyElementRemoved(Ehcache arg0, Element arg1) throws CacheException {
this.lastStatus = ListenerStatus.ELEMENT_REMOVED;
}
public void notifyElementUpdated(Ehcache arg0, Element arg1) throws CacheException {
this.lastStatus = ListenerStatus.ELEMENT_UPDATED;
}
public void notifyRemoveAll(Ehcache arg0) {
this.lastStatus = ListenerStatus.REMOVED_ALL;
}
}
What this gives us is a listener class which we’ll inject into the cache. On each cache event, the last status member will be updated.
Now for the finale:
import junit.framework.Assert;
import net.sf.ehcache.Cache;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.stw.sandbox.TestCacheListener.ListenerStatus;
public class TestDataFacade {
@Test
public void testCache() throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
DataFacade dataFacade = (DataFacade) context.getBean("cacheInjectedDataFacade");
TestCacheListener listener = new TestCacheListener();
Cache cache = dataFacade.getCache();
cache.getCacheEventNotificationService().registerListener(listener);
dataFacade.getData();
Assert.assertEquals(ListenerStatus.ELEMENT_ADDED, listener.getLastStatus());
Assert.assertNotNull(cache.get(DataFacade.CACHE_KEY));
listener.resetLastStatus();
Assert.assertEquals(listener.getLastStatus(), ListenerStatus.RESET);
dataFacade.getData();
Assert.assertEquals(ListenerStatus.RESET, listener.getLastStatus());
Thread.sleep(2500);
dataFacade.getData();
Assert.assertEquals(ListenerStatus.ELEMENT_ADDED, listener.getLastStatus());
}
}
Explanation:
- Lines 14 and 15 are the spring access and retrieval of the DataFacade instance
- Lines 17 through 19 take care of creating a new instance of the TestCacheListener and injecting it into the data facade instance
- Line 21 runs the method where we have some cache access going on
- Line 22: Because our last line actually put something in the cache, our cache listeners status will have changed. Here we’re making sure the status has been changed accordingly.
- Line 23: Make sure we have data in the cache (we could also check that the content is right)
- Line 25: Reset the last status on the listener
- Line 28: Fetch the data once again. At this point, the listeners last status will remain to RESET since it won’t have been put into the cache anew.
- Line 31: Because we configured our timeToIdle and timeToExpire to 2 seconds (see the spring config), we know that by sleeping 2.5 seconds, the next hit to our method will force a renewal of the cache content
Voila! Obviously, you could and should expand on this, but it’s start.
[EDIT] I’ve posted an update, mainly about how to access cache hits.
Using TumblrJ to read
Jan 9th
With the current implementation of TumblrJ working properly for straight reads of different types, I figured I’d show a quick demo of the api usage (without Spring – I’ll post something about that later).
The api revolves around a single class called TumblrService. The class pretty much acts like a facade hiding the implementation details. The TumblrService needs a couple things to work properly:
- A TumblrJProperties instance
- An implementation of the ITumblrReader interface. The api includes the only one possible at this point which is an HTTP specific implementation.
Configuration
The TumblrJProperties class automatically initializes itself by looking for a file called tumblrj-config.properties in the classpath. You can override the name by using the 1 arg constructor. For now, the file needs to be found in the classpath.
The file contains basic information about paths, url’s, … The contents should look something exactly like:
base.url=http://{0}.tumblr.com
path.read=/api/read
path.authenticate=/api/authenticate
path.delete=/api/delete
Since most of these properties are pretty much standard, I’ll implement a defaults mechanism so that they aren’t mandatory.
Connection options
The other object needed to use the TumblrService and TumblrHttpReader classes is a TumblrConnectionOptions instance. At a very minimum, you’ll need to enter the name of your tumblr log (usualy, the first part in your tumblr.com url). If you want to access private posts, you’ll want to put in your email and password.
And for those who want fine grained control over the connection options, the object can also accept a org.apache.commons.httpclient.params.HttpClientParams instance which will be used on every http call.
Full Example
TumblrConnectionOptions connectionOptions = new TumblrConnectionOptions();
connectionOptions.setName("lama");
TumblrHttpReader reader = new TumblrHttpReader();
TumblrJProperties properties = new TumblrJProperties();
reader.setProperties(properties);
reader.setTumblrConnectionOptions(connectionOptions);
TumblrService service = new TumblrService();
service.setReader(reader);
TumblrReadOptions readOptions = new TumblrReadOptions();
readOptions.setStart(1);
readOptions.setNum(1);
TumbleLog log = service.read(readOptions);
Explanation
Lines 1 through 11 were pretty much explaines. Lines 12, 13 and 14 are interesting in that they let you configure the read options by letting you filter the data. The available options include:
- Wether or not to include private posts
- The start and number of posts to return (for paging and limiting results)
- The id of the post
- The type of post
Check out the TumblrReadOptions class for details.
Line 13 is the line where the read is executed and a TumbleLog object returned. That object will include a List of TumblePost objects as well as a gamut of other information concerning the returned results. As mentionned before, the test package contains a lot of usefull unit tests showing off how to use the different read options.
Self sufficient teams
Jan 5th
Once again, Heir Atwood reminds us of the things we shouldn’t forget. I’ve had a natural progression towards the type of management Jeff mentions (the good type that is). As I grow older and hopefully wiser, I learn (and keep on learning) to build teams with people who can be relied on; where I can sit on the sidelines while the engine hums.
I’m fortunate right now to be “leading” a team like that. (quoted because when you have pros, everyone knows what to do, when and how, and they do it well. They don’t need to lead all that much).
Speaking for each point he mentions:
Do you pride yourself on being “on top of” the projects or your direct reports? Do you have a solid grasp of the details of every project?
Unfortunately, I still have a way to go here. I don’t pride myself on being on top, nor do I even try anymore, but it does bother me inside when I don’t know every detail … I’ll get over myself one day :)
Do you believe that you could perform most of the tasks of your direct reports, and potentially do a better job?
Absolutely not! I use the strengths and interests of everyone on the team.
Do you pride yourself on frequent communication with your employees? Does that communication include asking them for detailed status reports and updates?
I wouldn’t say I pride myself, but I do think frequent communication is important. I generally don’t ask for reports … unless I’ve pinpointed a problem case. Status reports are more about helping the problem team member, than keeping me up to date.
Do you believe that being a manager means that you have more knowledge and skills than your employees, and thus are better equipped to make decisions?
No. It just means that I’ve chosen a career path that includes some for of leadership as well as organizational and people skills. Sometimes I’m better equiped to make decisions, but not because of any supposed superior technical knowledge, but because of the extra insight I might be given by stakeholders.
Do you believe that you care about things (quality, deadlines, etc.) more than your employees?
No. No. No. Nuff said.
Obviously, I don’t claim perfection here. I’m still young have a lot to learn. I try my best, and read, read, read and absorb from great writers. A good start for anyone wanting reading material in the area would be this.
Call me master
Jan 4th
There you go. I’m now a certified Scrum Master. Admittedly, it was ridiculously easy to get “certified” … so much so that it should probably not be called a certification (just go to the course for 2 days, and give them your email and voila!).
The course was ok, but far from great. A couple obvious problems:
- 2 days is not enough. Not by a longshot. We were rushing through everything with not much time to delve into deeper questions and issues
- Obviously, in a course like this, a lot of leaders will be present. And that’s not meant in a good way. Because of the time constraints, we were continuously rushing to begin exercises without proper information on what we needed to do or how. Therefore, a lot of people inside the same teams wanted to bulldoze and force their ways on others. Yes, I get it: “Agile == team work”. But 2 days wasn’t enough to develop any type of team work inside the teams especially since a lot of members were annoyed with one another.
I had been using agile concepts for a few years, but never did the real thing because I was missing a few key concepts. Going to the course forced me to look into those things, and talk to people about real world experience with Scrum.
Starting on Monday, I’ll be applying a few of the things I learned, but without the whole wizz-bang.
- Obviously, iterations will be part of it. I’d been doing those for a while, but this time they’ll be much better structured with a review and demo.
- Continuous integration: I just got a Hudson server up and running and all our tests will need to be runnable inside an automated environment. Again, my teams and I have been doing unit tests for a while, but I’ve never automated them. (btw: This won’t be TDD. The jury is still out for me as far as full blown TDD goes – I’ll post my opinions on that later)
- Short user stories: This is key and one of the things that made the most sense to me.
- Daily scrums: Again, I had tried this but it didn’t work all that well. Turns out it was my fault for lacking focus and goal during those meetings. With what I learned, they will be a productive and informative 15 minutes.
Following that, with each new iteration I’ll try to implement an extra practice or 2.
My biggest problem right now is that my team’s physical setup is very 80′s style with no room for white boards, small cubicles and not much opportunity for open communication. I’ve fought the fight with no results at all (showed my managers this and this, but they don’t agree. Small cubes are fine apparently … anyway, that’s a fight for another day). And don’t think I’m being critical and non constructive. I’ve offered cheep and pragmatic ways to make my team better … but it seems like the economic crunch … well, you know.