We made a lot of progress working on our python shop this weekend. Our working patern ended up being a pair programming scenario, with him at the keyboard (as he was the python person, this was the most efficient) and me finding logic problems, and working on the overall program design. Based on some of what I’d seen discussed recently on the Alt.Net list regarding validation, we ended up doing a close-to-the domain style validation. The classic TurboGears way of data validation is to attach it to the page methods inside the controller. In contrast, the Alt.Net discussion centered around how domain logic validation (for instance, object x should have an object y to allow a certain set of actions, and this integer should not allow things outside of a certain range, and certain fields should be required) should be usable with the business objects themselves. If this is really domain logic, that is something that gets changed by the client, should be in one place and should be reusable no matter how these objects are addressed, bet it in other forms in the application, future tests, or even command-line manipulations. In a more advanced scenario, we could even have different object validators that we inject as appropriate… since this project is a toy 5-table project, we considered that, and decided that was out of scope. But to bring that object validation logic into the domain, we ended up working an optional validator method into the business objects.. We still have validation in the controller to deal with the form, but it purely tests for formatting of input… for instance, numbers should be numbers, to make sure that any data that makes its way into the object at all at least is the right type so the validator there won’t throw up trying to compare a text string to a decimal or something. The only negative of this is that it ends up being a two-pass validation, (type formatting then business validation) but it seemed like an acceptable tradeoff.
Archive for January, 2008
So, a colleague and I started on a little project. We’ve decided on our own time to take a toy project and jointly try it out in as many languages as are interesting to us. It’ll be a great learning experience, and it’ll also be some nice code that can be shown off without nondisclosure-type strings attached. We’re an interesting team because he’s heavily a Python person, whereas I’m mostly .Net. We’ve decided upon a shopping cart as our model project.
Our first session was to determine a general design/scope for all of these little shopping cart projects. An hour or so later, and a paper full of boxes and arrows, and we had a rough first hack at the sort of model that Amazon must have. Upon looking at it the next day, we decided that we’d gone though some temporary insanity. For the type of toy project we want to build, things like coupon codes, order fulfillment and tax were way out of scope! Really, a simple 5 table design was plenty for experimentation, and more than that would be too exhausting to realistically get through multiple projects.
Our first project is in Python, which you might think would be boring for my python-specializing colleague, but we’re doing it using TurboGears and SqlAlchemy, which are both new to him. I’m working my way through learning Python basics and finding some interesting differences from C#. The passing in of self everywhere as a parameter is odd, especially in that you only have to declare it, but not really pass it! I also found the importing of not just namespaces, but of actual classes (sort of as a shortcut) to be fairly weird. the dynamic number of parameters to functions was interesting as well… in C# you’d have to handle that as a passed-in array, list, or dictionary, and those things really wouldn’t be full-fledged parameters. At this point, he handled the initial TurboGears setup, and I’m looking through the default login stuff. Some of the initial setup was a little odd-I mistakenly tried setting things up in Windows before throwing that all out and giving it another go as a full cygwin setup, which worked a lot better! Hopefully, by the end, he’ll have a good grasp on TurboGears, and I’ll have a decent beginner’s grasp of TurboGears and Python! The SQLAlchemy stuff looks to have searching capabilities that are similar to some of what nHibernate has with its Criteria tools. (which, admittedly I haven’t looked into much-I’ve pretty much used HQL thus far)
So, I’m still working my way through The Pragmatic Programmer (yeah, I’ve been busy) and just went through the chapter on Demeter’s Law. I have to say, I’m a little skeptical. The general idea is that you only use objects and methods of objects that your current method(or class) “owns” directly, not things that other objects own. So for example, if your object takes a “Customer” object containing a “Person” object, you should not call Customer.Person.FirstName, because you don’t own the “Person” object. Instead, you should use a wrapper getter in Customer that gets FirstName from Person (CustomerFirstName, say). And if Customer was inside of Order, and you wanted the Customer’s first name from Order, the proper thing to do would be to wrapper the CutomerFirstName up, maybe with BuyerFirstName.
SO, instead of Order.Customer.FirstName
you’d have Order.CustomerFirstName
And THAT you can safely call. What’s the reasoning for this? well, this allows all kinds of changes to Person and FirstName, and once the class is changed in Customer, nobody else needs to know anything happened. since everything else is a wrapper, everything else will just work. Problem? well, Order, instead of being a stripped-down class just dealing with order-related stuff ends up possibly being an enormous class full of Customer and Person wrapper stuff, and depending on what other objects Order has, it could be even worse. Pragmatic suggests dealing with this by using a code generator… Frankly, though I see how coding this way would be safer, the idea of having huge amounts of wrapper crap kinda feels like a smell. Maybe this is worth it, but I’m not quite sold yet on it being worth the clutter. I’m going to have to think about this one a bit more.
I noticed yesterday there was a version of NHibernate out that does some things I’ve really been wanting: Version 1.2. Now, I’m on 18.104.22.168. Things I’m really excited about: the ability to use strongly typed collections. I’d looked into Ayende’s solution in his NHibernate.Collections, but frankly after checking it out, it gave me a bad vibe, so I never pushed for its use. But now, it’s built-in, and doesn’t require any sketchy stuff. Admittedly, the requirement that methods for NHibernate be virtual seems a little weird to me (I’d really prefer if the ORM didn’t affect the code in my model even that much), but that I can accept. OK, I confess, I was a little uneven about setting the virtual thing on my current code, because I didn’t see the point. But since the migration notes have a strongly-worded note about how 1.2 will complain if virtual is not there, I guess I’d better convince myself about virtual’s use, and get consistent on it!
“Of course software development is not dry cleaning!”, you might be saying. However, it’s apparently a not-so-obvious idea. As a services-oriented software company, what’s your role? Is it to deliver “satisfaction guaranteed” ? It it to do whatever it takes to get things done on time, and if there are delays, to do what it takes to get back on schedule? If the delivered is somehow unacceptable is it your job to fix the situation, because what you delivered wasn’t perfect? Is the customer’s singluar role to evaluate if what they brought you turns out right? Really, that sounds a lot like a dry cleaning business. The “Dry cleaning” approach is a classic services-industry scenario.
Dry cleaners, restaurants and florists who follow this model are generally going to be successful, it’s a tried-and-true approach. It’s really understandable that in approaching the services-side of software, that people might think the “dry cleaning” model would once again lead to success. However in software, this model leads to unsuccessful projects.
Picking apart the scenario, the main problem is the client relationship. Software services are very different from traditional services in that the client’s requirements can be incredibly complex and individualized. Developers need to understand the client’s business and the problem that nees to be solved. Communicating this information is not a one-time thing, but a task that generally runs thoughout the process of development. The client can’t just “drop off” what they need and pick it up later with software. In contrast, their busness and specific needs are so central that the client needs to be considered part of the development team to create the product together-the development team develops, the client communicates and is the investor, the designers manipulate graphics, these are all parts of a working whole with the same goal.
It might seem “scary” to let the client inside the team, but the fact is, doing so will help clients to understand that they and their requirements are important and valued by the software company. In addition, clients will understand that since they are important and equal members, they have to live up to their role in the team or the project is hurt. Since it’s no longer and us-vs-them situation, if the client IS late on something, they will have an easier time understanding that their actions have consequences, i.e. the whole team is delayed, and they’re are either causing someone to work overtime, or maybe they’ve created a situation in which the team cannot possibly deliver on time. If you leave the clients on the outside and leave the development process a black box, it’s understandable that they would be intolerant to delay or bugs. Bring them into the decision process… “well, things did end up getting a little more complex than we anticipated, so if we cut time for testing, there are going to be more bugs. or we can add time and deliver with fewer bugs. What’s best for the project?” If the client understands what led to bugs and their own role in that, they will be more willing to see followup as part of the process and not a “freebie” they are owed for the software company “messing up”. More followup was just a tradeoff choice.