Hacker News new | ask | show | jobs
by jpochtar 2949 days ago
I believe the code presented would have benefited from a lambda-based API approach instead of an object-oriented one. In Javascript:

  // global, since the cached values were apparently global in the original
  let cache = {};
  let lastCachedTime = 0;

  // Utility for fetching potentially cached values, or computing them 
  // if there's no valid cache entry.
  let cached = (id, recompute) => {
    // I don't love this policy, but thankfully it's all in one place.  
    if (lastCachedTime <= lastMidnight() || lastCachedTime <= lastNoon() {
      cache = {};
      lastCachedTime = Time.now();
    }
    if (!(id in cache)) {
      cache[id] = recompute();
    }
    return cache[id];
  };

  // now we get to have a nicely factored, simple, conceptually independent, 
  // declarative code for the dashboard.
  function displayDashboard() {
    print("Total Users: " + cached("numContent", => countUsers());
    print("Articles written: " + cached("numArticles", => countArticles());
    print("Words written: " + cached("numWords", => countWords());
  }
This achieves the same "Embedded Design" goal. If you squint, it's actually virtually the same as the DashboardStatComputation/DashboardStat/Dashboard the author comes up with, where each lambda in the displayDashboard function is corresponds to a DashboardStatComputation.

I prefer this lambda-based design because it reifies the "form" into a single, callable, function: cached(). If you want to use the idea of cached(), you don't have to subclass anything or know about its implementation details— just call it.

(PS. the code's even nicer in CoffeeScript)

3 comments

I agree. Using the class approach usually leads to complex class hierarchies and a lot of made up concepts for simple things which would be better solved if you could pass functions around easily (lambdas) and had generic data types (like javascript objects). But java does not have these easily available.

I think the OPs problems are mainly coming from the culture/design of Java.

Yes, 90% of abstraction is best done by organizing files and functions, NOT by creating classes.
Unfortunately these are largely the same thing if you're stuck with Java <= 8
This is similar to what I was thinking, but in python and remaining more object-oriented, its API would look something like this: (with essentially the same invalidation logic in the init)

   cache = GroupedCache(key="dashboard_stats")
   print("Total users: {}".format(cache.get(countUsers))
   print("Articles written: {}".format(cache.get(countArticles))
   print("Words written: {}".format(cache.get(countWords))
To me this would make it more apparent when reading the code that these should all be cached together (your functional one, with a different cache strategy, makes it look like it's acceptable for them to be cached for 1 hour, but offset from 30 minutes from each other due to external circumstances), and while pretty irrelevant for this particular example, would avoid the miniscule race condition if the clock ticks over midnight between Total Users and Articles Written.