You may recall me mentioning in passing some attempt at re-implementing The Project in C#. You may also recall me later reflecting on the several false starts I did along the way, which eventually led me to abandoning these attempts.
Lately, though, there has been an urge building in me, kind of like lower bowel movements. I feel like most of my obsessive questioning of how to apply domain-driven design and object-orientation has settled down. Part of the reason why I kept starting and stopping my earlier attempts at re-implementing The Project was because of how little I knew, and that was because of how little experience I had doing it the right way.
I think I’m ready for another try. This attempt at re-implementing The Project shall be code-named “Hydrocon.” Why? I don’t know. Further, this will be written in Smalltalk. There is no reason to learn yet-another-curly-brace language.
So, until I feel like stopping, I will spend a small amount of time each day writing code for Hydrocon, and the related thoughts and ideas that occur to me during the course of these sessions will become the content of my Wednesday posts.
I decided to work off of something of a domain model before I started writing code. I jotted this down in a text format. The minus sign indicates a private member, and the plus sign indicates a public member:
- has an id
- has an address
- has many Rooms
+ contains a Room
+ deAllocates a room
- has an id
- has a name
- has many Equipments
+ houses an Equipment
+ dehouses an Equipment
+ transfers an Equipment to a Room within the same Building
+ transfers an Equipment to a Building
- has many descriptions
- has an id
- has a status
+ moves to a new status
Value Object: EquipmentID
- has an equipmentNumber
- has a vendorID
Value Object: EquipmentDescription
- has a serialNumber
- has a textDescription
- has an author
- has a lastEditedTime
+ accepts an attribute
Value Object: PCDescription extends EquipmentDescription
- has a make
- has a model
- has a type
- has a classification
- has a build
- has a buildVersion
- has a networkName
This quaint model will be emergent. Methods for accessing the properties of these objects, for example, are not listed. Also, not all types necessary for type hiding are present, either. There are more sub-types of EquipmentDescription than PCDescription, but for now we’ll just focus on this subset of the actual model.
One part of Smalltalk I am already going to take advantage of is the lack of needing to cast to sub-types. Normally, I’d avoid this by using Double Dispatch or, as I have here with the EquipmentDescription’s accept method, try as much as possible to make the superclass’s interface contain methods that subclasses can implement.
In statically-typed languages, though, especially those without function pointers, like Java, this is a pain in the butt. But I think in Smalltalk, this is going to be much more smooth and accomplished with less code, too.
I started by writing the Building object. The domain organically grew: I realized that a Building should never remove a Room, it should only accept new ones or mark rooms as unavailable for new inventory. I paused when I realized OrderedCollection wasn’t what I wanted for the list of Rooms. I went with a Set instead.
It would be nice to have a way to view the instance members of a class without having to click off of the method I’m writing. Also, it would be nice to have a way to find out all of the messages a variable must respond to within a given context. Something like “Extract Interface.”
Old habits die hard: := vs. = for assignment still gets me.
Smalltalk’s lack of constructors means I have to expose a getter and a setter, even if I don’t want to expose the setter. Blah. Smalltalk could use constructors like Java. I went with a class method and set-once semantics for such setters.
setIDOnce:anId "sets the ID once. Further attempts to set it will be ignored." hasIDBeenSet ifFalse: [ hasIDBeenSet := true. id := anId. ].
Shortly after, I started hating it. If an object gets too big, I will have to use a Set for these flags. I’ve written two objects. Time for some unit tests. But first, I need to take type hiding seriously.
New additions to the domain, previously implicit:
Value Object: RoomName
- has a stringName
Value Object: RoomID
- has an integerID
I am aware that embedding the type of the variable in the variable name is probably a code smell in a dynamically-typed language. As I wrote these two classes, I really started to doubt the wisdom of the lack of constructors in Smalltalk. The language’s purity and minimalism actually generated more boilerplate code in the form of set-once methods.
Point of syntax: I think I’ll prefer a to put a space between “| tempVars |” and “^ returnValue” statements.
I started to implement equals method for RoomID…and was really annoyed that I can’t access the internals of another object of the same type. Of course, I can’t because of dynamic typing. Still, I think this could still be added to the language…some sort of special syntax that says “I am accessing a private member of this object, and only allow this to work if the object is of the same type as me”:
= other "answers true if the IDs are equal" ^ intID = other@intID.
The fact that I can’t do this is really annoying. I don’t want to create a category of methods called “private”, even though the vast majority of the built-in Squeak library does this. I know it’s a people problem. But that sucks.
Fine, fine, I’ll do it and name it something foreboding.
= other "answers true if the IDs are equal" ^ intID = other breachEncapsulationOfID.
Interesting that when I write the same method for Room, it’s all good because Room hides types:
= other "answers true if the Room is equal to the other one" ^ name = other roomName and: [id = other id].
Incidentally, I won’t include roomName in this method, but I have it here for demonstration. And I wrote my first compound boolean expression in Smalltalk. I didn’t even have to look up the syntax. Awesome.
I started to debate whether the constructor of Room should take primitives or objects. That is another topic, though. I could always have both.
That’s where I left it. Let’s hope this excursion into Programming Excellence doesn’t end up like The Carbon Copy Whiteboard did.
|Announcer: You’re reading the EIP web-ring.|