[Tutor] How to refactor a simple, straightforward script into a "proper" program?

David L Neil PyTutor at DancesWithMice.info
Mon Jan 6 23:31:06 EST 2020


On 7/01/20 12:29 AM, Alan Gauld via Tutor wrote:
> On 06/01/2020 03:25, boB Stepp wrote:
> 
>> So I have been thinking a lot about this today and find myself
>> stumbling around in a confused daze despite making lists, crude
>> UML-like diagrams, etc.  So questions!
> 
> OK, This switches the emphasis of the thread but lets go...

Maybe, but doesn't *some* of the discussion relate to design decisions?


>> I think the basic unit of code organization would be a ReadingMaterial
>> class, choosing this name to reflect Alan's thoughts that ultimately
>> there might be other things to read besides paper-based books.
> 
> Good thinking. But...
> 
> I'd create a very thin abstract class with just the interface
>   - remember think about behaviour first not attributes.
> Attributes are only there to support behaviour.
> 
> Then forget about eReaders etc for now and create a subclass
> that deals with the concrete problem of a paper book.
> 
> 
>> keep with the current confines of the original problem as stated, an
>> object of this class would have the following user-entered attributes:
>>   title, total_amount_to_read, total_amount_read, and goal_date.  I
>> switched from "pages" to "amount" as my best wording to reflect a
>> potential shift from pages read to percent of item read or lines read
>> or whatever.  This means that I will have to throw in the concept of
>> "units" if I do this generalization now.
> 
> The units are specific to te subclass. Amount are the generalized concept.
> 
> My only question is whether the dates are relevant to the book? Or do
> you need a Reader object? It is the reader who has reading goals. The
> book will tell you how much to read and current position. But it is not
> interested in dates.

Not necessarily. The reader doesn't know if (s)he is about to drop dead!

Alternately, if the book has been borrowed (eg library), then it has a 
finite availability.


> So now we have two objects interacting. And in theory you could have
> multiple readers reading the same book, and one reader reading multiple
> books.
> 
>> I know the Agile people
>> might say stick with today's problem (pages) and worry about other
>> units when one is forced to.  So I may stick with pages after I hash
>> out more important difficulties.  So back to "pages" for now.
> 
> Correct approach. Recognize that you may have another type of
> ReadingMaterial to deal with in the future, but park it for
> now - its a differnt class.

+1
Make it work before you make it better!


>> First point of confusion:  the creation of the ReadingMaterial object.
>> Should it start with (a) my_book = ReadingMaterial() or with (b)
>> my_book = Reading_Material(title [, total_pages_to_read,
>> total_pages_read, goal_date])?  The brackets indicate optionally
>> starting with all four attributes from the get-go.  In other words in
>> (a) the object would see to initiating the acquisition of user input
>> itself, while the second has some other entity taking care of user
>> input and then passing it into the instantiation process.
> 
> Separate user interaction from logic. What happens when you want to use
> this ReadingMaterial object in a GUI? So you have a ReadingMaterialView
> that can deal with interacting with the user to create the book. In an
> industrial version of this we probably have a database of readMaterial
> and the readers select an existing book. The creation of the book is a
> database(library?) admins job.
> 
> So I'd definitely opt for a separate data collection function/object
> and then instantiate the object with the data already gathered.

+1, which aligns with earlier mention of MVC
Once again, keeping in-mind the future possibility of using a GUI, first 
write the code to work from the terminal-only.


>> the proper way to proceed?  On the (a) side, ReadingMaterial knows
>> what it needs and it is the natural location for future additional
>> attributes that may need to be acquired someday.
> 
> It knows what it needs but it does that by being created with it. Thats
> what __init__() - ie. initialization - is for.
> 
>> direction I am currently leaning.  So the initialization of a
>> ReadingMaterial object might look like:
>>
>> class ReadingMaterial:
>>      def __init__(self):
>>          self.title = _get_input(???)
>>          self.total_pages_to_read = _get_input(???)
>>          self.total_pages_read = _get_input(???)
>>          self.goal_date = _get_input(???)
> 
> Again, how does that work in a GUI? Or on the web?

Alternate view: Were the get_input() coded as part of ReadingMaterial, 
how would we be able to re-use the method when needing to input into 
some other class, on some other project, some other day, ...


> I am answering your issues as I go and in each case you have
> already guessed the response. I think thats a good thing! :-)

+1


> Now start writing some usecases. Forget about code for now.
> How does the user interact with this application?
> That should start to give you clues as to what methods
> the classes need to support.
...

> It is really important to have it clear in your head how
> this app will work as a dialog with the user. That is fundamental to
> understanding what operations it needs to support. And operations
> translate to methods. And then you decide which object supports
> which operations. That in turn will tell you which attributes are
> needed in which class.

+1

-- 
Regards =dn


More information about the Tutor mailing list