My plan B for being a programmer
June 15th, 2009
I completely agree that in programming career, the past experience becomes irrelevant and most companies won’t pay me for the irrelevant experience such as VMS, mainframe, CORBA or EJBs. Also, as I became older and started family, switching jobs just for technology became a lot harder. I believe experienced programmers who have worked with varied technologies bring useful perspective and a bit of pessimism that is often needed. I also believe most experienced programmers have better design skills and pay more attention to writing maintainable or scalable code, but it probably doesn’t matter in may places that just want to get shit done.
Another aspect that differentiates programming career from other professions is lack of predictability. I have found that in our industry, project scope, requirements and estimates are poorly defined and most companies expect programmers to be heros or martyrs who will abandoned their life and dedicate completely to the work. IT people also have to pay for the global culture of 24×7 service and have to be oncall when things break. This becomes a lot harder with the family so many companies prefer young and unmarried folks who are more willing to be heros and those young programmers like the extra attention.
So what is my plan B? It is to continually learn new skills and be a little better than the competition. Many of my past colleagues have moved to the dark site and now are directors or senior managers at other companies. And truth is that in most companies managers carry more respect and authority so no wonder most programmers aspire to become one. I on the other hand, just can’t give up programming and usually spend my spare time on a number of small projects. So I will continue to be a lowly code monkey for the rest of my life.
ActiveObject based O/R Mapping library for iPhone development
June 13th, 2009
The OCActiveObjects library is fairly small and consists of following classes:
ActiveObject
This is the base class that you extend in order to add automatic O/R support. You have to override following Class methods to specify name of the database and table:
+ (NSString *) getTableName;
Above method defines name of table where instances of the object will be stored.
+ (NSString *) getDatabaseName;
Above method defines name of the database to be used. You will then be able to call following methods to interact with the Sqlite database:
+ (void) openDatabase;Above method must be called once before any other methods, usually at the start of your application.
+ (void) closeDatabase;Above method must be called once before you shutodnw your application.
- (void) save;Above method saves a new object or updates an existing object. Each subclass of ActiveObject is automatically assigned a unique database id with a property named “objectId”. This is another example of convention where all tables will use a numeric surrogate key to identify each row. If that property is nil then it assumes this is new object and inserts a new row in the database, otherwise it updates an existing row in the database. It assumes that name of database fields are same as property names, though you can override that behavior by overriding _getPropertyNamesAndTypes Class method.
+ (ActiveObject *) findByPrimaryKey:(NSNumber *)objId;Above method queries an object in the database matching objectId property, which identifies each object in the database.
+ (NSArray *) findWithCriteria:(NSDictionary *)criteria;Above method returns an array of objects that match criteria. The criteria at this time is simple dictionary, i.e., pair of name and values that are joined by “AND” clause. There is a immediate need to extend this to support more flexible queries.
+ (NSArray *) findAll;Above method returns all objects, which may not be good for iPhone application due to limited amount of memory. This is another area that needs immediate attention.
+ (int) removeAll;Above method removes all rows in the table so be careful with this.
+ (int) removeWithCriteria:(NSDictionary *)criteria;Above method removes only methods matching criteria. Again criteria consists of name/value pairs.
+ (int) countWithCriteria:(NSDictionary *)criteria;Above method counts the number of rows in the database matching criteria.
+ (int) countAll;Above method returns count of all rows in the table.
Exension Methods in ActiveObject
There are number of extension methods to customize SQLs or behavior of the object such as- (void) _insert;Above method inserts an object into the database.
- (void) _update;Above method updates an existing object into the database.
+ (NSDictionary *) _getPropertyNamesAndTypes;You can override above method to change properties that needs to be persisted.
+ (NSString *) _getCreateSQL;Above method generates an SQL for creating table.
+ (NSMutableString *) _getInsertSQL;Above method generates an SQL for inserting a row in the table.
+ (NSMutableString *) _getUpdateSQL;Above method generates an SQL for updating a row in the table.
+ (NSMutableString *) _getSelectSQL;Above method generates an SQL for selecting fields from the database.
+ (void) _createTable;Above method creates database table.
IntrospectHelper
The OCActiveObjects library uses some Objective C magical runtime support to query for properties and this class encapsulates those methods.SqliteHelper
This class some helper methods for Sqlite3.How to use
In order to test it, let’s define a simple Person class that extends ActiveObject, e.g.
#import <Foundation/Foundation.h>
#import "ActiveObject.h"
@interface Person : ActiveObject {
NSString *name;
short age;
int rank;
long votes;
char sex;
double income;
BOOL active;
NSInteger flags;
NSNumber *rating;
NSDate *birthdate;
}
@property (nonatomic, retain) NSString *name;
@property (nonatomic, assign) short age;
@property (nonatomic, assign) int rank;
@property (nonatomic, assign) long votes;
@property (nonatomic, assign) char sex;
@property (nonatomic, assign) double income;
@property (nonatomic, assign) BOOL active;
@property (nonatomic, assign) NSInteger flags;
@property (nonatomic, retain) NSNumber *rating;
@property (nonatomic, retain) NSDate *birthdate;
- (BOOL)isEqualToPerson:(Person *)aPerson;
@end
Implemention of Person.m looks like:
#import "Person.h"
@implementation Person
@synthesize name;
@synthesize age;
@synthesize rank;
@synthesize votes;
@synthesize sex;
@synthesize income;
@synthesize active;
@synthesize flags;
@synthesize rating;
@synthesize birthdate;
- (BOOL)isEqual:(id)other {
if (other == self)
return YES;
if (!other || ![other isKindOfClass:[self class]])
return NO;
return [self isEqualToPerson:other];
}
- (BOOL)isEqualToPerson:(Person *)aPerson {
if (self == aPerson)
return YES;
if (![(id)[self name] isEqual:[aPerson name]])
return NO;
return YES;
}
- (NSUInteger)hash {
NSUInteger hash = 0;
hash += [[self name] hash];
return hash;
}
- (NSString *)description {
return [NSString stringWithFormat:@"id %@, name %@", self.objectId, self.name);
}
- (void) dealloc {
[name release];
[birthdate release];
[super dealloc];
}
+ (NSString *) getTableName {
return @”persons”;
}
+ (NSString *) getDatabaseName {
return @”personsdb”;
}
@end
Then you can first open the database, e.g.
[Person openDatabase];
Then create a new person object, e.g.
Person *person = [[[Person alloc] init] autorelease];
person.birthdate = [[NSDate alloc]init];
int random = [person.birthdate timeIntervalSince1970];
person.age = random % 30;
person.rank = random % 20;
person.votes = random % 10;
person.sex = ‘M’;
person.name = [NSString stringWithFormat:@"Joe #%d", random % 1000];
person.income = random % 3000;
person.active = YES;
person.flags = random % 30 + 0.5;
person.rating = [NSNumber numberWithInt:20.5];
return person;
You will then be able to save the person object as
[person save];
You can see how many rows are in the database by
int count = [Person countAll];
And then retrieve the object that we saved as
Person *person2 = (Person *) [Person findByPrimaryKey:person.objectId];
When you are done, you can then close the database:
[Person closeDatabase];
One of the frustrating aspect of iPhone development has been lack of good unit testing support. Though, XCode comes with OCUnit, but it is hard to install and use with iPhone. I kept getting weird errors like:
exited abnormally with code 139
failed tests for architecture 'i386'Though, there are some basic tutorials like Test Driving Your Code with OCUnit or OCUnit: Integrated Unit Testing In Xcode, but they didn’t help. I also tried adding google-toolbox-for-mac but macro errors are extremely frustrating. Besides better testing, OCActiveObjects needs a lot of help to add better support of criteria, paging, relational mapping and validation. I also had hard time figuring out how to create a static library until I found Building static libraries with the iPhone SDK though I still need help in adding framework level support. Hopefuly, other people can contribute to the open source project. You can send me your suggestions and comments as well via email “bhatti AT plexobject DOT com” or tweet me at bhatti_shahzad.
Tracing memory leaks with command line Java tools
May 26th, 2009
jmap -F -dump:file=/tmp/dump.outI then copied the file to my local machine and ran jhat using
jhat dump.outThough, jhat is fairly slow, but it finally starts the web server on port 7000 and you can then point your browser to
http://mymachine:7000The jhat can also read data from hprof that you can dump by adding following vm option:
-agentlib:hprof=heap=sitesand then read the file using jhat. In addition to above tool, you can run garbage collection in verbose mode using following vm option:
-verbose:gc -verbose:class -Xloggc:gc.out -XX:+PrintGCDetails -XX:+PrintGCTimeStampsFinally, you can use jconsole to look at memory graph by adding support of jmx to your application server, .e.g.
-Dcom.sun.management.jmxremote.port=9003 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremoteDespite all these options, I find profiler is much better for finding memory leaks, but these tools helped a bit.
Integrating Springs event notification with JMS
May 6th, 2009
1 import org.springframework.context.ApplicationEvent; 2 import org.apache.commons.lang.builder.ToStringBuilder; 3 import org.apache.commons.lang.builder.ToStringStyle; 4 import java.util.Map; 5 import java.util.HashMap; 6 import java.util.Collection; 7 8 public class MessageEvent extends ApplicationEvent { 9 private String msg; 10 private Map<String, String> map; 11 public MessageEvent(final Object source, final String … properties) { 12 super(source); 13 map = new HashMap<String, String>(); 14 for (int i=0; i<properties.length-1; i+=2) { 15 String name = properties[i]; 16 String value = properties[i+1]; 17 map.put(name, value); 18 } 19 } 20 public MessageEvent(final Object source, final Map<String, String> map) { 21 super(source); 22 this.map = map; 23 } 24 public String getProperty(final String key) { 25 return map.get(key); 26 } 27 public boolean isProperty(final String key) { 28 String value = map.get(key); 29 if (value == null) { 30 return false; 31 } 32 return new Boolean(value).booleanValue(); 33 } 34 public Map<String, String> getProperties() { 35 return map; 36 } 37 @Override 38 public String toString() { 39 return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) 40 .append("source", getSource()) 41 .append("map", this.map) 42 .toString(); 43 } 44 } 45 46I then created a class to convert above message into JMS message, e.g.
1 import javax.jms.Session; 2 import javax.jms.JMSException; 3 import javax.jms.Message; 4 import javax.jms.MapMessage; 5 6 import org.springframework.jms.support.converter.MessageConversionException; 7 import org.springframework.jms.support.converter.MessageConverter; 8 9 import java.util.Map; 10 import java.util.HashMap; 11 import java.util.Enumeration; 12 13 public class MapMessageConverter implements MessageConverter { 14 public Object fromMessage(final Message message) throws JMSException, MessageConversionException { 15 if (!(message instanceof MapMessage)) { 16 throw new MessageConversionException("Message isn't a MapMessage"); 17 } 18 MapMessage mapMessage = (MapMessage) message; 19 Map<String, String> map = new HashMap<String, String>(); 20 Enumeration<String> en = mapMessage.getMapNames(); 21 while (en.hasMoreElements()) { 22 String name = en.nextElement(); 23 String value = mapMessage.getString(name); 24 map.put(name, value); 25 } 26 return map; 27 } 28 public Message toMessage(final Object object, final Session session) throws JMSException, MessageConversionException { 29 if (!(object instanceof Map)) { 30 throw new MessageConversionException("Object isn't a Map"); 31 } 32 Map<String, String> map = (Map<String, String>) object; 33 MapMessage message = session.createMapMessage(); 34 for (Map.Entry<String, String> e : map.entrySet()) { 35 message.setString(e.getKey(), e.getValue()); 36 } 37 return message; 38 } 39 } 40Next I created a class that listened for Spring application event and converted into JMS message and published it:
1 import javax.jms.JMSException; 2 import javax.jms.Session; 3 import javax.jms.Message; 4 import java.util.Map; 5 import java.util.UUID; 6 import org.apache.log4j.Logger; 7 import org.springframework.jms.core.JmsTemplate; 8 import org.springframework.jms.core.MessageCreator; 9 import org.springframework.jms.support.converter.MessageConverter; 10 import org.springframework.context.ApplicationEvent; 11 import org.springframework.context.ApplicationListener; 12 13 public class PublisherAdapter implements ApplicationListener { 14 private static final Logger logger = Logger.getLogger(PublisherAdapter.class); 15 private JmsTemplate jmsTemplate; 16 private MessageConverter converter; 17 18 // 19 public void setMessageConverter(final MessageConverter converter) { 20 this.converter = converter; 21 } 22 23 public void setJmsTemplate(final JmsTemplate jmsTemplate) { 24 this.jmsTemplate = jmsTemplate; 25 } 26 27 public void publish(final Map<String, String> map) { 28 jmsTemplate.send(new MessageCreator() { 29 public Message createMessage(final Session session) throws JMSException { 30 return converter.toMessage(map, session); 31 } 32 }); 33 } 34 35 public void onApplicationEvent(final ApplicationEvent event) { 36 if (event.getSource() != converter && event instanceof MessageEvent) { 37 publish(((MessageEvent)event).getProperties()); 38 } 39 } 40 } 41 42Then, I created a JMS listener that listened for messages on Topic and converted those into Spring application event:
1 import org.apache.log4j.Logger; 2 import java.util.Map; 3 import javax.jms.MessageListener; 4 import javax.jms.Message; 5 import javax.jms.MapMessage; 6 import javax.jms.JMSException; 7 import org.springframework.jms.support.converter.MessageConverter; 8 import org.springframework.context.ApplicationContext; 9 import org.springframework.context.ApplicationContextAware; 10 import org.springframework.beans.BeansException; 11 12 13 public class ListenerAdapter implements MessageListener, ApplicationContextAware { 14 private static final Logger logger = Logger.getLogger(ListenerAdapter.class); 15 private MessageConverter converter; 16 private ApplicationContext applicationContext; 17 18 public void setMessageConverter(final MessageConverter converter) { 19 this.converter = converter; 20 } 21 public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException { 22 this.applicationContext = applicationContext; 23 24 } 25 26 public void onMessage(final Message message) { 27 Map<String, String> map = (Map<String, String>) converter.fromMessage(message); 28 applicationContext.publishEvent(new MessageEvent(this, map)); 29 } 30 } 31 32Next, here is Spring configuration to bootstrap these listeners:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans> 3 <bean id="mapMessageConverter" class="com.amazon.jasper.messaging.spring.MapMessageConverter"/> 4 <bean id="springTopic" class="org.apache.activemq.command.ActiveMQTopic"> 5 <constructor-arg index="0" value="springTopic"/> 6 </bean> 7 <bean id="springJmsTemplate" class="org.springframework.jms.core.JmsTemplate" scope="prototype"> 8 <property name="connectionFactory" ref="jmsConnectionFactory"/> 9 <property name="deliveryPersistent" value="true"/> 10 <property name="messageConverter" ref="mapMessageConverter"/> 11 <property name="defaultDestination" ref="springTopic"/> 12 </bean> 13 <bean id="publisherAdapter" class="com.amazon.jasper.messaging.spring.PublisherAdapter" scope="prototype"> 14 <property name="jmsTemplate" ref="springJmsTemplate"/> 15 <property name="messageConverter" ref="mapMessageConverter"/> 16 </bean> 17 <bean id="springTopicListener" class="com.amazon.jasper.messaging.spring.ListenerAdapter" scope="prototype"> 18 <property name="messageConverter" ref="mapMessageConverter"/> 19 </bean> 20 <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer" init-method="start" destroy-method="stop" scope="prototype"> 21 <property name="connectionFactory" ref="jmsConnectionFactory"/> 22 <property name="destination" ref="springTopic"/> 23 <property name="messageListener" ref="springTopicListener"/> 24 <property name="transactionManager" ref="jmsTransactionManager"/> 25 <property name="concurrentConsumers" value="10"/> 26 </bean> 27 </beans> 28 29Finally, here is how you will actually use this plumbing in your code:
1 import org.springframework.context.ApplicationContext; 2 import org.springframework.context.ApplicationContextAware; 3 import org.springframework.context.ApplicationEvent; 4 import org.springframework.context.ApplicationListener; 5 import com.amazon.jasper.workflow.WorkflowContext; 6 public class Myclass implements ApplicationListener, ApplicationContextAware { 7 private ApplicationContext ctx; 8 9 // … 10 ctx.publishEvent(new MessageEvent(this, SYNC_ID, syncId, SYNC_XPDL, "true")); 11 12 public void setApplicationContext(ApplicationContext applicationContext) { 13 this.ctx = applicationContext; 14 } 15 16 public void onApplicationEvent(ApplicationEvent event) { 17 if (event instanceof MessageEvent) { 18 MessageEvent msgEvt = (MessageEvent)event; 19 // do cache coherence 20 } 21 } 22 23All you need is to add your class to your Spring configuration file, it will automatically be registered as listener for spring events. All this is fairly simple, but I hope it helps you for similar uses in your code.
Waterfall model of Hardware Acquisition
April 22nd, 2009
When in Rome, code like how Romans code
March 25th, 2009
In early 2000s, I learned Ruby from PicAxe Ruby book that taught me Ruby from object oriented style and I missed all its functional or meta-programming features. I slowly learned more functional style of programming and meta programming. I even had to switched back to underscores as opposed to camel case. I read Ruby code of other programmers to learn how they code and what conventions they use. I did similar excercises when I learned Python, Erlang, Scala, Objective-C, etc, i.e., I tried to learn not only language itself, its core and third party libraries but how people write the code, package applications or create libraries. Though, I think it helps if there are examples of good usage or style for that language. For example, I have seen plenty of abuses of Javascript that misunderstood its prototype or functional roots and used it as either procedural or class oriented language.
At my work, we use code reviews before any code checkin and I see conventions and styles of other languages mixed in all the time. I think learning different styles of programming makes you a better programmer. For example, I learned from functional programming how immutability can make sure programs safer and I tend to use it more in other object oriented or multi-paradigm langauges that don’t enforce immutability. Though, in other cases it’s hard to force yourself to use features from one language to another when that feature isn’t available inherently. For example, I like mixins feature of Ruby or traits of Scala but I can’t really use them in langauges that support only single inheritance such as Java. So instead of jumping over hoops to use features from other language, I try to use the style suitable for that specific langauge such as using multiple interfaces. I have been learning iphone development and been reading iphone SDK book by Jonathan Zdziarski. One of peculiar thing about his coding examples is that he does not use Interface Builder and creates all UI components from the code. Though, such style is acceptable in many situations but I would prefer to use Interface Builder and follow path of least resistence.
In practice, you will often find multiple styles or approaches of doing a thing in a single language. For example, Ruby encourage multiple ways to do things that can be quite confusing. Though, I like Python’s philolsophy of only one way to do things, but there are plenty of divergent opinions in that language as well. Another somewhat related topic is how to pick a language as languages vary in their core areas of strength. For example, Java was originally marketed as language for Web platform but these days I tend to use Ruby or Python for web development and Java for system development. Also, I tend to use Erlang for network oriented or concurrent applications and use C/C++ where performance is critical. Last year, there was big hoopla over Erlang’s aweful performance for search engine that sparked WideFinder benchmarks but it missed the point that Erlang’s core strength is distributed/concurrent applications and not text searching. So in nutshell, I think it helps to pick a language based on the problem and take advantage of its strengths. Finally, stick to general style of coding and conventions of the language especially when working with large codebase or large number of programmers.
Does software quality matters?
February 24th, 2009
- Single Responsibility Principle - this principle is based on the principle of Cohesion from Tom Demarco’s Structured Analysis and Design book and mandates that a class should have one, and only one, reason to change.
- Open Closed Principle - this principle is based on Bertrand Meyer’s book on Object Oriented Software Construction that says that a class should be open to extend without modifying it.
- Liskov Substitution Principle - this principle was introduced by Barbara Liskov that says derived classes must be substitutable for their base classes.
- Dependency Inversion Principle - states that your should depend on abstractions, not on concrete implementation.
- Interface Segregation Principle - states that you should make fine grained interfaces that are client specific.
I learned these principles many years agao and also watched Bob Martin in Best Practices 2004 conference, where he talked about these principles. These principles sound good, though in reality they should be general guidelines rather than principles. But the heat of the debate was the way these principles have been evangilized by Bob Martin who insisted on using these all the time. Over the years, I have seen similar debates between Cedric Beust and Bob Martin over the use of test driven development. There is also debate on topic of TDD and architecture between Bob Martin and Jim ‘O Coplien. Overall, I find that the issues from these debates boil down to the following:
Usable software vs quality
One of the controversial point that Jeff Attwood raised was that the quality does not matter if no one is using your application. I find there is lot of truth to that. In fact, this is the route that most startup takes when developing a new idea and trying something new. For example, everyone was blaming Twitter for choosing Rails when it had scalability and reliability issues. However, Twitter would not have existed if it were written with most scalable and reliable language or framework that took two more years or if the application itself wasn’t as useful. I tend to follow the age old advice: First make it work, then make it right and then make it fast. There is a reason why rapid prototyping frameworks such as Rails, Django, Zend framework, etc. are popular because they allow you to focus more on business functionality and to reduce time to market. So, I agree the first goal of the software should be to make the software that solves real problems or add value. Nevertheless, if first implementation is horrible then it takes hercules effort to make it right and some companies like Friendster never recover.External design vs internal design
One of the earliest advice I got on software development was to write manual before writing the code. It focuses you to solve business problem of the customer rather than writing with top down architecture, which is in a way similar to behavioral driven design in spirit. I find that most useful software developed bottom up and driven by the users. Kent Beck often says that you can’t hide a bad architecture with a good GUI. Nevertheless, for an average user, the usability matters a lot. I remember back in early 90s, IBM OS/2 was superior operating system than Windows but largely loss the market due to the usability (and marketing) issues. The same could be told why people think Macs are better than PC. Rails is also a good example that became popular because it could whip up a webapp in ten minutes despite the fact that its code has been plagued with maintenance issues from monolithic architecture and tricks like chain of alias methods. Other examples include Wordpress and Drupal both written in PHP and are the leader in the blogging and content management area due to their usability rather than quality of the code. Again as your software crosses some threshold of number of users it may have to be redesigned, e.g. Rails recently announced that it will merge with another framework Merb in 3.0 because Merb has been designed with micro-kernel and pluggability based architecture. This also reminds me of merge between Struts and WebWork that turned out to be failure. Joel Spolsky cautions about software rewrites in his blogs and book and I have also blogged on Software rewrites earlier. In the end you want to extend your application incrementally, which is not an easy thing to do. Ultimately, I think software development is all about people rather than technology, principles or best practice. If you have good people then can take your application to the next step regardless if it was written in PHP, Java or Erlang.Evolutionary architecture vs up front architecture
This has been brought up in debate between Jim Coplien and Bob Martin, where Jim took the position of more upfront design and architecture and Bob took position of evolutionary architecture. I have a lot of respect for Jim Coplien, I still have a copy of Advanced C++ I bought back in ‘92 and it introduced me to the concepts of abstraction, body/handle, envelop/letter principles which are sort of DIP. In the interview with Bob Martin, Jim Coplien raised a lot of good points that YAGNI and test-driven based bottom design can create architecture meltdown. Though, I believe good software is developed bottom up, but I do believe some architecture and domain analysis beneficial. I am not necessarily suggesting BDUF (big design up front) or BRUF (big requirements up front), but iteration 0 style architecture and domain analysis when solving a complex problem. For example, the domain driven design by Eric Evans or Responsibility driven design by Rebecca Wirfs-Brock require working closely with the domain experts to analyze the business problems and capturing essential knowledge that may not be obvious. Any investment in proper domain analysis simplifies rest of development and make your application more extensible. There are a number of agile methodologies such as feature driven development and DSDM that encourage some upfront architecture and domain analysis, which I find beneficial.Extensibility and maintenance
Once your product is hit and loved by users, your next task becomes extending it and adding more features. At this stage, all -ilities such as scalability, performance, security, extensibility becomes more important. This is also more common in corporate environment and most of the developers live their entire lives maintaining the code written by others. Nevertheless, each team should decide on what practices and principles are appropriate and follow them. Agile methodologies encourage collective ownership and pair programming that can spread knowledge and skills, though there are some alternatives such as code reviews or mentoring. I also think, having a technical lead who ensures overall quality and keeps the bar up for rest of developers can help with extensibility and maintenance.Test driven Development
Bob Martin has been adament proponent of test driven development with his three laws of TDD. I blogged about original debate between Cedric Beust and Bob Martin back in June, 2006 and showed how Bob Martin’s position was unpragmatic. This reaction has also been echoed by Joel, Jeff, Cedric and Jim, who agree 100% coverage is unrealistic. Lately, more and more people are joining this group. I watched recently an interview of Luke Francl who expressed similar sentiments. In my earlier blog, I wrote various types of testing required for writing a reliable and enterprise level software. One of the selling point of unit testing has been ease of refactoring with confidence but I have also found too many unit tests stifle refactoring because they require changing both the code and unit tests. I have found that testing only public interfaces or a bit high level testing can produce reliable software and also is less prone to breakage when doing refactoring. Though, no one refuses value of testing, but it needs to be practical.Dependency management
A number of SOLID principles and extended principles such as reuse principle, dependency principles mandates removing or minimizing dependnecies between packages. Those principles were made in C++ environment that historically had problems with managing dependencies. Again, the problem comes from religious attitude with these principles. For example, I have worked in companies where different teams shared their code with java jar files and it created dependency hell. I used jDepend to reduce such dependency but it’s not needed in all situation. I am currently building a common platform that will be used by dozens of teams and I intentionally removed or minimized static dependencies and instead used services.Conclusion
Unfortunately, in software industry buzzwords are often used to foster consulting or selling books. There are lots of books on principles, best practices, etc. The entire agile movement has turned into prescriptive methodologies as opposed to being pragmatic and flexible based on the environment. People like uncle bob use these principles in draconian fashion such as always stressing on 100% test coverage or always keeping interfaces separate from implementation (DIP). Such advice may bring more money from consulting work or publication, but is disingenuous for practical use. In the end, software development is about people and not about technology or principles and you need good judgement to pick what practices and solutions suit the problem.Software Estimation
February 23rd, 2009
As a project is always constrained by iron triangle of schedule/cost/functionality or sometime referred to as cost/quality/schedule or cost/resourcs/schedule. It is crucial to find what’s driving the project as also suggested by Johanna Rothman in her book Manage It. I have seen a number of cases where dates were arbitrary picked, sometime referred to as “happy date”. Though, at other times, dates may depend on marketing campaign, seasons, tax time, olympics, etc. So, you can negotiate between functionality and schedule based on what’s driving the project. Following are some of techniques that I have found useful with estimation:
- Get the vision and requirements straight - It’s important about the charter, constraints and requirements for the project as any misdirection here would lead to disaster. Luke Hohmann in his book Beyond Software Architecture recommends starting with good vision and mission statement. Johanna Rothman also recommends creating a project charter before starting the project.
- Probablistic based estimation - Despite the fact, you are often pressured to produce more precise estimates even though they would be inaccurate, it is better to give estimate with some probablity. Both Johanna Rothman and Steve McConnell cite cone of uncertainty, where your estimate becomes more accurate as project progresses.
- Based on best/worst/most-likely case - use following formula from Steve McConnell’s book can be used when estimates are more accurate:
expected case = (best-case + (4 * most-likely) + worse-case) / 6
If estimates are not accurate, then Steve McConnell recommendsexpected case = (best-case + (3 * most-likely) + (2*worse-case)) / 6
Bob Martin also similar formula from his article PERT, CPM, and Agile Project Management:Mean = (best-case+worst-case+(4*most-likely))/6 Variance = ((worst-case-best-case)/6)^2
- Iterative development - No matter if you are working on small or large project, the only way to bring some reality and feedback on initial estimate is to develop iteratively starting with highest valued features.
- T-shirt based estimation - I find t-shirt based estimation useful when estimating with minimal information available. For example, you may have to estimate projects that you can deliver in Q1, Q2, etc and you can order them in small, medium, large and compare them against their business value.
- Spiking can also help in areas that are new to the team and spending a little time creating walking skeleton or tracer bullet can give you some idea on the size of the effort for the project.
- Delphi estimation - where PM and team prepares task list, assumptions and estimate in private and reviews them together.
- Divide and conquer/Decomposition/WBS - as with any large effort, breaking a project into smaller subsystems, components, services and tasks will help estimate better. In general any errors in estimation of smaller tasks will cancel each other.
- Estimate fine grained tasks - I can rarely estimate with some accuracy for tasks that are longer than a few days so it’s important to estimate only fine grained tasks. XP has a concept of inch pebble and story points that can help in this case. The idea is that each task is either done or not done.
- Planning poker a technique from Agile Estimating and Planning by Mike Cohn, where each member of the team pick an estimate for a story based on fibonacci numbers, but don’t show until everyone selects some number. The members then pick some average or may ask member with highest or lowest estimates to explain.
- Historical data - though I rarely see PM track estimates but tracking them can help future projects and new projects can use LOC, man-months, function-points, # of services, files, interfaces, bugs from prior projects for estimation.
- Schedule chicken - Kent Beck often talks about schedule chicken where you have some some meeting about who is ontrack and you hope there is someone who is behind so that you don’t have to admit you are behind as well. Integrity is big part of the XP and agile methodologies so it encourages transparency and honesty instead of schedule chicken.
- Better to overestimate than underestimate - programmers often underestimate and though there is risk of student syndrome or Parkinson’s law but it’s better to overestimate.
- Don’t question developer’s estimate - even though developers tend to underestimate, some managers still question them, which is not a good idea.
- In XP or Scrum, you use story points, which can be ideal hours or based on some multiplier. These numbers are generally follow fibonacci sequence such as 1, 2, 3, 5, 8, 13, 21.
- Function points use number of external input/output/queries, internal logical files/external interface files and it can be used as unit of measurements similar to story points.
- Estimation quality factory (EQF) as proposed by Tom Demarco in his paper A Defined Process For Project Postmortem Review can be used to check how accurate estimates are.
- Include vacation, sick, holidays as well as non-development activities such as testing, deployment, configuration, migration, etc in your project plan.
- Scheduling is all about ordering with highest value features. I find rolling-wave scheduling based on milestones useful when planning iterations.
IP addresses of Spammers from my Honeypot
February 5th, 2009
Review of Clean Code
January 25th, 2009
The first chapter gathers thoughts on good code from a number innovators and authors such as Kent Beck, Bjarne Stroustrup, Grady Booch, Dave Thomas, etc. They mention various attributes of good code such as easy to read, efficient, DRY, focused, literate, minimal, error handling and warn of bad code that leads to messy code or broken windows mentality.
The chapter 2 talks about golden advice of using intention-revealing names to improve the readability and following principle of least surprise. This chapter denounces use of hungarian notation or member prefix such as _ or m_.
The chapter 3 describes functions and methods and advices to use small, cohesive functions. It suggests using one level of abstraction to facilitate reading code from top to bottom. It also recommends using polymorphic methods as opposed to switch statement, if-else or functions that take flag/boolean arguments. The chapter discourages functions with side effects or the one that create temporarl coupling. This chapter also mentions an aged old advice of command query separation, though it skips its roots from Bertrand Meyer’s design by contract. Finally, this chapter urges use of exceptions as opposed to error codes.
The chapter 4 describes writing good comments that focus on intent and dissuades against redundant and misleading comments.
The chapter 5 illustrates use of good formatting such as identation, horizontal, vertical spacing, etc.
The chapter 6 describes use of objects and data structures. It encompasses advice on polymorphism, law of demeter, encapsulation, DTO/value objects, etc.
The chapter 7 discusses error handling. Again it encourages use of exceptions rather than return codes or error codes. It prohibits use of checked exceptions as it violates open/closed principle. It also discourages returning or passing null and recommends exceptions or empty collection instead of returning null.
The chapter 8 describes boundaries between components.
The chapter 9 describes advice on unit testing such as TDD, keeping tests clean, one assert per test, single concept per test, etc.
The chapter 10 is similar to chapter 6 and contains recommendations on writing classes such as encapsulation, classes should be small, single responsibility principle, cohesion, dependency inversion principle, etc.
The chapter 11 encompasses advice on building systems and managing complexity. It suggests dependency injection and use of factories. It also advocates use of AOP for managing cross cutting concerns.
The chapter 12 talks about emergent design, the concept I first heard from Andy Hunt. This chapter describes advice from Kent Beck: run all tests, refactoring, no duplication, express intents of the programmer and minize the number of classes and methods. This chapter advocates use of template methods to remove duplication and command/visitor patterns to express design to other developers.
The chapter 13 discusses concurrency. It suggests use of single-responsbility principle to keep concurrent code separate from other code, limiting scope of data, keeping threads independent, and use of immutable oobjects or copies of data. It recommends keeping critical section small. The chapter also holds advice on testing threaded code and suggests making threaded code plugable.
The chapter 14 encompasses an excercise on how to incrementally improve code.
The chapter 15 describes JUnit framework and walks reader through improving tests.
The chapter 16 walks reader through another refactor excercise.
The chapter 17 encompasses a number of smells, heuristics and antipatterns. It deters use of poolrly written comments, builds/tests that require more than one step. The chapter prohibits passing too many arguments to functions or use of output/flag arguments to functions. It encourages testing boundrary conditions and respecting overridden safeties. It also proscribes writing code at wrong level of abstraction, i.e., exposing low-level logic through interface. The chapter also forbids exposing derivatives to base classes, having too much information in interface. Other smells include artifical coupling (sharing constants), feature envy (coupling formating logic), flag arguments. This chapter also holds advice of Kent Beck about using explanatory (local/temporary) variables. The chapter recommends use of constants, structure over convention, encapsulate conditionals, avoiding temporal couplings, keeping functions at same level of abstraction and keeping configurable data at high levels. The chapter also contains Java specific is advice such as avoiding wildcards in imports, avoiding use of interface to inherit constants, etc. Finally, the chapter cautions against insufficient tests, use of coverage tool, testing boundary conditions, etc.
In conclusion, this book contains advice from wide range of authors on writing good maintainable code. From being programmer myself for over 20 years, I can attest that writing good code is hard and requires a lot of attention for continually improving and refactoring code. I see too often projects have incredible pressure to deliver and programmers end up using short cuts or not able to refactor the code. Kent often talks about courage in XP and programmers needs to have courage to fight for writing maintainable code and take time to refactor existing code. Finally, I would also caution against using these practices mindlessly as another favorite rule of mine is that every practice or pattern depends on the situation. Unfortunately, there are lot of people in software industry including uncle bob who use these rules in draconian fashion such as always stressing on 100% test coverage or always keeping interfaces separate from implementation (DIP). Such advice may bring more money from consulting work or publication, but is disingenuous for practical use.