Good Design is Imperfect Design, Part 1: Honest Names
121–130 of 133 posts
Re: Good Design is Imperfect Design, Part 1: Honest Names
#122The problem is not in the `plus` method, as it's working as expected when the unit is in days. It's the `month` unit that is misleading, since `1 month` looks like a constant value but really isn't, as the behaviour depends on the other operand, breaking associativity – or any expectation on how addition between two constants work really. It would be less confusing if the API removed `month` as a period, and as a pro…
Re: Good Design is Imperfect Design, Part 1: Honest Names
#123The problem is not in the `plus` method, as it's working as expected when the unit is in days. It's the `month` unit that is misleading, since `1 month` looks like a constant value but really isn't, as the behaviour depends on the other operand, breaking associativity – or any expectation on how addition between two constants work really. It would be less confusing if the API removed `month` as a period, and as a pro…
Ever wondered why the variable-length month is second in the year, instead of a last? English names of months offer a hint: "September", "October", "November", "December" - sound similar to "hept-", "oct-", "non-", "dec-", i.e. 7th, 8th, 9th and 10th. So as it turns out, February used to come last, as reason would demand, but then the calendar got rotated right by two months.
If we imagine the calendar as it was, with February being the last, then at least the mapping between "day of year" and "month, day of that month" would be a function of just "day of year", instead of being a function of both "day of year" and "what year is it".
Re: Good Design is Imperfect Design, Part 1: Honest Names
#124To be clear it's still a tradeoff. But I think JodaTime did the right call by settling for the simpler name in this situation.
Re: Good Design is Imperfect Design, Part 1: Honest Names
#125Being honest with naming things is also a great roundabout way to ensure you write maintainable, readable code. If the name is honest and it feels awkward, it's a good red flag that there might be a problem with the approach you're taking. I think code golf languages (a-la [0]) are a good example of this approach as well, when your language is as terse as possible, giving very deep consideration to what the language…
I think I missed something here, does this article really suggest that plusExcuseExcuse() would be better? The domain is dates, we all know months have different numbers of days so _something_ must be done and this is explicit from the domain. Changing PI to PI_ISH because numbers in a language is limited does make code more readable. Almost everything in a computer is an imperfect model. i++ is not improved as incre…
Re: Good Design is Imperfect Design, Part 1: Honest Names
#126Earlier quoted context omitted.
The problem is that "What is one month after 2021-02-28?" doesn't have a single meaning in plain human language . It could mean 30 days in the future. Or the same day of the week 4 weeks in the future (i.e., 28 days in the future). Or the day of the same cardinality in next month. Or any date in the next month. And those are all equally correct. It's simply not a precise measure of time when spoken from one human to…
Plus/Increment/Add 1 month, does have one single meaning, it's that the outcome may be invalid that is the issue. "2021-01-31".plus(unit="Month", size=1) => "2021-02-31" But nobody really wants that, because it's not a valid date. So implicitly the library is deciding to return a valid date. A library could be written to just provide invalid dates, and let the end user handle any errors. That library could also inclu…
No, it doesn't.
You walk in to the doctor's office on February 28. At the desk, you see another patient about to leave. They turn to the desk attendant and say, "I'll see you in a month for my follow-up."
What date is the other patient's next appointment? What if the date you walked in had been January 31?
Also, for what it's worth, in C#:
DateTime x = new DateTime(2021, 1, 31);
x.AddMonths(1); // Feb 28
x.AddMonths(2); // March 31
x.AddMonths(1).AddMonths(1); // March 28Re: Good Design is Imperfect Design, Part 1: Honest Names
#127I think it's possible to be both honest and readable. One way to look at the issue is that the confusion stems from giving the same name to operators of different types , namely the "Instant plus Period" operator and the "Period plus Period" operator. Period could be implemented as a vector with independent components for days, months, and so on. (I don't know if that's how JodaTime does it, but that's what I would d…
Okay, I almost wish I hadn't read this comment because it is so similar to what I have in part 2! So please don't be annoyed when you see it in a couple of weeks ;-) I actually separated it into a separate part because it undermines my primary point. Sure, we all love it when we have a better decomposition, better names, and everything falls into place. But it doesn't always. Not in the time we have. So then we need…
Re: Good Design is Imperfect Design, Part 1: Honest Names
#128The problem is not in the `plus` method, as it's working as expected when the unit is in days. It's the `month` unit that is misleading, since `1 month` looks like a constant value but really isn't, as the behaviour depends on the other operand, breaking associativity – or any expectation on how addition between two constants work really. It would be less confusing if the API removed `month` as a period, and as a pro…
I don't like if `advanceMonths` returns an interval though, since this indicate that the interval is a meaningful unit separately from the initial date. It should return the new date, not an interval.
Re: Good Design is Imperfect Design, Part 1: Honest Names
#129Earlier quoted context omitted.
What is 2021-02-28 + 1 month? Is that 2021-03-28 or 2021-03-31? It is far from obvious what a normal human would do most of the time here. The lack of associativity is still a problem. If 2021-02-28 + 1 month = 2021-03-28,then (2021-02-28 + 1 month) + 1 month = 2021-03-28 + 1 month = 2021-04-28. While if I ask what is 2021-02-28 + 2 months (given 2021-02-28 + 1 month = 2021-03-31), most people would say 2021-04-30. W…
The problem is that "What is one month after 2021-02-28?" doesn't have a single meaning in plain human language . It could mean 30 days in the future. Or the same day of the week 4 weeks in the future (i.e., 28 days in the future). Or the day of the same cardinality in next month. Or any date in the next month. And those are all equally correct. It's simply not a precise measure of time when spoken from one human to…
Re: Good Design is Imperfect Design, Part 1: Honest Names
#130Earlier quoted context omitted.
Plus/Increment/Add 1 month, does have one single meaning, it's that the outcome may be invalid that is the issue. "2021-01-31".plus(unit="Month", size=1) => "2021-02-31" But nobody really wants that, because it's not a valid date. So implicitly the library is deciding to return a valid date. A library could be written to just provide invalid dates, and let the end user handle any errors. That library could also inclu…
> Plus/Increment/Add 1 month, does have one single meaning No, it doesn't. You walk in to the doctor's office on February 28. At the desk, you see another patient about to leave. They turn to the desk attendant and say, "I'll see you in a month for my follow-up." What date is the other patient's next appointment? What if the date you walked in had been January 31? Also, for what it's worth, in C#: DateTime x = new Da…
A month is a discrete unit of measure. It is not decomposable into any number of days.
When you increment a month, you get YYYY - (MM+1). Any higher significance is maintained, but irrelevant to the operation. (This applies to the hypothetical statement in the doctor's office, the specific day is indeterminant, but can be assumed the same as current day next month.)
The fact that not all possible days exist is orthogonal to the singular meaning of the operation. It's obviously not greatly valuable to an end-user, but the method of addressing the ambiguity involves a second operation that ensures validity.
End-users want an method that does both the addition and coercion, but you can create consistency if you follow the simple path I laid out in GP.
I'll use your syntax but with the strictly correct definition of the operation.
Datetime x = new DateTime(2021, 1, 31);
x.AddMonths(1); // DateTime(2021, 2, 31)
x.AddMonths(2); // DateTime(2021, 3, 31)
x.AddMonths(1).AddMonths(1); //DateTime(2021, 3, 31)
// Ensure Valid, using a coerce to clamp overflows
DateTime(2021, 2, 31).EnsureValid(); // Feb 28
DateTime(2021, 3, 31).EnsureValid(); // Mar 31
DateTime(2021, 4, 31).EnsureValid(); // Apr 30