destroy-all-software#tdding-spikes-away-with-rebase1 0038 tdding spikes away with rebase
watched. Skeptical that this is a good idea. He encourages us to try it out at the end, but mainly to learn more about TDD and version control, not because he thinks it's a good idea. His concern about the idea is that it would lead to your spiked design influencing your TDD design too much. destroy-all-software#tdding-spikes-away-with-rebase1
das-0036-what-goes-in-active-records
------------------------------------------------------------------------------ 0001 statistics over git repositories ------------------------------------------------------------------------------ 0002 how and why to avoid nil ------------------------------------------------------------------------------ 0003 building rspec from scratch ------------------------------------------------------------------------------ 0004 source code history integrity ------------------------------------------------------------------------------ 0005 extracting domain objects ------------------------------------------------------------------------------ 0006 conflicting principles ------------------------------------------------------------------------------ 0007 growing a test suite ------------------------------------------------------------------------------ 0008 processes and jobs ------------------------------------------------------------------------------ 0009 exceptions and control flow ------------------------------------------------------------------------------ 0010 fast tests with and without rails puts a seperate model in lib (outside of Rails) and uses rspec's stubs and expectations to test it In his script/test script He dds set -e to the top of the script to force it to blow up on errors. Interesting how he uses () to set the set +e on this sub-command, possibly to allow errors to happen without blowing the script up, but only from that scope. (set +e; grep -r 'spec_helper' $grep_filename) > /dev/null ------------------------------------------------------------------------------ 0011 git workflow ------------------------------------------------------------------------------ 0012 packaging in ruby and python ------------------------------------------------------------------------------ 0013 file navigation in vim ------------------------------------------------------------------------------ 0014 extracting objects in django ------------------------------------------------------------------------------ 0015 quick and easy perf tests ------------------------------------------------------------------------------ 0016 a refactoring story ------------------------------------------------------------------------------ 0017 wrapping third party apis ------------------------------------------------------------------------------ 0018 clarity via isolated tests ------------------------------------------------------------------------------ 0019 composing a unix command line find app lib -iname "*.rb" | xargs grep -h "^[[:space:]]*class\|module\b" \ | sed 's/^[[:space:]]*//' | cut -d " " -f 2 | while read class; \ do echo `grep -rl "\b$class\b" app lib --include="*.rb" | wc -l` $class; done \ | sort -n ------------------------------------------------------------------------------ 0020 tar fork and the tar pipe Use && most of the time because it will only cause the second thing to happen if the first part succeeds. Note, I mostly use ; in my unix commands, and should actively look at using && instead in cases where it makes sense. ------------------------------------------------------------------------------ 0021 coupling and abstraction in a model: default_scope where(:deleted => false) will cause ThatModel.all to not include objects where the "deleted" attribute is true Make a strong case for #test_driven_design by showing a the pain associated with testing a controller when you can't just stub out a single method. ------------------------------------------------------------------------------ 0022 test isolation and refactoring ------------------------------------------------------------------------------ 0023 spiking and continuous spiking "It depends how much design pressure I feel like I can put on the code, given the tests" Covers rationale of the #atdd_tdd_outer_inner_loop that's also in the rspec book ------------------------------------------------------------------------------ 0024 notes on stubbing extends an object with a module in the spec uses as_null_object talks about incidental interactions vs. essential interactions ------------------------------------------------------------------------------ 0025 controller refactoring demo part 1 He wants to get rid of #early_returns, but likes #guard_clauses, which he simply refers to as #guards ------------------------------------------------------------------------------ 0026 controller refactoring demo part 2 "Words like 'handle' and 'process' are really bad to use in method names." "What I'm afraid of are complexity and #opacity" ------------------------------------------------------------------------------ 0027 extracting from controller to model He called the things at the beginning of instance variables #spirals I see that he has some code that looks like this: flash.now[:error] = l(:notice_can_t_change_password) perhaps it's for internationalization ------------------------------------------------------------------------------ 0028 acceptance tests He recursively calls Cucumber steps ------------------------------------------------------------------------------ 0029 extracting from models extends an object with a module in the spec uses as_null_object talks about incidental interactions vs. essential interactions ------------------------------------------------------------------------------ 0030 some vim tips He calls the ampersand pretzel. I like that. Do (is faster than) scan (is faster than) read. That's his rationale for using something like command-T instead of NERDTree. ------------------------------------------------------------------------------ 0031 history spelunking with unix uses git bisect to automatically locate the commit that makes a change some of the interesting commands from this one (but not limited to) were: git rev-list --reverse master~250..master | awk 'NR % 50 == 0' to get a line of hashes like ############# jot -b '#' - 1 20 | xargs | tr -d ' ' ------------------------------------------------------------------------------ 0032 performance of different test sizes watched ------------------------------------------------------------------------------ 0033 simple bash script testing #bash_testing does a big thing that contains a cd in a subshell so it doesn't change the parent shell's directory. Good way of dealing with cd. ------------------------------------------------------------------------------ 0034 splitting into fine grained tests watched ------------------------------------------------------------------------------ 0035 which tests to write He talks a bit about how to provide justification for the tests you write, and how to avoid the dreaded #test_duplication that Sandi Metz worries about. ------------------------------------------------------------------------------ 0036 what goes in active records [das-0036-what-goes-in-active-records](das-0036-what-goes-in-active-records.html) ------------------------------------------------------------------------------ 0037 what goes in active records part 2 All things being equal, you want a #shallow_interaction_heirarchy ------------------------------------------------------------------------------ 0038 tdding spikes away with rebase watched. Skeptical that this is a good idea. He encourages us to try it out at the end, but mainly to learn more about TDD and version control, not because he thinks it's a good idea. His concern about the idea is that it would lead to your spiked design influencing your TDD design too much. ------------------------------------------------------------------------------ 0039 outside in tdd stubs vs stash I noticed that he has "before do" instead of "before :each do". Seems to work and it's less code, which is nice. ------------------------------------------------------------------------------ 0040 web apps when to test in isolation Among other things, he talks about the reasons for using #service_wrappers, a concept I first read about in #GOOS. Basically, by wrapping services, you end up with your own representation of the service, which you can mock or stub because you own it. This allows your #application_logic to be tested in isolation, even if it depends on the #service_wrappers. ------------------------------------------------------------------------------ 0041 untested code part 1 introduction Instead of checking "unless foo.nil?" he prefers "if foo.present?" He prefers the #happy_path comes first in the specs. He seems to prefer contexts to nested describe blocks. if you put in: if "blah" without the "do" block, it will be a pending test, which is nice from a documentation standpoint ------------------------------------------------------------------------------ 0042 untested code part 2 adding tests Likes to write integrated tests because isolated would lock in current interface, would be bad. example.com is defined by the standards as a testing domain, so it's the best one to use. lets are always #lazy_lets unless you specify let! user.books.should be_empty (I like that! Better than should == []) After writing a suite of tests, he does what heckle does, but he does it manually. He changes all conditionals to the opposite, and also forces them to both true and false to see that tests fail. He leaves a context in to force the degenerate path spec to run *after* the happy path spec. Order your examples from most general to most degenerate. ------------------------------------------------------------------------------ 0043 untested code part 3 refactoring 1 expect { user.add_book(book) }.not_to change { user.books.count } He uses a mock to communicate to the next developer the requirement that a particular method on the user model should be called. Otherwise, the next developer might just make a change and re-implement the functionality that's currently in the user model without thinking through all the cases that the method on the user model handles. ------------------------------------------------------------------------------ 0044 untested code part 4 refactoring 2 require "active_support/all" because it loads quickly and it doesn't really affect design, but rather just gives you nice convienience methods. He doesn't mind integrating with ActiveSupport. foo.should be_nil (instead of foo.should == nil) ------------------------------------------------------------------------------ 0045 emacs chainsaw of chainsaws watched ------------------------------------------------------------------------------ 0046 stubbing unloaded dependencies rspec's explicit subject syntax He tends to like to use dependency injection where there's an obvious coordinator, such as in a pipeline process where it moves things from one part of the process to the next. One way to create an unloaded dependency to ensure it can be stubbed is: class User; end He uses that technique mostly ------------------------------------------------------------------------------ 0047 brittle and fragile tests #test_fragility or #test_brittlenss is when a change in an unrelated class causes breakage in your test that shouldn't be concerned with the inner workings of that unrelated class. A complete lack of #failure_localization. Only mock your direct interface. #test_fragility is also (mis?)used to describe overly robust mocked tests where the tests continue to pass even though they shouldn't. He uses the term #seam to describe the interface between two classes. #out_of_sync_boundaries can happen when you create mocks, but the production code's interface changes and the mocks still have the old interface (and still pass) ------------------------------------------------------------------------------ 0048 repository statistics in raptor watched ------------------------------------------------------------------------------ 0049 generating coupons with bash sort -u (same as sort | uniq but shorter) the remove_confusing_characters function does: grep -v 1 | grep -v l | grep -v 0 | grep -v O he uses Python as a simple calculator. Assuming "count" is the a bash function returning the count of words, that he's going to create 1000 coupons, and that each coupon will have 3 words on it, he finds the probability that it's guessable. python -c "print 1000.0 / `count` ** 3" Also, I'd never heard of #expr. He does: index=`expr $RANDOM \% $(count) + 1` words | head -$index | tail -1 (note how he leaves off the -n) ------------------------------------------------------------------------------ 0050 shorter class syntax watched ------------------------------------------------------------------------------ 0051 sucks rocks 1 the rails app watched ------------------------------------------------------------------------------ 0052 sucks rocks 2 computing scores He uses a #sentinal_object or #sentinal_value instead of an actual value. Basically, he creates an object that exists only to mark the absense of a score. In this case, it's RockScore::NoScore Inside the RockScore class, he uses class RockScore NoScore = Class.new ... end He let his *very* duplicated tests remain non-DRY because he was pretty sure that the risk they posed to maintenence was pretty low. I find this questionable. Perhaps he thinks that the interface is solid or the code is simple. Dunno. ------------------------------------------------------------------------------ 0053 sucks rocks 3 the search engine He uses VCR.use_cassette("windows-vs-beos") around a block to capture the network traffic. I like his idea of having a separate vcr_helper.rb (instead of just shoving it into the spec_helper.rb) He shows how he can #hide_secret_data_in_environmental_variables, and how to set up VCR to ensure that the secret data remains hidden, even when persisting the cassette. He also uses VCR from within Cucumber, which is cool. Also, again, he inverts his tests to ensure failure and sees a bug. My biggest takeaway was him actually addressing a question I had about VCR, which is "what about when the results are unstable". To address that, he made sure that his tests compared two results from the Bing API rather than the actual values. So, that he saw "Microsoft Rocks" more than "Beos Rocks". ------------------------------------------------------------------------------ 0054 sucks rocks 4 caching #pass_through_cache should rewatch "0002 how and why to avoid nil" and "0009 exceptions and control flow" to see why he uses an exception. In this screencast, he does #using_exception_as_control_flow He closely follows Sandi Metz style of when to stub and when to mock.
das-0055-sucks-rocks-5-a-bug-and-a-model
------------------------------------------------------------------------------ 0056 sucks rocks 6 a controller He puts the translation of his domain concept of NoScore into nil down into the layer that actually touches the database. You can test whether a float is not a number by doing: float.nan? ------------------------------------------------------------------------------ 0057 sucks rocks 7 more cucumber mv public/dir/{hello,goodbye}.txt ------------------------------------------------------------------------------ 0058 sucks rocks 8 the whole design visit query_path(:term => "microsoft") score = ActiveSupport::JSON.decode(page.source).fetch("score") The #maybe_monad from a strong static language. Basically looks like a #null_object? Basically the thing from polymorphism instead of using a nil like Ben Orenstein and Joe Ferris talk about in Giant Robots. The Score and NoScore objects he creates are #value_objects He always wraps his 3rd party apis in his own classes. ------------------------------------------------------------------------------ 0059 when to generalize in tdd He rarely writes #multiple_assertions_in_one_test but he does in this episode. Generally starts his TDD with the happy path. * pending test will force you to generalize => use that * if sliming is harder than generalizing => generalize * if implementation is obvious AND easy => generalize, consider edge cases ------------------------------------------------------------------------------ 0060 the vimrc :help sometoken------------------------------------------------------------------------------ 0061 pushing complexity down when you expect a call to *not* happen, it is a #fragile_mock_expectation because you could have the method name wrong, for example he's said this before. He doesn't want conditionals in his activerecord classes, because he wants them to be very thin database wrappers #conditional_in_the_name_of_the_method is a big red flag because it tells you that you're missing an abstraction #do_filtering_up_front like the Danny/Gordon thingy. Still looking for a name for that concept (not just the upfront-ness, but also the seperateness) ------------------------------------------------------------------------------ 0062 three test shapes #non_destructive_state_based_test #local_destructive_state_based_test #global_destruction is a test that causes modification elsewhere (like when there's a mock expectation on another instance method which would cause destruction) He ordered them from most safe (from a destruction point of view to least safe) He talks about #implementation_obsession, in which you care about the internal details of an instance rather than relying on its external interface. He talks about the importance of the #shape_of_the_tests (which is closely related to the #shape_of_the_code) ------------------------------------------------------------------------------ 0063 pretty git logs in .gitconfig, there's an aliases section. You can have standard aliases, or, if you put a ! in front of the alias, it will run a shell to get the alias. In unix, "column" columnates lists he uses curly braces as seperators because they're uncommon in output column -t -s '{' quit if one screen in less less -F The format for just one of his attributes (he's got like 5) is: AUTHOR="%C(bold blue)%an%C(reset)" ------------------------------------------------------------------------------ 0064 mutation in tell dont ask watched ------------------------------------------------------------------------------ 0065 a magical isolation story This one was all about python and what he thinks is cool about it ------------------------------------------------------------------------------ 0066 ugly tests trigger refactoring He noticed #deep_stubbing in his tests for a particular feature, showing a design flaw. I guess this makes this screencast another example of #test_driven_design, in that the tests indicated that the code could be better written. Pay attention to the #shape_of_the_test. In this case, he said that big rectangles are a tell that too much is being stubbed. He thinks it's ok to allow a #value_object to be constructed in and interact with a test that's not about that value object, as long as it has no behavioural methods. ------------------------------------------------------------------------------ 0067 the mock obsession problem In a fully RESTful system you wouldn't do /foo/v1/ /foo/v2/ for versioning your API, but rather would rely on #media_types When talking about an overly-large setup function, he says: "I do like to share values sometimes, but I don't like the setup function doing things to the system and here I'm setting the version numbers" Uses the term #list_comprehension to refer to a map ------------------------------------------------------------------------------ 0068 test driving shell scripts He outlines an interesting way to initialize an empty git repo on every test run. It could also work well for any filesystem-based data repo that needs to be reset between tests (like pageoftext) He uses shunit. When you see "`some command`" it's because you want to results of some command to be returned as a single string value (not perhaps the multiple values that would otherwise be returned) chmod u+x (I should learn this stuff instead of octal... it would be easier) #bash_testing ------------------------------------------------------------------------------ 0069 conditional whac a mole #ad_hoc_polymophism is commonly associated with Java. Methods with the same name but different types in their signatures. Maybe also called #multi_method_dispatch. #subtype_polymorphism is the common Ruby type of polymorphism The extending syntax is easy. For example, you can extend with the PrivateUser module by simply doing: User.new("garybernhardt").extend(PrivateUser). I've done this many times before, but seeing it all in a one-liner made me appreciate it all over again. "#dynamic_object_extension is allowing the same complexity to exist, it's just hiding it from you." It's one of the reasons he's not very impressed with #DCI. He thinks it leads to massive type proliferation where the control is not as clear as if you wrote a single function, and all of that is because you're doing the dynamic object extension. DHH had a blog post where he talks about the Rails approach to DCI, #concerns. http://37signals.com/svn/posts/3372-put-chubby-models-on-a-diet-with-concerns Debate ensued. ------------------------------------------------------------------------------ 0070 time to first request he uses lsof to find the socket listening lsof -i :9292 (lists all the processes listening on 9292) ------------------------------------------------------------------------------ 0071 test isolation without mocks In this screencast he actually does some tested #view_model stuff, though he calls it #view_object. He says that, in his opinion, it's ok if a #value_object has some methods as long as they operate only on internal data, they take no arguments, don't do anything complex, and don't operate on any outside objects or classes. He called the thing that he's dependency injecting into the constructor for the class a #collaborator Talks about a #magical_constant, which basically sounds like another name for #magic_number He creates a TweetRenderer, which is a #class_that_ends_in_er (and has a method that ends in er, too). #tell_dan In functional programming, there's an idea that #intelligence_should_be_in_the_data_structures_rather_than_in_the_code ------------------------------------------------------------------------------ 0072 functional core imperative shell watched ------------------------------------------------------------------------------ 0073 collapsing services into values He ends up creating a class that inherits from struct, which is cool. ------------------------------------------------------------------------------ 0074 splitting active record models He uses a composed_of method in activerecord that allows him to easily map to other objects, but he only did that temporarily. ------------------------------------------------------------------------------ 0075 removing a rubinius feature He does an ack command, then uses it like so vim $(ack_command) to load the files into vim ------------------------------------------------------------------------------ 0076 python vs ruby objects watched ------------------------------------------------------------------------------ 0077 where correctness is enforced watched ------------------------------------------------------------------------------ 0078 separating arrangement and work After he has seperated arrangement, it's easy for him to use a #queue object to have email be sent in a background thread. He also goes on to discuss the #actor_model just a little bit, showing some pseudo code. ------------------------------------------------------------------------------ 0079 primitive obsession watched ------------------------------------------------------------------------------ 0080 isolating by separating value Seperates out a #value_object that he then uses when testing another class. It gets around the problem of deeply nested objects, but is only really good for data-heavy objects, not so great for behaviour-heavy ones. ------------------------------------------------------------------------------ 0081 imperative to oo to functional In his simple script, he does stuff in a "main" function. Tries for #pure_functions that are #referentially_transparent but puts them into an object because it pulls the methods into groups based on what they operate on. ------------------------------------------------------------------------------ 0082 debugging with tests watched it, but no notes ------------------------------------------------------------------------------ 0083 test cases vs examples #persistence in functional programming means the original persists and a copy is returned. He refers to variables that he uses in his code that he hasn't yet gotten around to declaring as #free_variables. ------------------------------------------------------------------------------ 0084 a bit of c If you run cpp on the source file, you will see output with the macros expanded. ------------------------------------------------------------------------------ 0085 analyzing context switches #load_average is the number of processes waiting for the cpu In "uptime", the load averages displayed are for the last 1, 5 and 15 minutes `which -a time` gives a different time binary than the one usually used in the shell. Try running: /usr/bin/time -l foo From playing around on my own, I realized that, as a non-root user, you can make your processes more nice, but not less nice. He called ^ "hat" He runs individual Cucumber scenarios, checking the voluntary context switches for each one. ------------------------------------------------------------------------------ 0086 actor syntax from scratch I had an idea. The working system is the first step, and the spike is the way to get there. I'm not sure if I buy into the idea that spikes have to be thrown away completely, but maybe there's something to that. He creates an #internal_dsl for actors ------------------------------------------------------------------------------ 0087 running tests asynchronously How cool is this?!? Using tmux, you can send input to another pane. In this case, he was in pane 0 of the "foo" session, which he created beforehand ``` tmux send-keys -t foo.1 "echo hello" C-m ``` #fifo is a #named_pipe You can create one with mkfifo test-commands if you then do an ls -l, you'll see a p at the beginning, which means it's a pipe echo "rspec --color foo_spec.rb" > test-commands (this is in one place) while true; do sh -c "$(cat test-commands)"; done (this is in another) ------------------------------------------------------------------------------ 0088 test recommendations Don't forget the {{{ to change {Order.count}.by(1) syntax from earlier. Name all your stubs proactively, since it will aide immensly in debugging #only_stub_things_that_you_trust ... things you trust not to change in breaking ways. This feels very similar to what Sandi Metz said about relying on other classes. I'll have to re-read that section of her book. Also, he uses the example of #service_wrappers to highlight why you would wrap the service (because your interface is less likely to change than Braintree's, and yours provides a more idealized interface) He says that he prefers #testing_behavior_rather_than_implementation, but that he hasn't been able to find a way to show it in a screencast well. Hmm. Wonder what that would look like, and what he's talking about. ------------------------------------------------------------------------------ 0089 when rails is right application controller is a #junk_drawer, but sometimes it's the right place to put stuff. ------------------------------------------------------------------------------ 0090 a day in the life He doesn't like to alter unix commands that are already there, but he does like to add new abstractions. I really like the idea of very short videos for an actual presentation. ------------------------------------------------------------------------------ His "boundaries" talk #contract_tests and #collaboration_tests are like what Sandi Metz suggests, but they're more tests.