no. 9| 05.28.2014 |

Modeling Stuff Using Ruby Classes.

Crap.

This blog is super late. Again.

This week (uh, I mean last week) we were asked to pick something we'd like to model and show how to do it with Ruby classes, methods and instance variables.

While my first impulse, "Shame Meter!" would surely be hilarious, how about something more positive and productive? A time management tool.

Ideally, I'd like to input tasks that have to get done during the week, and a time estimate of how long each task will take. I want my time manager to break up big tasks and distribute them in chunks of time across the days of the week. Then it could tell me what I should be working on each day, and as I do stuff, track by task how much of the allotted day's time I've used, and warn me if I'm getting off track.

I've been reading Practical Object-Oriented Design in Ruby (aka POODR) by Sandi Metz. I really like it, and I'm going to try and follow some of her recommendations for object oriented design. To the best of my still-fairly-meager ability.

First and foremost? Make sure each class has a single responsibility.

So I have to think specifically about what parts a time manager will need, and then how to translate and organize those parts into classes that are as focused as possible.

I'll probably need classes like "Week", "Timer", "Notifier", "Day", and maybe things like a "DayScheduler" that would break the weekly task time estimates across days. In truth, I'm overwhelmed by the whole animal, so I'm going to start small. I'm pretty sure I'll need a class like this:

Knows the following stuff about itself:

- The task name.
- The amount of time this task has been allotted for the day.
- How much time is left for completion.
   (This could maybe be a negative value if I've gone over time.)
- If it's an active task.
   (i.e. is it being worked on right now or ignored?)

Can do the following stuff:

- Report its task name
- Report the time allotted for the task for the day
- Report how much time is left for the task
- Report its active status
- Change its active status
- If active, decrement the time allotment with a timer.
   (I feel like this timer should be a separate object?)

Oh code that is and does the things above, I shall call you "DayTask". You shall be a class. I hope you shall not suck.

Objects have "noun-y" parts, like properties or states, and "verb-y" parts — which are behaviors, or "actions they can do". The object-creating blueprint that shall be the class "DayTask" will store the things from the "Knows about itself" list in instance variables. The "Can do" stuff will take the form of methods.

After a bit of Googling, it seems like timers can be a bit tricky. In order to keep moving forward, I think it would be best if "DayTask" isn't responsible for timing. I don't know how to implement it yet, and besides, that would violate single responsibility too, right? Maybe "DayTask" just needs to record a time stamp when its active state changes. If there's a time history, it can compare that with the current time (which is easy to get in Ruby) and report back a status based on the active state. Some external object could then be responsible for occasionally asking, "Hey instance of DayTask, how much time remains for your task?" If the task has been inactive, it would respond with "Same as the last time you asked (sheesh)." If it's been active, it can calculate how much time has passed since it got activated, decrement that from the time remaining and report back.

That means I'm going to need one more instance variable: One that can hold the last known time the instance was set to active. And since it's easy, I'll update that variable when the instance gets set to inactive too, because I can already think of 3 possibilities that might need that info. Hopefully that doesn't count too much as "trying to guess the future", which according to POODR is a bad idea.)

So here's what this "DayTask" class might look like:

Click here for the full size code screenshot.

I can already see both my methods are probably violating the "Do only one thing" rule of thumb. The "active" method is esentially flipping a switch to turn time tracking on or off, but it's also recording the time a switch flip happens. The "time_remaining" method is doing that secondary task of time stamping as well. Right now that's probably not a big deal, but since the only-one-thing rule applies to methods too, it's probably not the best design.

That time stamping action could be broken out into its own method. Then the "active" and "time_remaining" methods could call the time stamp method, and it would make it easier to change the stamping system later, if need be. Perhaps from a single value to an array or hash containing a history of time-stamped state changes — which would be necessary if I wanted, someday, to implement some kind of "FillOutMyTimeSheet" functionality.

I'd make that change, but look! I'm out of time.

#DBC, #Classes, #OOD, #POODR