4

One of the functions of an application I manage is to operate a fleet of vehicles. I have an object vehicle with which I can do tasks that are vehicle-related; getMileage(), setDriver(), etc. I also have a collection of vehicles with which I can do tasks that are multiple-vehicle related; fitWinterTyres(), updateInsurance() etc.

Until now, when I am creating my collection of vehicles, I have been using PDO::fetchAll with the argument PDO::FETCH_CLASS to return vehicle objects into my list of vehicles. This has advantages, as when traversing the collection, I can use well-known methods to view and edit individual attributes in bulk.

However, I have been noticing that often times we have been creating collections where we compute member attributes that are only of relevance to the current collection. For example $vehicle->priority helps staff decide which vehicle to use based on the condition of all the vehicles in just this collection. Another is $vehicle->service_due which when computed makes sure not all vehicles get booked in for a service at the same time. To me, these dynamically computed variable are still object attributes, but I wouldn't expect to view/edit them on a single instance.

In addition, there are attributes which useful in the collection but redundant in an individual instance. The $vehicle->driver_ID is stored as an integer in the vehicle table in the database. I can either get a seperate collection of drivers and find the driver by ID, or JOIN the ID with the drivers table to get the driver name, and populate the $vehicle->driver attribute.

Finally, there are often many attributes which are just never needed in a collection, which makes me wonder how efficient it is to use the whole object in collections.

Is it good practice to have a base object which is extended just for the purpose of being a member of a collection? If not, how should I be doing it?!

(the development environment is php and mysql, but I guess the question is platform agnostic)

  • You should instead subclass the collection in which you store Vehicles with new methods like findNextVehicleToUse() (this returns the unbooked Vehicle with the highest priority) and findVehiclesWithServiceDue() (this returns all the Vehicle that are allowed to go to service). – Spotted Mar 22 '16 at 13:55
1

However, I have been noticing that often times we have been creating collections where we compute member attributes that are only of relevance to the current collection. For example $vehicle->priority helps staff decide which vehicle to use based on the condition of all the vehicles in just this collection. Another is $vehicle->service_due which when computed makes sure not all vehicles get booked in for a service at the same time. To me, these dynamically computed variable are still object attributes, but I wouldn't expect to view/edit them on a single instance.

$vehicle->priority should actually be replaced by a function in vehicles collection called something like getVehicle(). This function will return the vehicle to be used for the task based on your priority algorithm.

$vehicle->service_due should be replaced by a variable $vehicle->last_serviced_on. And, your vehicles collection should have a function called getVehiclesForService(number). This function would return the vehicles you CAN send for servicing based on the vehicle's last_serviced_date

In addition, there are attributes which useful in the collection but redundant in an individual instance. The $vehicle->driver_ID is stored as an integer in the vehicle table in the database. I can either get a seperate collection of drivers and find the driver by ID, or JOIN the ID with the drivers table to get the driver name, and populate the $vehicle->driver attribute.

Ideally, you should be handling this (Database to Objects) part via an ORM. If you aren't using one, it depends on your use case, if the driver's name is required in all cases when a vehicle is accessed, it should be loaded with the vehicles from database, otherwise it can be lazy-loaded.

Finally, there are often many attributes which are just never needed in a collection, which makes me wonder how efficient it is to use the whole object in collections.

Modern languages should only be keeping a reference to a complex type. In C/C++ one could have used pointers, but some kind of collection would always be required to keep objects that need to be treated as a group.

  • Hi Ozair - the problem is that I want to see priority, service_due and driver as attributes when I display my collection, so that's why they end up as a vehicle attribute rather than a vehicles method. If I have a method in vehicles, I'd still need to iterate over the collection to update the vehicle attribute, which means the vehicle object should have the attribute defined in the first place. – boatingcow Mar 22 '16 at 12:54
  • Can you have a method for that in vehicles getPriority(vehcileIndex) OR getPriority(vehcileId)? The priority of a vehicle might be changing frequently and the collection might be calculating it quite frequently anyways. – Ozair Kafray Mar 22 '16 at 13:01
  • Yes, there could be a method in vehicles which computes it on a per-vehicle basis, but there are two problems here; 1) the basis for priority may have changed between the first and last vehicle, 2) multiple queries to the database for the same metric are usually much more inefficient than a single well-formed query. – boatingcow Mar 22 '16 at 13:11
0

I would say that objects and collections of them are fundamentally different beasts. Management of a collection or pool of objects is different from the management of or interaction with a single object individually, and each merits its own interface, design etc..

For example, whether an individual vehicle is due for service is different from whether a service appointment can be had. These concerns should be separated (SRP, single responsibility). I would say that a vehicle is due for service according to that vehicle's maintenance & service protocol. I would consider it inappropriate to say that a vehicle is due for service only if an appointment for it can be obtained. Due for service, making an appointment before it is overdue for service, scheduling the service for a large fleet, and actually taking the vehicle in for its scheduled service appointment are each different task that should be executed at the appropriate level (the pool or the individual vehicle).

It seems to me that your system design isn't giving the pool or collection enough responsibilities. Further, I would separate and design more management objects than just the pool of vehicles. Beyond vehicle and vehicles pool, I'd probably have a servicing manager, which manages (scheduling of) appointments, and is oriented toward the understanding (and collecting) the mechanics and service bays in service locations.

Regarding the drivers, yes, do the JOIN approach (with respect to the persisted information model), keep your data DRY, separate responsibilities, and don't cache a copy of the driver in the vehicle.

Rather than concerning oneself with efficiency of the objects, I'd concentrate on design principles like DRY and SRP. These are saying that things are being conflated and need to be separated. The redundancies you are finding are a sign that the design needs attention, not just an efficiency issue. (Efficiency/performance may merit attention, but only when you have a good overall characterization of performance (e.g. tests), and, measurable issues in some area should we try caching or de-normalizing for performance. Caching takes work, and has runtime costs, so we need those tests to make sure we're not making something else slower.)

  • service_due is a function of current mileage, service mileage interval, service time interval, location and availability for all vehicles in the current collection. As it is dynamic, I don't want to persist it anywhere other than the current session. I see service_due either as an attribute of each vehicle in a collection, or as a collection of services_due in its own right. If service_due is not an attribute of each vehicle, then surely I would have to combine the services_due collection with the vehicles and priorities collections and others to achieve a meaningful display? – boatingcow Mar 22 '16 at 17:45
  • Service-due makes sense as a function (of time&mileage, interval/policy for that vehicle, last service info (date/time)), but not of properties (like the availability of) the other vehicles or service appointment availability. I would separate those concerns. – Erik Eidt Mar 22 '16 at 17:53
  • service_due is the result of all those properties and does depend on the availability of other vehicles and drivers. This is a business rule which has been modelled in the application. That's why it's calculated and not just a straight function of the attributes of a single vehicle. The same goes for priority and attributes elsewhere in the application. Hence the question on whether the collection should use the same object, or perhaps treat it as a different model. – boatingcow Mar 23 '16 at 8:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.