I wrote an internal API for products. The API consists of many methods that make changes to the database. The value is in the database is the original value and the code changes it.
For every different change there is a method that makes this change. The API uses the database as internal memory.
Every method in the API gets data, updates it or writes it. There is no code that makes changes to the product in the memory. Let’s start with a simple example.
A product has a normal price and a discounted price. The following code creates or updates the discounted price.
$api->ProductSetDiscountPrice($id, '1995');
At first this doesn’t seem as a big problem. But when I started to write more code, it became apparent to me that this is the wrong way. In a different universe the code would look like this.
my $product = $api->ReadProduct($id);
$product->set_discount_price('1995');
$api->WriteProduct($product);
I removed the coupling with the database by introducing a ‘Product’ object.
The next example is a bit more elaborate. Here the change is more integrated.
sub MakeSupplierOrderItemBackorder {
my ($self, $soi_id, $received) = @_;
my $count = $self->db->Scalar("SELECT `count` FROM `supplier_order_item` WHERE `id` = ?", $soi_id);
if ($received > $count) {
die "Received more than ordered";
}
my $new_soi_id;
if ($received < $count) {
# Start with one item, and copy that
$new_soi_id = $self->SupplierOrderItemCopy($soi_id);
# Adjust count on both the total should stay the same
$self->SupplierOrderItemUpdateCount($soi_id, $received);
$self->SupplierOrderItemUpdateCount($new_soi_id, $count - $received);
# I left the state of the old SOI as 'requested'
}
$self->SupplierOrderItemSetState($soi_id, 'received');
return $new_soi_id;
}
This code takes a supplier_order_item (SOI) and total received count and creates a new state where there are some items received and other stay in the state requested (backorder).
This code contains an algorithm, but because of the other code it’s not very obvious. Let’s look at the code. It seems the function expects three fields in a SOI: id, count and state.
The parameter $soi_id
is part of the start input state. And afterward there
are possibly two output states.
The input state is the following.
[ $soi_id, $count, 'requested' ]
Depending on the $received
parameter the output becomes the following.
[ $soi_id, $received, 'received' ]
[ $new_soi_id, $count - $received, 'requested' ]
With this information we can write a new function that creates these output states in memory from the input states. After which we can load the input state from the database and write the output state to the database.
In a way the MakeSupplierOrderItemBackorder
function is an instantiation of
the algorithm. By separating the algorithm from the database code, it becomes
easier to make changes to the algorithm.