« Interesting Announcement at Tonight's MySQL Meetup | Main | Evening at the Pumpkin Festival »

October 19, 2006

Wrestling with Building a New Page View

I've been wrestling with an issue over the past few days that I just can't seem to get right. Hopefully hammering it out here might provide some clarity.

I'm writing a new view of an existing, very complex, time entry form. It's like a timesheet, but it contains a lot more than just days of the week and entry boxes for hours worked. A user can split their hours on one given day over any number of projects, entering the specific hours and times associated with each project. There is also some semi-complex javascript to provide on-the-fly calculations as different points on the grid are updated.

The issue is this. The code is organized in such a way that all the data is gathered and then painted to the screen using a specific method for output (something like TimeGrid->paint).

So the logical thing to do seems to be to subclass TimeGrid and create a new class that has just the paint method. In a perfect world all the calls to the new class would go up to the super class for data processing and handle only printing the information out to the screen in a new format.

Unfortunately TimeGrid->paint doesn't just paint, it also contains a fair amount of processing to decide what to paint and how to respect various settings in the application. So creating a subclass object and duplicating the paint method is going to result in a ton of duplicate code, which I'd like to avoid.

Here are the ideas that have crossed my mind. Some of them I've attempted, others seemed wrong enough off the bat that I moved on:

  1. Create a DynamicGrid class, a subclass of TimeGrid, with only a paint method. Step through TimeGrid->paint and pull logic out into a separate TimeGrid method that can be accessed from both TimeGrid and DynamicGrid.
  2. Create a new method in TimeGrid, paint_dynamic_grid, and duplicate the paint method's logic but change the presentation.
  3. Split TimeGrid->paint into two methods, trying to provide better separation between logic and display. Let the logic method choose which display method to use (paint or paint_dynamic_grid).
  4. Move the pieces of TimeGrid->paint logic that aren't for presentation back up into the calling class.
  5. Create a second method (paint_dynamic_grid) in TimeGrid that contains all data manipulation and business logic in TimeGrid->paint, but doesn't paint. Create a new class and method, DynamicGrid->paint, that is presentation only and takes the data from TimeGrid->paint_dynamic_grid and performs the presentation of the data. Where possible consolidate TimeGrid->paint and TimeGrid->paint_dynamic_grid into common methods.

I think the last approach is really what needs to be done, it may produce some duplicate code if it's hard to centralize logic into common methods, but is probably the best as far as moving toward a cleaner interface.

I've learned that 1) it's not always easy or intuitive to create a true MVC separation in the code and 2) it's very difficult to add a new view when there isn't a tight MVC implementation.

Thanks for being my tech sounding board today.

Posted by mike at October 19, 2006 1:46 PM