Changing Mindset: From Procedural to Object Oriented

Yesterday I had the chance to write some code to determine if I needed to schedule an action for later processing, or do the action immediately. I am working on a system that has a fairly well laid out component architecture, with a fairly good Business model. However, it is almost all “Controllers and Data Structures” at this point. Given my previous experiences with how people would write this type of code, it would invariably end up like this:

  1. public void someComponentMethod(Long rootModelID) {
  2.   RootModelObject root = DAOFactory.getRootModelDAO().getRootModel(rootModelID);
  3.  
  4.   // many lines of code later …
  5.  
  6.   if ( root.getExtraData() != null &&
  7.         root.getExtraData().getSchedule() != null ) {
  8.         Schedule s = root.getExtraData().getSchedule();
  9.         if ( s.getScheduleDate().after(new Date()) ||
  10.              s.getCronExpression() != null ) {
  11.                 root.setStatus(SCHEDULED);
  12.                 DAOFactory.getRootModelDAO().save(root);
  13.                // schedule for later code
  14.         }
  15.   } else {
  16.         // deliver immediately code
  17.   }
  18.   // many lines of code later …
  19. }

There are a number of issues in the above code:

  1. The interface to this method is abhorrent. I will discuss this in another post.
  2. The component knows WAY too much about the specifics for processing.
  3. Hand in hand with the above, it knows way too much about the Business Model.

This is a classic case of “Asking, not Telling”, the antithesis to the awesome article Tell, Don’t Ask, by Dave Thomas and Andy Hunt. GO NOW and read it if you haven’t.

Here is the code I ‘ve written so far:

  1. public void someComponentMethod(RootModelObject root) {
  2.         // small amount of other code
  3.  
  4.         if ( root.shouldBeScheduled() ) {
  5.                 root.setStatus(SCHEDULED);
  6.                 DAOFactory.getRootModelDAO().save(root);
  7.                 scheduleComponent.schedule(root);
  8.         }
  9.         else {
  10.                 root.setStatus(PROCESSING);
  11.                 DAOFactory.getRootModelDAO().save(root);
  12.                 nextComponent.process(root);
  13.         }
  14. }

There are few things here that are better: First, I pass in the object I want to work on… this is SO much better than having to go get the Object from some back-end store by ID. I will definitely be talking about this more in the near future. Second, I broke out the beautiful comments from the code above into separate methods, on the components that they represent. This can only make things easier in that code, which most assuredly would have otherwise been in the if block as the comments suggest. And finally the piece that got me started on this post, I moved all of the logic revolving around the Schedule behind the walls of the RootModelObject. But, I did not stop there. Since from the perspective of the RootModelObject, it is not it’s responsibility to determine if it should be scheduled, I created a shouldBeScheduled method on the ExtraData object, which then called a shouldBeScheduled() method on the Schedule object:

  1. class RootModelObject {
  2.   …
  3.   public boolean shouldBeScheduled() {
  4.         return getExtraData().shouldBeScheduled();
  5.   }
  6. }
  7.  
  8. class ExtraData {
  9.   …
  10.   public boolean shouldBeScheduled() {
  11.         return getSchedule().shouldBeScheduled();
  12.   }
  13. }
  14.  
  15. class Schedule {
  16.   …
  17.   public boolean shouldBeScheduled() {
  18.         return ( getScheduleDate().after(new Date()) ||
  19.                    getCronExpression() != null );
  20.   }
  21. }

This “string of pearls” makes it much easier to keep the code where it needs to be, while providing convenience to the component developer.

So, the code is better, but part of me says that the code really should look like this:

  1. public void someHigherLevelComponentMethod(RootModelObject root) {
  2.   …
  3.   root.schedule();
  4. }

Since technically, when you say “process immediately” you are effectively saying “schedule for processing now”. What do you think?