4 ms·
> That means you shouldn’t have something like a reference to a product’s foreign key to dynamically grab the price when you render the receipt. This is vastly
by joshu 3y ago
> That means you shouldn’t have something like a reference to a product’s foreign key to dynamically grab the price when you render the receipt.
This is vastly underrated principle that is rarely understood and should be much broadly applicable. My data is separate from other people's data. In Carta, I have had my startup investments leave the system (die, acquired, etc) and I am left taking screenshots of everything because my records are just foreign keys into some other data store. If they had mailed me PDFs even paper or something, I would be fine.
- shortcake27 3y agoI feel like this is one of those cases where people take a mantra too seriously. Storing values that could otherwise be derived results in complexity and discrepancy. This may lead people to the conclusion that all values which can be derived should be derived, but in the case of a receipt/invoice, this is not the right call. Discretion must be applied.
- joshu 3y agoyour comment doesn't provide when to decide one way or the other, which makes it more warning and less useful. when the data is stuff that could be paperwork - you get a copy, i get a copy - it should not be the case that one side gets to unilaterally decide if the data is deleted or modified.
- shortcake27 3y agoI am in agreement with you. I’m just saying that developers need to apply discretion rather than following arbitrary “rules” or “patterns”. When to store or derive depends on the use case, of which are infinite.
- mrighele 3y agoI think it is not difficult to decide: sometimes you want to reference an entity with its current state, some other times you mean with the properties that it has at a specific point in time. For example if I don't pay yearly tax on my car I will receive a fine. The fine may arrive one or two year later, but it should be sent to me even if I sold the car meanwhile, because what matters is that I was the owner at the time. On the other side, the fine should be sent to my current address, not the one I had when I forgot to pay. There a number of ways to handle this. The simplest is to make a copy of the data, but you can also decide to keep all the historical data and reference the state during a certain time interval. Both can be valid choices, depending on the context, frequency of change, number of references....
- squeaky-clean 3y agoI think the biggest deciding factor in this particular situation is what the article says in the sub heading. 'A “Receipt” is immutable'. You don't care about the consistency guarantees of normalization. You don't care about being able to re-derive it with new logic or additional features. And in all likelihood the storage savings from not storing the final generated output is going to be miniscule. If some data is meant to be truly immutable, and storing it separately won't impact your storage costs, store it separately. Because otherwise that immutability needs to be somewhere else in the system. If you normalize your data and dynamically derive receipts, your logic needs to include all receipt logic you have ever used, cordoned by timerange. Was the price of a large Pizza changed in 2018? Your receipt logic and data has to reflect that forever. Did you allow stacking coupons but in March 2017 you started limiting it to 1 coupon per customer? Your receipt logic and data has to reflect that forever. Did you have a week where prices were rounding in the wrong direction when a certain coupon code was used? That has to be in your receipt handling forever. There's just so much additional effort, so much potential to go wrong, and so little to gain.
- hot_gril 3y agoThe general way I'd do this is to have the foreign key, but not to a "current prices" table, rather to an "all prices" table containing present and past prices. Which goes back to immutability. Maybe over-engineered for a small pizza shop that could get by fine with $ values copy-pasted everywhere, but we're talking about general principles. It's not like the customers' data is meant to be separate, like they're all paying the same price that we decided for the day, other than promotions which would be a separate table or misc adjustments that would just be a col directly on the sales table.
- andix 3y agoThere are a lot of things that can change, not only the price. The name of the product can change. What was "Medium crispy crusted pepperoni pizza" yesterday, may be called "Extra large pepperoni pizza" today. If you re-print the invoice, it should look the same as on the first print. Otherwise you may get some issues with the authorities (manipulating your copy of the invoices). There may also be a lot of related tables for finding the price (in the system I worked it was about 10 joins to get from the article to the price). It can be done in an immutable way, but it is possible that the way of calculating prices may change after an update. There may even have been a bug in the first place (like incorrect rounding, issuing rebates that shouldn't have been issued, incomplete sync of the prices table from the main server to the cash register, ...). Once you fix it all the previously issued invoices would show a different price. Which means you "lost" your copy of the invoice. Authorities don't like that. Credit card companies don't like it, if the customer disputes the charge and you show them an invoice with a different amount. Your bookkeeper doesn't like it, if a lot of payments don't match the invoices exactly, ... Edit: Example for rounding: Two people split a pizza for 19,99$. Version 1.0 creates two invoices with 10,00$ each. Version 2.0 creates one invoice with 9,99$ and a second one with 10,00$. Then the authorities pass a law that rounding prices must always floor them. So Version 3.0 creates two invoices for 9,99$.
- hot_gril 3y agoRight, other things can change, and you record those changes as immutable rows in a table too. You don't forget that the "super pizza" used to be called "uber pizza," so you can print the same exact receipt again, but you know they're the same product.
- runlaszlorun 3y agoThe receipt sounds like a place for an event driven approach, IMHO. It’s more like a journal entry in an accounting ledger.