5 ms·
The example is hilariously terrible. Firstly, this is the currently required code: def set_deadline(deadline): if deadline <= datetime.now():
by epr 2y ago
The example is hilariously terrible. Firstly, this is the currently required code:
def set_deadline(deadline):
if deadline <= datetime.now():
raise ValueError("Date must be in the future")
set_deadline(datetime(2024, 3, 12))
set_deadline(datetime(2024, 3, 18))
There simply is no trade-off to be made at this point. Perhaps there will be eventually, but right now, there is one function needed in two places. Turning two functions that already could be one into a class is absurd.
Now, as far as teaching best practices goes, I also dislike this post because it doesn't explicitly explain the pros and cons of refactoring vs not refactoring in any detail. There is no guidance whatsoever (ie: Martin Fowler's Rule of Three). This is Google we're talking about, and newer developers could easily be led astray by nonsense like this. Addressing the two extremes, and getting into how solving this problem requires some nuance and practical experience is much more productive.
- LorenPechtel 2y agoMy thought here is that they're focusing on the wrong thing. Yes, we have repetitive date-checking logic, but we don't want lay a trap for the future. Not sure what language this is in so I'll use C#: EnsureDateInFuture(DateTime Time) { if (Time <= DateTime.Now()) throw new Exception("Date must be in the future"); } One check for the future, one copy of the error message, not locked in.
- alex_smart 2y agoAlmost all programming tutorials and even books to a certain extent suffer with the problem of terrible examples. Properly motivating most design patterns requires context of a sufficiently complex codebase that tutorials and books simply do not have the space of getting into. This particular case is especially bad, probably because they had the goal of having the whole article fit in one page. ("You can download a printer-friendly version to display in your office.") > There is no guidance whatsoever (ie: Martin Fowler's Rule of Three). That is completely unfair imo. Although not properly motivated, the advice is all there. "When designing abstractions, do not prematurely couple behaviors that may evolve separately in the longer term." "When in doubt, keep behaviors separate until enough common patterns emerge over time that justify the coupling." Simplified maxims like "Rule of Three" do more harm than good. Don't couple unrelated concerns is a much higher programming virtue than DRY.
- LouisSayers 2y ago> Properly motivating most design patterns requires context of a sufficiently complex codebase As someone that's made a best selling technical course, I strongly disagree. It's 100% laziness and/or disregard for the reader. The reason examples are as bad as they are is that people rush to get something published rather than put themselves in the audience's position and make sure it's concise and makes sense. It's not like webpage space is expensive. There's plenty of room to walk through a good example, it just requires a little effort.
- Bjartr 2y agoWhat does sales have to do with what you're claiming? Please share the course and or examples of it being done well without requiring that excessive context, so that there's something to support your claim.
- LouisSayers 2y agoWell if my course and teaching was crap I wouldn't get good reviews and therefore many sales. I've spent $0 on marketing. https://www.udemy.com/neo4j-foundations/ https://www.udemy.com/neo4j-foundations/ There are many people who do teach and explain topics well. Richard Feynman comes to mind. I've found Abdul Bari on YouTube to also be an excellent teacher around technical topics.
- Aeolun 2y agoNot related to the topic at hand, but who buys these courses? Going off the chapter titles it looks like it’s all basic ‘read the documentation’ kind of stuff (to me). I could imagine it being useful to beginners, but not anyone with a moderate amount of experience (they’d just go to the Neo4j documentation). On the other hand, what beginner starts with Neo4j and Cypher? Is there really enough of them to justify a whole course? Apparently there are, it just feels weird to me.
- 2y ago
- re-framer 2y agoYour example, deduplicating the two functions into one, illustrates an interesting point, although I'd prefer still having the two specialized functions there: def set_deadline(deadline): if deadline <= datetime.now(): raise ValueError("Date must be in the future") def set_task_deadline(task_deadline): set_deadline(task_deadline) def set_payment_deadline(payment_deadline): set_deadline(payment_deadline) set_task_deadline(datetime(2024, 3, 12)) set_payment_deadline(datetime(2024, 3, 18)) You lose absolutely nothing. If you later want to handle the two cases differently, most IDEs allow you to inline the set_deadline method in a single key stroke. So the argument from the article... > Applying DRY principles too rigidly leads to premature abstractions that make future changes more complex than necessary. ...does not apply to this example. There clearly are kinds of DRY code that are less easy to reverse. Maybe we should strive for DRY code that can be easily transformed into WET (Write Everything Twice) code. (Although I haven't worked with LISPs, macros seem to provide a means of abstraction that can be easily undone without risk: just macro-expand them) In my experience, it can be much harder to transform WET code into DRY code because you need to resolve all those little inconsistencies between once-perfect copies.
- epr 2y agoI can only assume the Google example would be part of a script/cli program that is meant to crash with an error on a bad parameter or similar. Perhaps the point is to catch the exception for control flow? My personal goal is to get things done in as few lines of code as possible, without cramming a bunch on one line. Instead of coming up with fancy names for things, I try to call it by the simplest name to describe what it's currently doing, which can be difficult and is subjective. If we wanted to define a function which crashes like the example, I would probably write this: def throw_past_datetime(dt): if dt <= datetime.now(): raise ValueError("Date must be in the future") If the point is not to crash/throw for control flow reasons, I'd write this in non-cli/script code instead of defining a function: dt = datetime(2024, 5, 29) if dt < datetine.now(): # Handle past date gracefully? If it needs to do more in the future, I can change it then.
- alex_smart 2y ago>You lose absolutely nothing. If you later want to handle the two cases differently, most IDEs allow you to inline the set_deadline method in a single key stroke. Problem with unintentional coupling isn't that you can't undo it. It is that someday someone from some other team is going to change the method to add behaviour they need for their own use case that is different from your own and you won't even notice until there is a regression.
- Aeolun 2y agoI was going to say you were talking nonsense, but then realized I’d replaced the original post in my mind, by this much nicer post that someone else linked in this thread: https://verraes.net/2014/08/dry-is-about-knowledge/ https://verraes.net/2014/08/dry-is-about-knowledge/ They essentially say the same thing, but one is better than the other.