Skip to content

Discussion Questions

benjaminoakes edited this page Feb 22, 2012 · 42 revisions

Discussion Questions

See also: Russ Olsen interview on Ruby Rogues (there were some questions about DPiR, from the beginning until about 6-7 minutes in, and perhaps later)

Preface

  • Regarding the C OOP analogy, Linus Torvalds is an OOP naysayer, but has made highly reliable (and maintainable?) code. What does this say about OOP? benjaminoakes
    • I think it means OOP is not the only way to do it. You can write poetry in French or English. danbernier
    • For the curious: Panel: Objects on Trial is supposed to be a funny but serious look at oop in general. Best point made for me is that you don't need O.O. based language to create an O.O. system. diego
  • Is it bad to use patterns as more than a vocabulary? Should they only be "rediscovered"? benjaminoakes
  • Is DRY an antipattern? Is it over-applied or often prematurely applied? benjaminoakes
  • Is YAGNI an antipattern? Is it over-applied or often prematurely applied? danbernier
  • Does Ruby hide too much complexity? Is there too much magic in, say, how mixins work? For example, the equivalent in JavaScript is as expressive, but less "magical". benjaminoakes
  • What's the equivalent in JavaScript? Something like a.extend(b)? or do you mean the prototype object model? danbernier
  • As an engineer, shouldn't you know how your plumbing works? benjaminoakes
  • Yes, but how far down? Do engineers need to understand quarks? danbernier
  • How does the problem domain affect the use of patterns? How about culture of an organization? benjaminoakes
  • I think the architecture affects it more than the problem domain. Web apps have similar patterns regardless of problem domain, and same goes for rich-client 3D simulations, rich-client GUI apps, web service layers, and language parsers. danbernier
  • How does your organization's culture view pattern use? Do they have a bad name (e.g. from being over-applied)? benjaminoakes

Chapter 1: Intro

Chapter 2: Overview of the Ruby language

This chapter is Ruby basics. If anyone has any clarifying questions, we'll be happy to clear things up.

  • Coming from statically typed languages like Java and C, I still don't fully understand how the ruby interpreter handles all @instance_variable's. How exactly does the interpreter pick up all of them? Zach
  • I'm not sure what part is unclear to you, but basically, the syntax (something like /\b@[a-z_]+\b/) makes them easy enough to recognize. The main difference is that Ruby lets you add new instance variables at run-time (see https://gist.github.com/1579738: first, f has no @bonk, then later, it does). Think of it like a hash, where the key is the instance variable's name, and you can add new keys. danbernier
  • To expand on @danbernier's explanation: are you familiar with how this is bound in JavaScript? How about this.variable = 'value'? The latter is essentially the same idea as @variable = 'value' in Ruby.

Chapter 3: Template Methods

From Wikipedia:

The control structure (inversion of control) that is the result of the application of a template pattern is often referred to as the Hollywood Principle: "Don't call us, we'll call you."

  • When have you found yourself using Template before? benjaminoakes
  • When have you wished you hadn't used Template before? benjaminoakes
  • One thing I find tricky about the Template Method pattern is picking methods to "punch out" of the template, in a way that makes sense. If you pick strictly the things that vary, it's an effective solution, but it might not be the clearest; and as the code ages & changes, you might need to refactor the lines of the template methods. Maybe this is an argument for keeping use of the template method small. I'll try to think up a good example. danbernier
  • Is Template limited in its usefulness? As @danbernier points out, it's more useful when there are fewer things that vary. The example of initialize in Ruby being a hook method is one example (only one method, but look at how much you can do with it). benjaminoakes
  • Is Ruby's Object a good example of when inheritance makes sense (in conjunction with the initialize hook)? If so, what does that mean for BasicObject? benjaminoakes

Chapter 4: Strategy

Pattern

  • When have you found yourself using Strategy before? benjaminoakes
  • When have you wished you hadn't used Strategy before? benjaminoakes
  • When is Template a better choice? benjaminoakes
  • How does your favorite library use Strategy well? Poorly?
  • Guidelines for teasing out a Strategy? Go just far enough to get you where you need to go?

Ruby Implementation

  • raise NotImplementedError vs raise "not implemented" benjaminoakes
  • When sharing data (context), what factors into your decision of how much context to share? There are two extremes: self vs an object tailor-made for this context. What are the pros and cons to each approach? benjaminoakes
  • Pros/cons of passing self?
  • How does your data-sharing mindset relate to how you use templating systems such as ERB? Or others such as Mustache? benjaminoakes
  • How would you switch at runtime based on input? Metaprogramming? A lookup table? if / case ?
  • Duck typing: are superclasses good as documentation? Good enough to keep around? What are alternatives (e.g. documentation style)?
  • How does passing a Proc limit your choices for future changes? Are they only good for when you need throwaway use cases? What could give the best of both worlds?
  • A crazy idea that I haven't tested: is this a better (more flexible/future-proof) alternative?
# Define method on foo
def foo.bar
  # ...
end

object.do_thing_with_bar_strategy(foo)

Chapter 5: Observer

Pattern

  • When have you found yourself using Observer before? benjaminoakes
  • When have you wished you hadn't used Observer before? benjaminoakes
    • Things mentioned in book:
      • Lots of updates
      • Checking for complete changes
      • Handling failures
  • How does your favorite library use Observer well? Poorly? benjaminoakes
  • How does using an observer change when multithreading? Observing over the network? benjaminoakes
  • Can using an observer (and not knowing who your observers are) be too much "magic"? That is, can it make it hard to debug/tell what your dependencies are? benjaminoakes
  • Guidelines for handling updates? benjaminoakes
  • Is there a difference between "subscribing" and "broadcasting" (newspaper vs radio)? (E.g. another pattern that does the latter better?) benjaminoakes
  • Who has used the "Publish-subscribe pattern" before? How does it relate to Observer? When would you use one over the other (advantages/disadvantages)? benjaminoakes
  • From Wikipedia:

The Observer pattern is criticized[5] for being too verbose, introducing too many bugs and violating software engineering principles, such as not promoting side-effects, encapsulation, composability, separation of concepts, scalability, uniformity, abstraction, resource management, semantic distance. The recommended approach is to gradually deprecate observers in favor of reactive programming abstractions.

Ruby Implementation

  • Java veterans: pain points of using the inheritance-based java.util.Observable? benjaminoakes
  • Ever found Ruby's Observable lacking? benjaminoakes
  • Why have ActiveRecord::Observer at all? Why not just use include Observable and register your observers? How does the answer change with and without a SQL backend in the picture? NoSQL? benjaminoakes
  • Related REXML/EventMachine discussion? benjaminoakes

Chapter 6: Composite

  • When have you found yourself using Composite before? benjaminoakes
  • When have you wished you hadn't used Composite before? benjaminoakes
  • How does this help me code better? seekayel
  • At what point does the Composite pattern stop? If I'm making an online forum where there are themes, topics, and posts, I could perhaps use the Composite pattern. But if I'm using a SQL database along with ActiveRecord is it still Composite? If it's just a bunch of loose relationships between tables? benjaminoakes
  • Preferring composition to inheritance: when is inheriting from Array a good idea? The only times I've seen it in the wild, I wish they had done composition. benjaminoakes
  • How flexible (able to cope with change) should your code be when determining leaves? benjaminoakes
  • When is a plain tree data structure a better idea? benjaminoakes

Chapter 7: Iterator

  • When have you found yourself using Iterator before? benjaminoakes
  • When have you wished you hadn't used Iterator before? benjaminoakes
  • Reading this chapter brought to mind Ruby 1.9's Enumerator class, "A class which allows both internal and external iteration", according to the page on ruby-doc.org. I've been unclear on exactly where one would need to use an Enumerator. I'm closer to understanding, thanks to this chapter, but I'm still curious: have any of you come across a case in which an Enumerator was the perfect object for the task? If so, what was it? cowmanifestation
  • Related to cowmanifestation's question: how does Russ Olsen's discussion change with regards to Ruby 1.9? We now have Enumerable and Enumerator:

Example:

ruby-1.9.2 > [].each
=> #<Enumerator: []:each> 
ruby-1.9.2 > [1, 2, 3].map
=> #<Enumerator: [1, 2, 3]:map> 
ruby-1.9.2 > [1, 2, 3].map.with_index { |e, i| i }
=> [0, 1, 2] 
  • Would it be simpler in a good way or bad way if [].map gave back a function rather than an Enumerator? (E.g. like in JavaScript's [].map) benjaminoakes
  • How about a parallel iterator? Like one that can take advantage of a GPU? benjaminoakes
    • (yonkeltron mentioned the closely related parallel gem)

Example:

[1, 2, 3].parallel.map { |i| i * 2 } # math done in parallel, rather than sequentially
  • Have you ever actually used each_reverse (or now reverse_each)? Why did you use it over reverse.each? benjaminoakes
  • Is there a good middle road between internal and external iterators?

For example, wrap functions:

def smallest(enumerable)
  def enumerable.each
    # logic to give back the smallest, e.g. using a heap
  end
  
  enumerable
end

# Resist changes made while iterating...
def protect(enumerable)
  enumerable.dup
end

a = [1, 2, 3]

# Now I can change how I iterate on the fly...
smallest(a).each { |i| ... }
protect(a).each { |i| ... }

class Foo
  def bar
    safe_and_sound = protect(@a)
    SomeLibrary.do_something_with_enumerable(safe_and_sound)
  end
end

Chapter 8: Command

  • When have you found yourself using Command before? benjaminoakes
  • When have you wished you hadn't used Command before? benjaminoakes
  • How does this help me code better? seekayel

benjaminoakes:

  • Is the composite command overkill? Seems like a simple script might be better.
  • Undoable: If this is a requirement the this pattern makes sense.
  • Undoing destructive commands: seems like this could be an error prone strategy if not done carefully.
  • How does PowerShell handle this? They have cmd-lets right?

Chapter 9: Adapter

  • When have you found yourself using Adapter before? benjaminoakes
  • When have you wished you hadn't used Adapter before? benjaminoakes
  • How does this help me code better? seekayel

benjaminoakes:

  • Monkey patching? Really?
  • Is duck typing a general case of Adapter in some ways?
  • Why not wrap like, say, jQuery? Is monkeypatching evil?
  • Is ActiveSupport a good or bad example of taking monkeypatching responsibility seroiusly?
  • Why doesn't ad-hoc modification get done more? If it's because of memory, what strategies are there to mitigate the problem?
  • How does testing factor into the decision of monkeypatching vs classic adapter?
  • How about using a Module and including or extending to keep things neat?
  • How would you go about testing the implementation of an adapter?