Hacker News new | past | comments | ask | show | jobs | submit login
Basic Patterns for Everyday Programming (laktek.com)
85 points by laktek on Nov 23, 2011 | hide | past | favorite | 23 comments



Checking for null on every method invocation? I usually call methods for a reason and if my object is null, I have an error. If I have a situation where an object may be null, there will be specific handling for that case.

The other "patterns" are fishy too. How has this gotten so many points?


Checking for null on every method call certainly sounds nuts to me. Furthermore I would argue that doing so decreases consistence in your program. For example, in Objective-C I can count on nil being returned every time I call a method on a nil object. The opposite is true for other languages. The point is, it renders me able to make certain assumptions about how my code will behave, and thereby reduces the amount of code and tests I have to write.

Now if the language you're using behaves opposite of your wish, you're either using the wrong language or doing things the wrong way.


The author's response to a comment destroys the article's credibility by saying the difference between '==' and '===' is purely stylistic. I think somewhere down the line the author started to run before he could walk and that'll definitely come back to haunt him.


I have never claimed the choice between '==' and '===' is stylistic.


The tucking-away of current_date and current_day inside discount_day? is a mess. If either change between calls to discount_day?, suddenly discount_day? is returning the wrong value. That method returns different values given the same inputs; it's not a good candidate for being memoized.

(Furthermore, it's harder to test, as now current_date and current_day need to be stubbed out. It's also less obvious which day is being checked with regards to being discount day or not.)

I'd recommend having discount_day? taking a date as the argument, and having it invoked as discount_day?(current_date). (The day can then be calculated from the provided date.)


I'd be careful with the last Memoize example, if current_date changes then the JavaScript function at least will return the old value still.

Memoize only works if your function is one to one (one set of inputs gives the same outputs), and you cache the result of the function for each value of the input.


The last example also doesn't actually memoize if the result of the computation is false -- it will recompute on each call.


It will store a false in the JavaScript version, I'm not familiar with Ruby but I believe you are correct in that case.


Shouldn't that be solved with a closure in both languages?


I'm not sure there's anything there to be solved. If a "function" can return two different answers despite being provided with the exact same input parameters, you simply should not be attempting to memoize it.


One pattern that this guy misses is "better to be clear than to be clever". His "a == x || a == y..." example is a case of verbosity being a good thing, and probably the reason why most languages don't have a == (x or y or z) in their syntax. And then, if this isn't convoluted enough, he hides it behind an abstraction, which is another anti-pattern: Whatever you need to hide, you need to refactor. Hiding your cleverness away from the user is never a good idea. He even excuses it with "This refactoring allows others to read the code in context to the domain, without having to comprehend the internal logic." Sadly, this "Don't make me think" attitude is very common.


He proposes to replace

   if(current_day == "Monday" || current_day == "Wednesday" || current_day == "Friday") 
with

   if(["Monday", "Wednesday", "Friday"].include?(current_day))
I've done this before, and I don't think it's any less clear -- I wouldn't have thought of making a public announcement about it, though. I like it because it more closely aligns with the way you're probably thinking in this example: you're wondering if current_day is part of a certain set of days (the discount weekdays, apparently), not if it's equal to "Monday" or equal to "Tuesday", etc. I like the Javascript example with it's indexOf(..) >= 0 a lot less, but I guess people more used to JS idioms auto-translate this sequence to a set-contains operation.

It's more sensible if the set of values is larger than just three; and in this instance, you have to wonder why the day isn't available as a numeric variable, but I think you can let it slide for a contrived example.

It's even more useful if you reference the same set more than once, because you can just define it once, and as a constant if your language of choice does that kind of thing. This would also let you make your code less wordy (but arguably more literal) without hiding logic in functions, e.g. his later example would be

  if(discount_weekdays.include?(current_day) && current_date > 20)


So like Python's 'in'?

  if 5 in [1, 2, 5, 6, 8]:
      pass


"It's more sensible if the set of values is larger than just three ... It's even more useful if you reference the same set more than once"

Both are correct, I am strictly referring to his rationale being it's too verbose.


    case current_day when "Monday", "Wednesday", "Friday" then <do stuff> end


do_stuff() if $current_day ~~ @discount_weekdays;


I think his code choices are clear. The domain logic is "if it is a discount day then...". Keeping the calculation for what is and is not a discount day in the if statement muddles the logic because now you have the domain logic and logic for calculating whether or not today is a discount day in the same block of code. The discount day calculation is complex enough by the end (before memoization) that you'd likely end up adding a comment above the if statement to explain that you're calculating a discount day.

His choice to use [].include? is idiomatic ruby so I don't think it's being clever for clever's sake... although I've always kind of stumbled over that construct, I sort of wish there was an 'in' statement... if current_day in [x,y,z]. It would be easier to read (for me at least).


> current_day in [x, y, z]

Your pseudocode is idiomatic Python code :)


Yes, it did strike me how JS and Ruby are hard to read compared to Python's "if x in [a, b, c]".

Moreover, the memoise part is better handled with a decorator: it is a special behavior of the function and don't relate to its logic (its body).


Memoization is an optimization technique, I certainly don't use it every day. Be sure you verify you actually get a speedup (especially when using hash-tables for your cache) before you run off and prematurely optimize, as well as understand the trade-off of increased memory and less computation (if it's an actual speedup). As others have pointed out the example of memoizing in the blog is pretty bad. Storing the value in a variable seems like a better choice than in a procedure to me, if your program won't be running over a day.


Cool. Looks a lot like an excerpt of Smalltalk Best Practices[1] and a bit of Refactoring[2] book together.

[1] http://www.amazon.com/Smalltalk-Best-Practice-Patterns-Kent/...

[2] http://martinfowler.com/books.html#refactoring


If you want to use memoization for caching in C#, you can try out my library FuncCache: https://bitbucket.org/Yrlec/funccache/overview


I love the design on this blog.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: