Wednesday, November 12, 2014

Programmer problems: there's one right way to do that and it's wrong

I'm still stuck on that problem I discussed last week, how to get a few numbers from one place to another place within my problem.  Or rather, I've won one little learning battle but the programming war remained frozen like Stalingrad.  What I'm trying to do, task #190, is make my program so that when a user adds a book to the list of books they want to read (for example), the new book goes to the top of their book list but not to the top of, let's say, their recipe list.

In jargon terms, I'm trying to retain and pass around context, and apply that context consistently.  That context includes tags, of course: (once again, I'm blurring out all of the jargon) if I say "Books", the system should remember "Books" for as long as appropriate.  It also includes my identity: if I add a task, it should go on my list, not yours.  And the context should stick around: after adding the task, I'd like the website to remember to show me my list of tags, not yours or everybody's.

Last week I was stuck on one portion of this problem: taking the context from one web page, like after you click "Books" and "Filter", and passing it forward to the buttons on the page so that, when you add a new task, the controls to add a new task remember that you are concerned only with "Books".  Once I found the right tool (it turned out to be something called a QueryDict), I solved that in five minutes and two lines of code.  Of course, it had taken 10 cumulative hours to figure out those two lines of code, but ... they work, and they are the Right Way for my platform of choice.

But that's only covers passing the context around; I also need the system to properly apply the context when it stores and retrieves data.  And it stores and retrieves data for many reasons—when looking at the list, or when adding a new task, or when moving a task up or down, just to name a few—so I want to write the code for that once and have it work in all places.  This is called DRY, "Don't Repeat Yourself." Being the avid learner that I am, I went to find the most correct way to consolidate all of my repeated view filtering code in Django.  The instructions say to use a custom Manager:
You can use a custom Manager in a particular model by extending the base Manager class and instantiating your custom Manager in your model. There are two reasons you might want to customize a Manager: to add extra Manager methods, and/or to modify the initial QuerySet the Manager returns.
But when I go looking for examples, I stumble across an argument:
Using raw ORM query code in views and other high-level parts of your application is (usually) a bad idea. Instead, creating custom QuerySet APIs and attaching them to your models with a PassThroughManager from django-model-utils gives you the following benefits:
Although the very first comment is pure trolling.
There is no "right" way to use an ORM. Put it down and step away.
Troll aside, more googling finds that somebody agrees with the premise:
If you haven’t read that post, head over that way to hear why it’s a fantastic idea to build high level interfaces to your models, and because of limitations in Django’s manager API, to do so in QuerySet’s rather than Managers.
but has a different solution in mind:
While this definitely has the feel of slightly noodley trickery to it,  I think it starts to get at the core of what we might want in a more robust future ORM for Django: the ability to define high-level logic to assign meaning to particular collections of fields, and to preserve that logic across relations and chains.
Somebody else also agrees with the premise, but has a yet better way to do things:
But using Python mixins I've developed what I think to be a better way
(If there's one nice thing about online arguments about the best way to do a particular kind of computer programming, and there may not be, it's that everybody who wants to be read has to provide examples; nobody can just claim there isn't enough room in the margins to back up their claim.  On the other hand, you then have to read their examples.)

So the practical question is, do I want to do things the "rightest" way, which is going to mean researching this debate and picking a side, or do things the way the official documentation suggests, or do things the quick and dirty way and pay for it later? This is not a rhetorical question; being able to accurately estimate the cost of fixing it later is a professional skill which great programmers have. In my case, I'm trying to roughly balance expediency and rigor, and that's not working very well. I probably want to lean a bit back toward expediency.

No comments :

Post a Comment