Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

more WIP

  • Loading branch information...
commit 4f37099ed1ace73a90dacaf321c1ca6a05555ebd 1 parent 51c91eb
@raganwald raganwald authored
View
115 2012/08/decisioons_decisions.md
@@ -100,22 +100,30 @@ We developers are personas and have user stories. Although it has little to do w
Simple, easy to test. Can you do one thing (e.g. `cap deploy`) and push the latest changes to staging or production?
-We have other, more subjective requirements we can express as stories. For example, the great mantra of "bondage and discipline" coding environments is that a large team of moderately inexperienced developers with a relatively low level of communication can sustain a consistent velocity of development. Whether you agree that languages like Java and tools like XML make this possible or not, this is a user story with well-understood persona.
+We programmers don't usually talk about program designs in terms of "user stories," but we think about them. The jargon I usually hear from programmers is "Optimizing for \_\_\_\_\_\_\_." For example, we might say that we believe that polymorphism optimizes for creating or changing objects and their implementations. Or we might say that we believe that inheritance optimizes for easy sharing of implementations.
-When we say that method decorators and YouAreDaChef both solve the same problem, another way to say it is that they appear in the same user story. That story is one where a developer wishes to separate some cross-cutting functionality (like authorization, logging, displaying feedback, &c.) from some core functionality.
-
-If we stop right there, method decorators are the clear winners. They're simple and require only that you wrap your head around functions returning functions. But we needn't stop right there. Why is the developer separating these concerns with decorators instead of inline? What other developer user stories are involved?
+A more colloquial thing to say is that a particular design choice "makes something easy." For example, many people believe that good automated test coverage makes refactoring easy. So, what does YouAreDaChef make easy? And what does that tell us about designing programs?
What does YouAreDaChef make easy?
---------------------------------
-Let's look more closely at YouAreDaChef and see if we can glean some of the other user stories by looking at what it "makes easy." ([1](#Notes))
+Let's look more closely at YouAreDaChef and see if we can glean some insights by looking at what it "makes easy." ([1](#Notes))
![Dos Equis Guy Endorses YouAreDaChef](http://i.minus.com/i3niTDYu2cbR1.jpg)
The first and most obvious thing that YouAreDaChef makes easy is using *three* pieces of code to separate some advice from some methods. the advice is one chunk. The methods are another, and YouAreDaChef's bindings are a third. With method decorators, you only need two, the decorators and the method declarations that separate the invocation of the decorators from the method bodies, but are still in the same big chunk of code.
-The both have three chunks of code, but YouAreDaChef completely breaks them apart, while method decorators have them separate but adjacent:
+The both have three chunks of code, but YouAreDaChef completely breaks them apart:
+
+```coffeescript
+YouAreDaChef
+ .clazz(SomeExampleModel)
+ .method('setHeavyweightProperty')
+ .after triggers('cache:dirty')
+
+```
+
+While method decorators have them separate but adjacent within the class definition:
```coffeescript
class SomeExampleModel
@@ -126,50 +134,77 @@ class SomeExampleModel
# set some property in a complicated way
```
-[YouAreDaChef] is a meta-programming framework. It modifies an existing class or hierarchy of classes to add *method advice*. In the very simplest cases, method advice resembles decoration. You can provide "advice" in the form of a function that is executed `before`, `after`, or `around` a method. You can also `guard` a method with a predicate. You can do all of these things with method decorators, of course.
+Having the binding in a third chunk of code does make a few things easy. What happens if you omit the third chunk of code? If you are careful to make the YouAreDaChef bindings the only dependency between the advice and the method bodies, you have decoupled the advice from the methods.
+
+What does this make easy? Well, for one thing, it makes testing easy. You don't need your tests to elaborately mock up a lot of authorization code to appease the authorization advice, you simply don't bind it when you're unit testing the base functionality, and you bind it when you're integration testing the whole thing.
+
+YouAreDaChef's decoupling makes writing tests easy.
-First, method decorators do something very simple: They modify the behaviour of one method body. Nothing else is changed. Second, method decorators are almost always used in the declaration of a method. Finally, method decorators make use of functions calling other functions, so at runtime the structure of a decorated method can only be deduced by tracing its execution. There is no runtime-introspection capability that might be used for debugging or advanced meta-programming purposes.
+What else does YouAreDaChef make easy?
+--------------------------------------
+
+YouAreDaChef does allow you to break things into three pieces, but you can also put them in two pieces, but in a different way. Consider the difference between:
+
+```coffeescript
-YouAreDaChef differs from method decorators on all three counts:
+# Method Decorators I
-1. YouAreDaChef decouples advice from class declarations.
-2. YouAreDaChef understands inheritance.
-3. YouAreDaChef can be introspected at run time.
+triggers = (eventStrings...) ->
+ after ->
+ for eventString in eventStrings
+ @trigger(eventString)
+
+# Method decorators II
-YouAreDaChef decouples advice from class declarations
----
+class SomeExampleModel
-With method decorators, you decorate the method right in the class "declaration." That is nice when you're reading a method and want to know everything it does. There's no spooky "action at a distance."
+ setHeavyweightProperty:
+ triggers('cache:dirty') \
+ (property, value) ->
+ # set some property in a complicated way
+
+ recalculate:
+ triggers('cache:dirty') \
+ ->
+ # Do something that takes a long time
+```
-However, it tightly couples classes to cross-cutting concerns. For example:
+And:
```coffeescript
-class WidgetViewInSomeFramework extends BuiltInFrameWorkView
-
- # ...
-
- switchToEditMode:
- withPermissionTo('write', WidgetModel) \
- debugEntryAndExit('switchToEditMode') \
- (evt) ->
- # actual
- # code
- # switching to
- # edit
- # mode
-
- switchToReadMode:
- withPermissionTo('read', WidgetModel) \
- debugEntryAndExit('switchToReadMode') \
- (evt) ->
- # actual
- # code
- # switching to
- # view-only
- # mode
+
+# YouAreDaChef I
+
+triggers = (eventStrings...) ->
+ for eventString in eventStrings
+ @trigger(eventString)
+
+YouAreDaChef
+ .clazz(SomeExampleModel)
+ .method('setHeavyweightProperty', 'recalculate')
+ .after triggers('cache:dirty')
+
+# YouAreDaChef II
+
+class SomeExampleModel
+
+ setHeavyweightProperty: (property, value) ->
+ # set some property in a complicated way
+
+ recalculate: ->
+ # Do something that takes a long time
```
-Why should a view know anything about permissions? Permissions and authoriz
+The first one is organized such that the class being 'decorated' knows what does the decorating. So the decorated class depends on the decoration. The second one is organized such that the method advice knows what it advises. So the advice depends on the class being advised.
+
+The first one, written with method decorators, makes it easy to look at a class--like `SomeExampleModel`--and know everything about that model's behaviour. The second one, written with YouAreDaChef, makes it easy to look at a particular concern--like managing a cache--and know everything about the concern's behaviour. They both make it easy to look at a model class and understand its primary responsibility, uncluttered by other concerns.
+
+The YouAreDaChef approach is thus superior when you want to make working with cross-cutting concerns easy. [Recursive Universe] demonstrates this approach with the knobs turned up to eleven: Concerns like caching and garbage collection are entirely separated from core classes, and you can learn how the code works a piece at a time.
+
+[Recursive Universe]: http://recursiveuniver.se
+
+
+
Notes
-----
View
98 2012/08/youaredachef.md
@@ -1,98 +0,0 @@
-*This essay is a work in progress. Feel free to comment, tweet, &c. but it is definately not ready or Hacker News, Reddit, and so forth. Thanks!*
-
-Three Reasons to use YouAreDaChef
-===
-
-In [Method Combinators in CoffeeScript][mcc], I described method decorators, an elegant way of separating concerns in CoffeeScript and JavaScript methods, for example:
-
-```coffeescript
-triggers = (eventStrings...) ->
- after ->
- for eventString in eventStrings
- @trigger(eventString)
-
-displaysWait = do ->
- waitLevel = 0
- around (yield) ->
- someDOMElement.show() if (waitLevel += 1) > 0
- yield()
- someDOMElement.hide() if (waitLevel -= 1) <= 0
-```
-
-And then we use the new decorators:
-
-```coffeescript
-class SomeExampleModel
-
- setHeavyweightProperty:
- triggers('cache:dirty') \
- (property, value) ->
- # set some property in a complicated way
-
- recalculate:
- displaysWait \
- triggers('cache:dirty') \
- ->
- # Do something that takes a long time
-```
-
-I also wrote, more-or-less:
-
-[mcc]: https://github.com/raganwald/homoiconic/blob/master/2012/08/method-decorators-and-combinators-in-coffeescript.md#method-combinators-in-coffeescript
-
-> Without method decorators, you end up "tangling" every method with a lot of heterogenous cross-cutting concerns. Faced with this problem and some Ruby experience, an intelligent but not particularly wise developer might rush off and write something like [YouAreDaChef], an Aspect-Oriented Framework for JavaScript. YouAreDaChef provides a mechanism for adding "advice" to each method, separating our base behaviour from the cross-cutting concerns.
-
-> In CoffeeScript, we rarely need all of YouAreDaChef's Architecture Astronautics.
-
-[YouAreDaChef]: https://github.com/raganwald/YouAreDaChef "YouAreDaChef, AOP for JavaScript and CoffeeScript"
-
-Of course, "rarely" does not mean "never." Method decorators look great and are easy to write. The obvious question is, "What is YouAreDaChef, what does it do that method decorators can't do, and when would you prefer YouAreDaChef to method decorators?"
-
-I'm glad you asked.
-
-![Dos Equis Guy Endorses YouAreDaChef](http://i.minus.com/i3niTDYu2cbR1.jpg)
-
-[YouAreDaChef] is a meta-programming framework. It modifies an existing class or hierarchy of classes to add *method advice*. In the very simplest cases, method advice resembles decoration. You can provide "advice" in the form of a function that is executed `before`, `after`, or `around` a method. You can also `guard` a method with a predicate. You can do all of these things with method decorators, of course.
-
-First, method decorators do something very simple: They modify the behaviour of one method body. Nothing else is changed. Second, method decorators are almost always used in the declaration of a method. Finally, method decorators make use of functions calling other functions, so at runtime the structure of a decorated method can only be deduced by tracing its execution. There is no runtime-introspection capability that might be used for debugging or advanced meta-programming purposes.
-
-YouAreDaChef differs from method decorators on all three counts:
-
-1. YouAreDaChef decouples advice from class declarations.
-2. YouAreDaChef understands inheritance.
-3. YouAreDaChef can be introspected at run time.
-
-YouAreDaChef decouples advice from class declarations
----
-
-With method decorators, you decorate the method right in the class "declaration." That is nice when you're reading a method and want to know everything it does. There's no spooky "action at a distance."
-
-However, it tightly couples classes to cross-cutting concerns. For example:
-
-```coffeescript
-class WidgetViewInSomeFramework extends BuiltInFrameWorkView
-
- # ...
-
- switchToEditMode:
- withPermissionTo('write', WidgetModel) \
- debugEntryAndExit('switchToEditMode') \
- (evt) ->
- # actual
- # code
- # switching to
- # edit
- # mode
-
- switchToReadMode:
- withPermissionTo('read', WidgetModel) \
- debugEntryAndExit('switchToReadMode') \
- (evt) ->
- # actual
- # code
- # switching to
- # view-only
- # mode
-```
-
-Why should a view know anything about permissions? Permissions and authorization should be decoupled from correctly rendering or updating a view. After all, if it's a seperate
View
32 dumping_ground/admiral-akbar-on-requirements.md
@@ -0,0 +1,32 @@
+Admiral Akbar on Requirements
+===
+
+(picture of the big fish)
+(caption; "It's a trap!")
+
+Market risks
+---
+
+* "The only product with \_\_\_\_\_" vs. "Like other quality products, it includes \_\_\_\_\_."
+
+Technical risks
+---
+
+* Cross-cutting concern
+ * Undo/redo
+ * Version control
+ * Comments and discussion
+ * Voting
+ * Collaborative filtering
+ * Collaborative editing
+ * Authorization
+
+* Home-grown framework
+ * Supplanted by open framework
+ * Just like choosing the "wrong" framework, except it's nearly alway sthe wrong framework
+
+* Design pattern
+ * Everyone has to use the pattern
+
+* Unobtrusive pattern
+ * everyone has to understand how the magic works
View
93 homoiconic.tmproj
@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>currentDocument</key>
- <string>2012/08/coffeescript_for_ruby_developers.md</string>
+ <string>2012/08/decisioons_decisions.md</string>
<key>documents</key>
<array>
<dict>
@@ -13,8 +13,6 @@
<string>homoiconic</string>
<key>regexFolderFilter</key>
<string>!.*/(\.[^/]*|tmp|log|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
- <key>selected</key>
- <true/>
<key>sourceDirectory</key>
<string></string>
</dict>
@@ -51,36 +49,6 @@
<key>firstVisibleLine</key>
<integer>0</integer>
</dict>
- <key>2008-11-07/from_birds_that_compose_to_method_advice.markdown</key>
- <dict>
- <key>caret</key>
- <dict>
- <key>column</key>
- <integer>0</integer>
- <key>line</key>
- <integer>0</integer>
- </dict>
- <key>columnSelection</key>
- <false/>
- <key>firstVisibleColumn</key>
- <integer>0</integer>
- <key>firstVisibleLine</key>
- <integer>0</integer>
- <key>selectFrom</key>
- <dict>
- <key>column</key>
- <integer>0</integer>
- <key>line</key>
- <integer>0</integer>
- </dict>
- <key>selectTo</key>
- <dict>
- <key>column</key>
- <integer>85</integer>
- <key>line</key>
- <integer>259</integer>
- </dict>
- </dict>
<key>2009-09-22/anaphora.md</key>
<dict>
<key>caret</key>
@@ -165,63 +133,19 @@
<key>firstVisibleLine</key>
<integer>31</integer>
</dict>
- <key>2012/05/read_only_code.md</key>
+ <key>2012/08/decisioons_decisions.md</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
- <integer>85</integer>
- <key>line</key>
- <integer>156</integer>
- </dict>
- <key>columnSelection</key>
- <false/>
- <key>firstVisibleColumn</key>
- <integer>193</integer>
- <key>firstVisibleLine</key>
- <integer>112</integer>
- <key>selectFrom</key>
- <dict>
- <key>column</key>
- <integer>159</integer>
- <key>line</key>
- <integer>143</integer>
- </dict>
- <key>selectTo</key>
- <dict>
- <key>column</key>
- <integer>85</integer>
- <key>line</key>
- <integer>156</integer>
- </dict>
- </dict>
- <key>2012/08/coffeescript_for_ruby_developers.md</key>
- <dict>
- <key>caret</key>
- <dict>
- <key>column</key>
- <integer>217</integer>
- <key>line</key>
- <integer>0</integer>
- </dict>
- <key>firstVisibleColumn</key>
- <integer>0</integer>
- <key>firstVisibleLine</key>
- <integer>0</integer>
- </dict>
- <key>2012/08/method-decorators-and-combinators-in-coffeescript.md</key>
- <dict>
- <key>caret</key>
- <dict>
- <key>column</key>
- <integer>87</integer>
+ <integer>15</integer>
<key>line</key>
- <integer>264</integer>
+ <integer>180</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
- <integer>220</integer>
+ <integer>146</integer>
</dict>
<key>dumping_ground/coffeescript_and_underscore.md</key>
<dict>
@@ -254,14 +178,11 @@
</dict>
<key>openDocuments</key>
<array>
- <string>2008-11-07/from_birds_that_compose_to_method_advice.markdown</string>
- <string>2012/08/method-decorators-and-combinators-in-coffeescript.md</string>
- <string>2012/08/coffeescript_for_ruby_developers.md</string>
- <string>2012/05/read_only_code.md</string>
+ <string>2012/08/decisioons_decisions.md</string>
</array>
<key>showFileHierarchyDrawer</key>
<true/>
<key>windowFrame</key>
- <string>{{898, 0}, {1148, 1406}}</string>
+ <string>{{462, 1}, {1148, 1406}}</string>
</dict>
</plist>
View
1  ten_millionth.txt
1 addition, 0 deletions not shown
Please sign in to comment.
Something went wrong with that request. Please try again.