Analytics

Sunday, April 4, 2010

My Comprehensive Reading List

Recently I decided to track all the books I have read since I graduated college and compile them into one comprehensive list.  What I discovered was that I have read many technical books and that my interests lie in a few discrete other areas.  All the books I have read contribute to my career path and my personal life in some way, and I try to apply anything I learned from reading.  I am interested to see what has influenced you as a developer as well as a person.

I welcome any recommendations, suggestions, thoughts, or criticisms related to these readings.  I am particularly interested in the category I labeled as "Social Science", as I think the themes in those books correlate with the software workplace in many ways, but with a different perspective.  On the same note, I am always looking for the inspiring novel or story to sharpen up the emotional side of my brain.

Technical
  • The Pragmatic Programmer: From Journeyman to Master, by Andrew Hunt and David Thomas
  • Ship It!: A Practical Guide to Successful Software Projects, by Jared Richardson, Will Gwaltney, Jr
  • Domain Driven Design: Tackling Complexity in the Heart of Software, by Eric Evans 
  • Clean Code: A Handbook of Agile Software Craftsmanship, by Robert C. Martin
  • Design Patterns: Elements of Reusable Object-Oriented Software (Hardcover), by Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides
  • Head First Design Patterns, by Eric T Freeman, Elisabeth Robson, Bert Bates, Kathy Sierra
  • Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and the Unified Process, by Craig Larman
  • Agile and Iterative Development: A Manager's Guide, by Craig Larman
  • Refactoring: Improving the Design of Existing Code, by Martin Fowler, Kent Beck, John Brant, and William Opdyke
  • Seam Framework: Experience the Evolution of Java EE, by Michael Juntao Yuan, Jacob Orshalick, Thomas Heute
  • Maven: A Developer's Notebook, by Vincent Massol and Timothy M. O'Brien
  • JBoss RichFaces 3.3, by Demetrio Filocamo
  • Getting Started with Grails, by Jason Rudolph
  • Grails in Action, by Glen Smith and Peter Ledbrook
  •  Driving Technical Change, by Terrance Ryan
  • The Agile Samurai, by Jonathan Rasmusson
  • Getting Real, by 37Signals
  • Programming in Groovy, by Venkat Subramaniam
  • Building and Testing with Gradle, by Tim Berglund and Matthew McCullough  
  • Practices of an Agile Developer, by Venkat Subramaniam and Andy Hunt
  • Manage It, by Johanna Rothman 
  • Joel on Software, by Joel Spolsky
  • Theory of Relativity, an intuitive explanation, by Jeffrey Bennet   
Social Sciences
  • Naked Economics: Undressing the Dismal Science, by Charles Wheelan
  • The Tipping Point: How Little Things Can Make a Big Difference, by Malcolm Gladwell
  • Outliers: The Story of Success, by Malcolm Gladwell
  • Blink, by Malcolm Gladwell
  • Kluge: The Haphazard Evolution of the Human Mind, by Gary Marcus 
  • First Things First, by Stephen R. Covey, A. Roger Merrill, Rebecca R. Merrill 
  • The 7 Habits of Highly Effective People, by Stephen R. Covey
  • Freakonomics: A Rogue Economist Explores the Hidden Side of Everything, by Steven D. Levitt, Stephen J. Dubner
  • The World is Flat: a Brief History of the Twenty-First Century, by Thomas L. Friedman
  • Ethics for Everyone, by Arthur Dobrin
  • The Happiness Hypothesis: Finding Modern Truth in Ancient Wisdom, by Jonathan Haidt 
  • Shalom in the Home: Smart Advice for a Peaceful Life, by Rabbi Shmuley Boteach  
  • The Principle of the Path: Smart Advice for a Peaceful Life, by Andy Stanley
  •  Under the Banner of Heaven, by John Krakauer
  • The Big Short, by Michael Lewis
  • God the failed Hypothesis, by Victor Stenger
  • God is not Great, by Christopher Hitchens 
  • Discover your Inner Economist, by Tyler Cowen 
  • Liar's Poker, by Michael Lewis 
  • The End of Faith, by Sam Harris 
  • Moneyball, by Michael Lewis  
  • Freedom At Midnight, by Larry Collins and Dominique Lapierre  
  •  Power of Habit, by Charles Duhigg
  • It Starts With Food, Dallas and Melissa Hartwig 
  • Free Lunch, David Johnston 
  • Predictable Irrational, Dan Arielly 
  • Bonobo and the Atheist, Frans De Waal 
     Biographies
    • Three Cups of Tea: One Man's Mission to Promote Peace . . . One School at a Time, by Greg Mortenson and David Oliver Relin
    • The Boy Who Harnessed the Wind: Creating Currents of Electricity and Hope, by William Kamkwamba and Bryan Mealer
    • Gandhi An Autobiography: The Story of My Experiments With Truth, by Mohandas Karamchand (Mahatma) Gandhi
    • The Autobiography of Martin Luther King, Jr., by Martin Luther King Jr. and Clayborne Carson
    • Baseball's Great Experiment: Jackie Robinson and His Legacy, by Jules Tygiel
    • Faith of My Fathers: A Family Memoir, by John McCain and Mark Salter
    • Hang Time: Days And Dreams With Michael Jordan, by Bob Greene
    • Playing for Keeps: Michael Jordan and the World He Made, by David Halberstam 
    • It's Not About the Bike: My Journey Back to Life, by Lance Armstrong 
    • Crazy Horse and Custer, by Stephen Ambrose
    • The Color of Water, by James McBride
    • Lessons From a Third Grade Dropout, by Rick Rigsby
    • The 5 Love Languages, by Gary Chapman
    • Unbroken, by Lauren Hildenbrand
    Novels
    • A Thousand Splendid Suns, by Khaled Hosseini
    • And the Mountains Echoed, by Khaled Hosseini
    • For One More Day, by Mitch Albom 
    • The Five People You Meet in Heaven, by Mitch Albom 
    • Siddhartha, by Hermann Hesse
    • The Da Vinci Code, by Dan Brown
    • Tuesdays with Morrie: An Old Man, a Young Man, and Life's Greatest Lesson, by Mitch Albom
    • The Twentieth Wife, by Indu Sundaresan 
    • On the Road, by Jack Kerouac
    • Fever Pitch, by Nick Hornby
    • The Alchemist, by Paolo Coehlo 
    • The Girl Who Played With Fire, by Stieg Larsson 
    • The Girl Who Kicked the Hornet's Nest, by Stieg Larsson
    • The Help, by Kathryn Stockett
    • The Hunger Games, by Suzanne Collins
    • Catching Fire, by Suzanne Collins  
    • Mockingjay, by Suzanne Collins
    • The Lucky One, by Nicholas Sparks
    •  True North, by Jim Harrison
    Parenting
    • How to Really Love Your Child, by D. Ross Campbell 
    • Raising Happiness: 10 Simple Steps for More Joyful Kids and Happier Parents, by Christine Carter
    • 1-2-3 Magic: Effective Discipline for Children 2-12, by Thomas W. Phelan
    • Toddler 411: Clear Answers & Smart Advice for Your Toddler, by Denise Fields and Ari Brown
    • Fatherhood, by Bill Cosby and Alvin F. Poussaint
    • Bavy 411, by Dr. Ari Brown

    Sunday, March 28, 2010

    One to One Shared Primary Key is Eagerly Fetched in Hibernate

    One to One Shared Primary Key is Eagerly Fetched
     
    Every so often Hibernates presents some peculiarity that, at first observance, doesn't make much sense.  However, once you investigate the peculiarity thoroughly, you see why hibernate behaves the way it does. 
     
    An instance occurs when mapping a one-to-one relationship with a shared primary key.  In certain instances, even if this mapping is declared to fetch lazily, hibernate will eagerly fetch the association.  The reason is because due to the nature of a shared primary key, hibernate does not know whether to initialize the association to null or not without actually joining against the associated table. 
     
    Explore through an Example
     
    Let's set up an example to further explain the situation.  Let's say we want to map a one-to-one association with a shared primary key for two basic entities: a Passenger and a AirlineTicket.  A Passenger can only have one Airline ticket, and an Airline ticket can only have one passenger.  For our example, the relationship will be bidirectional from Passenger to AirlineTicket.
     




    We can map the objects with JPA and hibernate with the code snippets below. Note that we have marked the association from Passenger to AirlineTicket as LAZY.
    
    ....
    @Entity
    @Table(name = "PASSENGER")
    public class Passenger {
    
        @Id
        @GeneratedValue
        @Column(name = "PASSENGER_ID")
        private Long id;
    
        @Column(name = "NAME")
        private String name;
        
        @Column(name = "BIRTHDATE")
        private int age;
        
        @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "passenger")
        private AirlineTicket airlineTicket;
    ... 
    }  
    

    
    ...
    @Entity
    @Table(name = "AIRLINE_TICKET")
    @org.hibernate.annotations.GenericGenerator(name="passenger-primarykey", strategy="foreign",
     parameters={@org.hibernate.annotations.Parameter(name="property", value="passenger")
    })
    public class AirlineTicket {
    
        @Id
        @GeneratedValue(generator = "passenger-primarykey")
        @Column(name = "PASSENGER_ID")
        private Long id;
        
        @Column(name = "SEAT_NUMBER")
        private int seatNumber;
        
        @Column(name = "CLASS")
        private String clazz;
        
        @OneToOne
        @PrimaryKeyJoinColumn
        private Passenger passenger;
        
        public AirlineTicket() {
        }
    ...
    }  
    

    However, when we load the entity with a entityManager.find(..), hibernate issues a join in the generated sql to eagerly load the AirlineTicket!  If the Passenger entity was loaded with a ejql statement such as "from Passenger", hibernate will issue two separate sql statements back to back: one to load the passenger, and then another to load the airline ticket (which essentially is an eager fetch.)
     
    Why does this peculiarity occur?  When hibernate loads the Passenger object, it has to initialize its attributes.  AirlineTicket is an association which is mapped with a shared primary key.  Therefore, in order to find out whether the AirlineTicket is null or not, hibernate must issue a join to the AIRLINE_TICKET table to check if a row exists with the same primary key as the Passenger object.  If hibernate abstained from issuing a join to AIRLINE_TICKET and proceeded to instantiate a proxy for AirlineTicket, the Passnger object would contain a AirlineTicket, even if there was no real association in the database.
     
    Solution
     
    In order to take advantage of lazy loading when you have a shared primary key one-to-one relationship, you can use the optional=false setting on the relationship. For example, the AirlineTicket reference in the Passenger object would have optional=false.  This conveys to hibernate that the there will always be an AirlineTicket for a Passenger, thus it can create a proxy and it is guarenteed to have a corresponding object.
     
    Design Considerations
     
    So what are the situations to use a shared primary key in a one-to-one?  This begs the question of when is it best to use a one-to-one relationship?  One-to-One relationships are modeled in the domain when one object instance has an exclusive relationship with another object instance.  Simple examples would be [Person, Heart], [Husband, Wife], [HeadCoach, NflTeam]. (Of course, you could make silly arguments to debunk this, but you get the drift). 
     
    The easiest mapping for one-to-one relationship is to have a foreign kep from the owning entity to the other object.  In our Passenger example, the PASSENGER table would have a foreign key column AIRLINE_ID. This approach has no peculiarities with lazy loading, as hibernate can figure out if the association exists without joining to another table. All it has to do is check the foreign key for null. 
     
    A shared primary key for one-to-one mapping is appropriate only if the association is non-optional.  Meaning each end of the association has to exist.  If one side exists, so does the other.  If you map without this symbiotic relationship, you will run into the peculiarities above and possibly have to eager fetch for no reason.  This could lead to performance issues.  Shared primary keys save a column on the database, but the mapping is a little more complicated and peculiarities exist.  Hardware is cheap, knowledge is expensive.  Consider this approach carefully.

    Source Code 
    one-to-one.zip
     
    References:

    Monday, March 22, 2010

    5 Ways to Think Wisely in Development

    Recently I have been reading some popular and interesting social psychology books.  The contents are based on empirical evidence and scientific research, and often provide stories about how society operates, and why people behave the way they do.  Some of the books in this genre include: Freakonomics, The Tipping Point, Outliers and Kluge

    The most recent book I read is Kluge: The Haphazard Construction of the Human Mind, by Gary Marcus.  Marcus argues that the human mind is not the elegantly designed organ that we conventionally perceive it as, rather it is a cobbled together contraption which is a product of evolution. He offers explanations on why our minds do clumsy things, such as forget where our car is parked, or why we can't remember what we ate for breakfast.

    Without getting into the details, he points out several characteristics of the human brain that are products of evolution. Our cognitive makeup contains several bugs which can be referenced by psychological terms, some of which include: context driven memory, confirmation bias, motivated reasoning, and framing.  (I'll leave the explanation of these terms to the book itself.) He also gives recommendations on how to overcome these mental pitfalls.  It is a fascinating for the laymen psychologist. 

    So what does all this have to do with developing software?  From Marcus' exploration of the mind, I see several recommendations that can help us become better software developers.  Many of the technical and social decisions we make as part of a software team are often afflicted by the "kluges" of the mind.  Some basic and common sense tactics can help offset these imperfections, not to mention a help us becomes clearer thinkers, wiser developers, and better teammates. 

    1. When possible, consider alternative hypotheses.

    Often when we have an idea, we get stuck on it and want to see it through to the finish, just for the satisfaction of feeling good about ourselves. It could be a design pattern we see for a problem, or it could be some performance enhancement we think needs done.  We tend to not evaluate our own ideas in a dispassionate or objective way.  One of the simplest things we can do to improve our capacity to think and come up with good solutions is to consider an alternative track.  Contemplate on the opposite and counter your own initial ideas.  This can go a long way on improving your own initial thoughts or could lead to an entirely better solution.


    2. Imagine your decisions will be spot-checked.

    Research has shown that people who believe that they will have to justify their answers are less biased than people who don't.  Hold yourself accountable for any decisions you make,  technical or otherwise.   If we do this, we will tend to invest more cognitive effort and make correspondingly better decisions based on analysis, not just feelings or habits.  A good practice would be to write down rationale for any sophisticated decision made and make sure the reasoning is sound.  This could be notes for yourself, or published to the software team in a collaborative tool such as a wiki.


    3.  Always weigh benefits against costs.

    There is always some feature or tool that is cool to use or enticing to learn.  We should always weigh the benefits versus the costs before we proceed down a certain route.  The feature may be cool to the developers, but how much business value does it provide? Does it help the business save money?  The new ORM tool looks great and has some added benefits, but what cost will it incur versus the technical savings? 

    The inverse argument should be considered just as much.  A refactoring may incur some cost to implement upfront, but will payoff in the long run by resulting in more maintainable and defect free code.  The new integration testing tool may require a week of investment, but could reap dividends by allowing the team to write automated tests and eliminate the painstaking manual and repeated tests.  Sometimes the initial pain is worth enduring to get a long term benefit.

    4.  Whenever possible, don't make important decisions when you are tired or have other things on your mind.

    Marcus describes how we have two portions of the brain: the reflexive and the deliberative. The reflexive portion of the brain evolved early on and controls our bodily motions. It also controls ours emotions and fight or flight responses.  The deliberative portion of the brain is the most recently evolved and controls rational thinking and logic.

    When making decisions related to software, make sure you are well rested and not stressed.  Get enough sleep and keep your hunger under control.  When your health is not optimal, your reflexive portion of the brain activates and overrides the rational part.  This inhibits rational thinking and can especially inhibit complicated problem solving.  In order to make the best technical and team decisions, keep in a rested state to leverage the rational part of the mind.

    5. Distance yourself.

    Our mind is set up to ponder the near and defer future decisions for a later time.  It's always about the now and the urgency of the present.  The release needs to be done immediately, and we get into fire fighter  mode where everything is an emergency. Or...The debate is on about the new design and we must engage in the battle and win the argument!

    It's always best to take a step back and distance yourself from the situation. Imagine you are watching from afar and try to judge the situation objectively.  Of course, the here and now is always important, but it's also important to balance situation by distancing yourself.  Doing so will help assess the situation fairly.  It can also let the reflexive portion of the brain simmer down and let the deliberative mind step in to take control when needed.

    Even though we are rational people in a technical field, we are human after all.  We are products of our ancestors and emotions and rationality are both part of our makeup, although not always in the correct proportion. However, simple mindful steps can be taken to offset any shortcomings we have.