Wednesday, February 20, 2013

Agile: Diagram-Driven Development

Agile methodologies have been helping software developers produce higher quality software in less time for almost ten years now.

However, there are always ways to improve. After observing teams function in some form of Agile for the last decade, I am left with the impression that there was a baby in the bathwater who may have been unwittingly tossed out.

Agreed - software documentation is not something that customers typically ask for, hence it is of lower value in Agile methodologies. It is not entirely without regard - some Agile processes like FDD and XP, for example, include short Design phases in their process, which one can interpret as generating some form of Documentation.

In practice though, teams trying to become Agile tend to cling to the concepts in the Agile Manifesto, which extoll production over documentation.

The Oversight

I believe there is room for better balance here.  The original intention of "documentation for developers" - i.e. Diagrams - was to save time and money. It was a good idea, but it was hard to get right.  Hence the entire practice was largely thrown out with Agile.

The Proof

People tend to do what is necessary to get their job done.  Normally that includes installing and configuring an IDE, reading an Ant or Maven build script, and digesting source code.

In my experience, unless a project is very simple, as I am trying to digest source code, I tend to jot down class diagrams, activity diagrams, and deployment diagrams.  I do this because with larger systems I cannot remember all of the business rules, the entity relationships, and where all the servers are.

A developer must understand the codebase to be productive. The more clarity, the higher quality the solution tends to be.

This requires a significant investment by each team member.  Requiring each developer to take on this cost multiplies overall cost across the project - developers either bear the cost directly by doing the research, or indirectly via longer execution time for each task.  A development task cannot be performed without some knowledge of the system.

The Ideal Solution

Of course we could say that ideally, there would be diagrams documenting each aspect of the system and they would be magically updated as things change. It is easy to see that this is not Reality.

Challenges include:
  • comprehensive production of diagrams - do we have diags for everything?
  • maintenance of diagrams - is anyone updating these as things change?
  • finding a tool that does what we need and is easy to use
Mitigation

An effective way to relieve this tension is by clarifying and simplifying the documentation needs.  I suggest reducing the set of documents to:
  • Activity diagrams - Essential - for complex business rules
  • Entity diagrams - Helpful - both class and database
  • Deployment diagrams - Helpful - for servers in use on the project

Entity diagrams are the easiest to manage, as they should always be generated.   This requires a tool that will reverse-engineer classes.  Open source solutions tend to fall short of this, however.  Current options include:

  • the diver project 
  • Object Aid UML Explorer, an Eclipse plugin available at http://www.objectaid.com/update
  • UMLet - an Eclipse plugin available at Eclipse Marketplace  (although it seems un-downloadable at the moment?)

Database tools tend to have diagramming capability at some level, but investigation is required to find the right solution for the primary database in use during development.

Capturing business rules, however, is a different story.  Its challenges are unique:
  • worthwhile sets of rules tend to be complex, meaning they are difficult to actually diagram
  • diagramming tools often require manual layout, which imposes maintenance costs for complex diagrams
The team needs to decide which business rules require diagramming. The guiding principal should be:
  • waste no time diagramming simple rules
  • waste no time debating complex rules - let the diagram speak 

These diagrams must be required to be maintained by any contributor working on the code.  I would suggest that Test-Driven Development be augmented by Diagram-Driven Development in these cases.

Definition:  Diagram-Driven Development

Test-Driven software development which is directed by business rules captured in diagrams.  Can be applied to any significant body of business rules which will be implemented in code.
  1. developers and stakeholders agree on the set of rules, or modifications to existing rules
  2. ideally: rules are diagrammed in real-time during user story discussions
  3. rules are coded into test cases
  4. rules are coded into source code
If we turn the production of Diagrams upside down, as leading the process rather than following it, we have a process which ensures that important diagrams are maintained, just as our test cases are.

And in return, we have useful documentation which can be used to reassure The Customer that we know what we built.





Monday, February 18, 2013

Performance: Grails vs. Java

Background
I wanted to compare the Grails platform vs. a straight Java platform with a similar stack, to figure out which would provide the best dev and deploy environment for new web projects. Grails has development advantages with its Groovy language and plugin architecture, but Groovy's rampant runtime indirection has an implied cost.

Before I ran into Grails I was a long-time user (and occasional submitter) of the AppFuse framework,  an awesome rapid development platform for Java web-apps.  I was rather pleased to find that Grails has quite a bit in common with the AppFuse stack.  For example:
  • Spring IOC-based
  • SpringMVC-based (one option among AppFuse's choices)
  • Hibernate persistence
  • AspectJ AOP
  • SiteMesh templating
  • SpringSecurity
Conjecture
A comparison of the server portion of the two mentioned platforms would be a decent comparison of performance between a Grails webapp vs. a plain Java webapp.

Objective
My intention is to isolate the server-side processing as much as possible, by reducing client generation to a bare minimum.  Ideally this test would eliminate client page generation altogether and simply invoke server operations via a REST/JSON interface.

I decided not to do that though since it would require significantly more effort, and also introduces I believe a variance in the processing; while AppFuse comes bundled with CXF for this purpose, Grails uses its native DSL on top of SpringMVC plus your choice of JSON processor to produce the same.  While comparing these 2 would be interesting enough, it wasn't my primary objective.

Approach
To reduce variance in the platforms I am simply using SpringMVC to process two kinds of requests:
  • 'Create/Add' request
  • a nearly empty 'Retrieve/List' request
Initially I had included the list generation, but as the list size grows the DisplayTag functionality in AppFuse begins to take forever to render.  Result of that test posted at the end as an FYI.

Environment
All of the tests were built and run with the following:
  • Oracle Java 1.6.0_38 
    • started with Java1.7.0_10, but was forced back - read on
  • Linux Mint 14
  • Grails 2.1.1
  • AppFuse 2.x
  • Maven 2.2.1 
  • MySQL 5.5.29 for debian-linux-gnu
  • Apache Tomcat 7.0.32
  • Apache JMeter 2.8
  • JProfiler7
  • Hardware, as reported by Gnome system monitor:
    • Intel® Core™ i7-3610QM CPU @ 2.30GHz × 8
    • 15.6 GiB

General Test Layout
To produce equivalent tests in both platforms I created 2 POJOs
  • Person
  • Account
with a simple one-to-one relationship from Person to Account, and 2 functions:
  • add new Person and Account
  • list all Persons
The test would run 100 users all creating Person/Account objects and retrieving the entire list of Persons.  (Note: Account would be lazily-loaded in each case and hence in the test as posted would not be a factor).


Expectation
I fully expected the AppFuse platform to easily trounce the Grails platform, since Grails is encumbered by DSLs and Groovy, and does a lot of dynamic class decoration for things like installing Hibernate functionality onto domain classes.


Grails Test Creation
To produce the desired test in Grails I used the usual combination of Grails generators:
  • grails create-app
  • grails create-controller
and 'manually' created 2 domain classes:

class Person {

    String name
    Account account


    static constraints = {
        name(unique:true)
        account(nullable:true)
    }

    String toString() {
        return name
    }

    boolean equals(Object input) {
        return this.name == input.name
    }
}

class Account {

    String accountId
    Float balance
    transient Float amount

    static belongsTo = Person
    static transients = ['amount']

    static constraints = {
        accountId(blank:false)
        amount(blank:true,nullable:true)
    }
}

Then I modified the generated Person list view under grails-app/views/person/list.gsp to only display the total count of Person records.

A zip of the project can be downloaded here.

Java Test Creation
I used AppFuse's project creation maven plugin with the SpringMVC archetype to generate the project.

mvn archetype:generate -B -DarchetypeGroupId=org.appfuse.archetypes -DarchetypeArtifactId=appfuse-basic-spring-archetype -DarchetypeVersion=2.2.1 -DgroupId=com.uss -DartifactId=txtest3 -DarchetypeRepository=http://oss.sonatype.org/content/repositories/appfuse

then included the full source from the AppFuse framework

mvn appfuse:full-source

and created 2 nearly identical POJOs, 'manually'

@Entity
@Table(name="account")
public class Account extends BaseObject {

    private Long id;
    private String accountId;
    private Float balance;
    private transient Float amount;


    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() {
        return this.id;
    }
    public void setId(Long id) {
        this.id = id;
    }
  
  
    @Column(name="accountId", length=50)
    public String getAccountId() {
        return accountId;
    }

    public void setAccountId(String accountId) {
        this.accountId = accountId;
    }


    @Column(name="balance")
    public Float getBalance() {
        return balance;
    }

    public void setBalance(Float balance) {
        this.balance = balance;
    }


    @Transient
    public Float getAmount() {
        return amount;
    }
  
    @Override
    public String toString() {
        return "AccountId:: " + getAccountId();
    }
    @Override
    public boolean equals(Object o) {
        if (! (o instanceof Account)) {
            return false;
        }
        return this.getAccountId().equals( ((Account)o).getAccountId() );
    }
    @Override
    public int hashCode() {
        return accountId.toCharArray().hashCode() + (id == null ? 0 : id.intValue());
    }
  
    public static void main(String[] args) {
        HashSet s = new HashSet();
        s.add("test");
        s.add("test #2");
      
        System.out.println("Hash contains test: " + s.contains("test"));
        System.out.println("Hash contains test #2: " + s.contains("test #2"));

    }
}

@Entity
@Table(name = "person")
public class Person extends BaseObject {
   
    private Long id;
    private String name;
    private Account account;

    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() {
        return this.id;
    }
    public void setId(Long id) {
        this.id = id;
    }

   
    @Column(name="name", length=50)
    public String getName() {
        return name;
    }
    public void setName(String in) {
        name = in;
    }
   
    @ManyToOne(optional=true,cascade=CascadeType.ALL,fetch=FetchType.LAZY)
    @JoinColumn(name="acct_id", nullable=true, updatable=false)
    public Account getAccount() {
        return account;
    }
    public void setAccount(Account in) {
        account = in;
    }

   

    public String toString() {
        return "id: " + getId() + "\tname: " + getName();
    }

    public boolean equals(Object input) {
        if (! (input instanceof Person)) {
            return false;
        }
        return this.getName().equals( ((Person)input).getName() );
    }
    @Override
    public int hashCode() {
        return name.toCharArray().hashCode() + (id == null ? 0 : id.intValue());
    }
}

and generated the scaffolding

mvn appfuse:gen -Dentity=Account
mvn appfuse:gen -Dentity=Person

Note: This is where I learned that AppFuse requires Java6 due to an issue with the declaration of the Hibernate descriptors.  (TODO:  Citation)

and modified the generated Persons list view src/main/webapp/WEB-INF/pages/persons.jsp  to only report the total count of Person records.

A zip of the project can be downloaded here.



Deployment
Both projects were independently deployed to Tomcat as packaged WARs and pummeled with 10k requests from a JMeter script.

Results
This is a snapshot of the JMeter results* side-by-side. The results I am focusing on are:
  • Person List:   19ms avg (Grails) vs. 112ms avg (Java)
  • Add Person: 37ms avg (Grails)  vs. 134ms avg (Java)


 also available here.

*Note: The AppFuse result shows 20k+ total samples due to additional requests required to negotiate security; hence the "Person List" and "Add Person" results should be compared directly.

Complete results are here:

Grails app:
JMeter Performance Results
Zipped JProfiler output

Java app:
JMeter Performance Results
Zipped JProfiler output

Note: The Call Tree results for the Java app show an apparent anomaly in that the sub-tree does not seem to sum up to the parent folder:

53.9% - 80,177 ms - 500 inv. org.hibernate.Criteria.list
5% - 5,217 ms - 5,642,324 inv. com.uss.model.Account_$$_javassist_3.getHibernateLazyInitializer
2% - 3,271 ms - 5,642,324 inv. com.uss.model.Account.<init>
7% - 1,081 ms - 5,642,324 inv. org.appfuse.model.BaseObject.<init>
6% - 954 ms - 5,642,324 inv.com.uss.model.Account_$$_javassist_3.setHandler
6% - 938 ms - 5,642,324 inv. com.uss.model.Person.setId
6% - 925 ms - 5,642,324 inv. com.uss.model.Person.setAccount
6% - 874 ms - 5,642,324 inv. com.uss.model.Person.setName

I contacted the producer of JProfiler and was assured this is due to filtering, so not all of the child nodes are actually shown. I'm not very happy with how they decided to indicate that since the end result is that it is misleading, and how many managers will suffer through such an explanation - but worse IMHO is that their stance is that the numbers in the child nodes should not be expected to add up to their parent values. That has not been my experience with profilers over time. Anyway here was the explanation I received:

Thanks for your email. The explanation is this:

"org.hibernate." is not a profiled package in the default session settings (se the
"Filter settings" tab of the session settings).

Only the first call into this package is measured. Then there are a lot of
internal calls in that package and into other unprofiled packages that take some
time. That time is attributed to "org.hibernate.Criteria.list". Deeper in the call
tree some profiled classes are reached, for example in the "com.uss." packages.
Those are shown separately. In general, the summed execution times of the children
in the call do not have to add up to the execution time of the parent.


Conclusion
I scratched my head for a while when I first saw the JMeter results -  then I decided to use a profiler.  That's when I discovered and removed the horrible DisplayTag taglib. AppFuse was much more competitive afterwards.

But I am still trying to figure out where the significant differences lie.  Some known differences are:
  •  AF includes the SpringSecurity filter, which I did not remove prior to testing

But I am left with concluding that Grails offers development benefits plus runtime benefits, and so will likely be my choice of platform. 


Ways to Improve This Test
Some things I'd like to do when I get time:
  • disable the AF SpringSecurity filter
  • look up a single record and access the Account sub-object
  • add a one-to-many relationship

Friday, February 15, 2013

Photography Cheat Sheet

Trying to get my head around my digital camera.
 

Aperture
  • Def: the lens diaphragm opening; i.e. how large the shutter curtain opens
  • Calibrated in f-numbers, a.k.a. f-stops
    • f22 (f/22),16 (f/16), f/11, f/8.0, f/5.6, f/4.0, f/2.8, f/2.0, f/1.8 etc.
    • indicate inverse size: f/22 is smallest, f/1.8 is biggest
  • Effect: controls amount of light entering
    • each smaller step (moving towards f/1.8) lets twice the light in
  • 2nd Effect: affects Depth of Field (DOF)
    • see section "Depth of Field"
  • http://www.mir.com.my/rb/photography/fototech/apershutter/aperture.htm
  • Note: actual f-number diameter is unique to the lens -
    e.g. wide-angle lens will open differently than narrower, to get same f-val
Shutter Speed
  • How quickly the shutter opens and closes
  • Effect: slower speed lets in more light
  • Indicated as fraction of a second:
    1/8000, 1/4000, 1/1000, 1/500, 1/250, 1/125, 1/60, 1/30, 1/15, 1/8, 1/4, 1/2, 1 or -1, -2 etc.
  • Effect: Regulates amount of light allowed in
    • each slower speed allows double the light of the previous
  • 2nd Effect: Can freeze or blur a photo
Exposure
  • Exposure = Aperture + Shutter Speed
  • Hence, to maintain same Exposure:
    increase in Aperture <=> decrease in Shutter Speed
    translates as: reduce f-stop <==> increase ASA speed
    also can say: f-stop towards f/1.8 <==> ASA speed towards 1/8000
Depth of Field (DOF)
  • Def: the focus of close and far away objects
  • Smaller aperture extends DOF
    • Deep DOF = everything is in focus = moving towards f/22
    • Shallow DOF = only close objects in focus = moving towards f/1.8
  • Focal length of lens affects DOF
    • Wideangle have deeper DOF
      • hence good for scenery shots
    • Telefoto have shallower DOF
      • e.g. use larger aperture with telefoto to blur a background
    • Wideangle = 35mm; 50mm is standard; 80mm+ is Telefoto