Matthijs Langenberg
2007-Sep-29 21:43 UTC
[rspec-users] How to write the very first example?
Many posts on this list are about using RSpec with Rails and that''s the way I''m also using RSpec all the time. Unfortunately there isn''t that much info about using RSpec for standalone Ruby projects. I must admit I''m really having a hard time writing the very first example(s) for a fresh standalone Ruby project. I haven''t really got a clue where to start, how to call the first example and how to describe it. I want to use the outside-in approach, but that suggests the first example you write should specify the workings of the whole project, right? I alway catch myself focusing on dependancies and start from the inside instead of the outside. (if I implement this first, I can use it as a building brick for that feature, and if that feature is implemented I can work on that other feature.) So, where do I actually need to start? -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/rspec-users/attachments/20070929/05d13a88/attachment-0001.html
On 9/29/07, Matthijs Langenberg <mlangenberg at gmail.com> wrote:> Many posts on this list are about using RSpec with Rails and that''s the way > I''m also using RSpec all the time. > Unfortunately there isn''t that much info about using RSpec for standalone > Ruby projects.I don''t think that matters much, the principles are the same. You write stories for features, and write specs to drive object implementation. In fact I would say that Rails presents some unique challenges for BDDing, and that a "pure" ruby project is easier!> I must admit I''m really having a hard time writing the very first example(s) > for a fresh standalone Ruby project. I haven''t really got a clue where to > start, how to call the first example and how to describe it.Begin at the beginning :P There are a couple approaches. First thing I would do is write a story for one feature you want in the system. Having that story means that you stay focused on one particular task and building the infrastructure that will be used. I actually wrote a blog post a while back on what I call "design deep, not wide" [1] On a simpler level, stories represent real progress. When you''re done with a story you should have actual value, and that is fulfilling and motivating. Also, you can start with smaller stories and build out from there. In Dan North''s article about introducing rbehave [2] he works with simple objects instead of a full application stack like you might in Rails. When I first read it, I thought a standard spec might be more appropriate. Once it hit me though (which was a couple months later), I fell in love with that approach. To give you an idea, here''s the starting code: Story "transfer to cash account", %(As a savings account holder I want to transfer money from my savings account So that I can get cash easily from an ATM) do Scenario "savings account is in credit" do Given "my savings account balance is", 100 Given "my cash account balance is", 10 When "I transfer", 20 Then "my savings account balance should be", 80 Then "my cash account balance should be", 30 end Scenario "savings account is overdrawn" do Given "my savings account balance is", -20 Given "my cash account balance is", 10 When "I transfer", 20 Then "my savings account balance should be", -20 Then "my cash account balance should be", 10 end end Eventually he sticks objects in there as he implements them, but at least at the very beginning there''s no code to speak of. It''s just a user story. The beauty of it is that all you''re doing is specifying acceptance criteria - what it means to be "done." One scary part of doing lower level specs is on some level you''re designing code without any real sense of direction. You might not necessarily know what objects you need. While specs are excellent for discovering the behavior of objects, as far as what operations they perform and interactions they have, they don''t do much to help with the desired behavior of the system. So, basically, writing stories forces you to think about what you want to achieve, and gives you a clear way to measure progress. You know where you want to end, and you know all the steps it takes to get there, and that gives you the knowledge of where to start.> I want to use the outside-in approach, but that suggests the first example > you write should specify the workings of the whole project, right? > I alway catch myself focusing on dependancies and start from the inside > instead of the outside. (if I implement this first, I can use it as a > building brick for that feature, and if that feature is implemented I can > work on that other feature.)This is where mock objects yield their greatest benefits. A lot of people think mock objects are good only for isolating expensive resources, but they''re fantastic in allowing you to design well in chunks. For example, something as simple as: customer.place_order some_item, 12 Will require that I have a customer class, a place_order method, an item class, and probably an order class somewhere. I''m adding a little feature, and all of a sudden I have to implement all these classes, at least in bits, and because I''m only handling a little bit of the behavior I don''t have any idea how they''re going to be used in other parts of the system. It''s scary because there''s more pressure to get it right the first time. mocks, otoh, allow you to defer all of that until later. When working on a feature, I can concern myself only with that feature and not worry about all the plumbing that it may need. A couple things happen there 1. I tend to end up with a clean, layered architecture. This happens because I''m only working on one layer at a time. When I''m bouncing back and forth between layers, I have to be extra mindful of what I''m dealing with, otherwise stuff that should be in one layer creeps into another and now I''ve got a muddled, difficult to understand design. 2. My life is easier! With mocks, I can isolate my thinking to a certain level or chunk of the code. Instead of pushing and popping all kinds of stuff on my mental stack, I limit the number of little things I need to think about at one time. I wasn''t blessed with unlimited brain space, so that''s a huge win for me. It also creates extra room to think about what I''m doing at a higher level and keep everything in perspective. It''s interesting, because your questions really boil down to being overwhelmed with what you have to do. It''s a feeling I know all too well. Fortunately RSpec provides two tools that do a fantastic job in easing the uncertainty. First you have user stories which help give you direction in the project. You know what you want to get done, have a good measure of progress as you implement it, and finally have a clear understanding of when you''ve completed it. On a lower level, mock objects help keep your thinking focused instead of running off in all different directions writing the all the infrastructure that it may take to write one line of code. You become less likely to code yourself into a corner, and you keep your mental stack in check. I hope that was helpful. I completely understand sitting at the keyboard wondering just what the hell I should be doing. I''ve found that RSpec helps me out a great deal both in terms of capturing desired business outcomes and in implementing the code to achieve them. It can take a while to really get it, but you may come to find that once you do you''re hooked. Pat [1] http://evang.eli.st/blog/2006/12/18/design-deep-not-wide [2] http://dannorth.net/2007/06/introducing-rbehave
Matthijs Langenberg
2007-Sep-30 09:56 UTC
[rspec-users] How to write the very first example?
Thanks for clearing things up Pat!I''ll give the story stuff I try, I haven''t looked at it yet. Does this actually mean I need to start describing some stories, then start with writing the examples/code for the first story by using mock objects for every layer? Do I eventually need to replace all the mocks by real objects? And is it bad to do partially stubbing on objects, or does this indicate an object should provide more information about its state? For instance, take a look at this pastie http://pastie.caboo.se/102174, is this a good way to write an example for a behaviour or am I taking a wrong approach? I feel the need for some small, simple, clean example programs, to take a look through. Maybe, I just need to put my current pet project online and let people shoot at it. - Matthijs On 9/30/07, Pat Maddox <pergesu at gmail.com> wrote:> > On 9/29/07, Matthijs Langenberg <mlangenberg at gmail.com> wrote: > > Many posts on this list are about using RSpec with Rails and that''s the > way > > I''m also using RSpec all the time. > > Unfortunately there isn''t that much info about using RSpec for > standalone > > Ruby projects. > > I don''t think that matters much, the principles are the same. You > write stories for features, and write specs to drive object > implementation. In fact I would say that Rails presents some unique > challenges for BDDing, and that a "pure" ruby project is easier! > > > I must admit I''m really having a hard time writing the very first > example(s) > > for a fresh standalone Ruby project. I haven''t really got a clue where > to > > start, how to call the first example and how to describe it. > > Begin at the beginning :P > > There are a couple approaches. First thing I would do is write a > story for one feature you want in the system. Having that story means > that you stay focused on one particular task and building the > infrastructure that will be used. I actually wrote a blog post a > while back on what I call "design deep, not wide" [1] > > On a simpler level, stories represent real progress. When you''re done > with a story you should have actual value, and that is fulfilling and > motivating. > > Also, you can start with smaller stories and build out from there. In > Dan North''s article about introducing rbehave [2] he works with simple > objects instead of a full application stack like you might in Rails. > When I first read it, I thought a standard spec might be more > appropriate. Once it hit me though (which was a couple months later), > I fell in love with that approach. > > To give you an idea, here''s the starting code: > > Story "transfer to cash account", > %(As a savings account holder > I want to transfer money from my savings account > So that I can get cash easily from an ATM) do > > Scenario "savings account is in credit" do > Given "my savings account balance is", 100 > Given "my cash account balance is", 10 > When "I transfer", 20 > Then "my savings account balance should be", 80 > Then "my cash account balance should be", 30 > end > > Scenario "savings account is overdrawn" do > Given "my savings account balance is", -20 > Given "my cash account balance is", 10 > When "I transfer", 20 > Then "my savings account balance should be", -20 > Then "my cash account balance should be", 10 > end > end > > Eventually he sticks objects in there as he implements them, but at > least at the very beginning there''s no code to speak of. It''s just a > user story. The beauty of it is that all you''re doing is specifying > acceptance criteria - what it means to be "done." One scary part of > doing lower level specs is on some level you''re designing code without > any real sense of direction. You might not necessarily know what > objects you need. While specs are excellent for discovering the > behavior of objects, as far as what operations they perform and > interactions they have, they don''t do much to help with the desired > behavior of the system. > > So, basically, writing stories forces you to think about what you want > to achieve, and gives you a clear way to measure progress. You know > where you want to end, and you know all the steps it takes to get > there, and that gives you the knowledge of where to start. > > > I want to use the outside-in approach, but that suggests the first > example > > you write should specify the workings of the whole project, right? > > I alway catch myself focusing on dependancies and start from the inside > > instead of the outside. (if I implement this first, I can use it as a > > building brick for that feature, and if that feature is implemented I > can > > work on that other feature.) > > This is where mock objects yield their greatest benefits. A lot of > people think mock objects are good only for isolating expensive > resources, but they''re fantastic in allowing you to design well in > chunks. For example, something as simple as: > > customer.place_order some_item, 12 > > Will require that I have a customer class, a place_order method, an > item class, and probably an order class somewhere. I''m adding a > little feature, and all of a sudden I have to implement all these > classes, at least in bits, and because I''m only handling a little bit > of the behavior I don''t have any idea how they''re going to be used in > other parts of the system. It''s scary because there''s more pressure > to get it right the first time. > > mocks, otoh, allow you to defer all of that until later. When working > on a feature, I can concern myself only with that feature and not > worry about all the plumbing that it may need. A couple things happen > there > > 1. I tend to end up with a clean, layered architecture. This happens > because I''m only working on one layer at a time. When I''m bouncing > back and forth between layers, I have to be extra mindful of what I''m > dealing with, otherwise stuff that should be in one layer creeps into > another and now I''ve got a muddled, difficult to understand design. > 2. My life is easier! With mocks, I can isolate my thinking to a > certain level or chunk of the code. Instead of pushing and popping > all kinds of stuff on my mental stack, I limit the number of little > things I need to think about at one time. I wasn''t blessed with > unlimited brain space, so that''s a huge win for me. It also creates > extra room to think about what I''m doing at a higher level and keep > everything in perspective. > > It''s interesting, because your questions really boil down to being > overwhelmed with what you have to do. It''s a feeling I know all too > well. Fortunately RSpec provides two tools that do a fantastic job in > easing the uncertainty. First you have user stories which help give > you direction in the project. You know what you want to get done, > have a good measure of progress as you implement it, and finally have > a clear understanding of when you''ve completed it. On a lower level, > mock objects help keep your thinking focused instead of running off in > all different directions writing the all the infrastructure that it > may take to write one line of code. You become less likely to code > yourself into a corner, and you keep your mental stack in check. > > I hope that was helpful. I completely understand sitting at the > keyboard wondering just what the hell I should be doing. I''ve found > that RSpec helps me out a great deal both in terms of capturing > desired business outcomes and in implementing the code to achieve > them. It can take a while to really get it, but you may come to find > that once you do you''re hooked. > > Pat > > [1] http://evang.eli.st/blog/2006/12/18/design-deep-not-wide > [2] http://dannorth.net/2007/06/introducing-rbehave > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/rspec-users/attachments/20070930/69dbf0cf/attachment-0001.html
On 9/30/07, Matthijs Langenberg <mlangenberg at gmail.com> wrote:> Thanks for clearing things up Pat! > I''ll give the story stuff I try, I haven''t looked at it yet. > > Does this actually mean I need to start describing some stories, then start > with writing the examples/code for the first story by using mock objects for > every layer?Here''s how I do this. I start with a set of stories and scenarios expressed only in text (no code in the Given/When/Then steps). I pick a scenario to start with and fill in the code, writing the code I wish I could write as I go. This helps me to discover the outermost objects and their APIs. Next, I pick one of the objects from the story and start driving it out with examples. The first examples will often overlap a bit with the stories and this is OK. Even expected. For anything that is needed by the object I''m working on at any given moment, if the code already exists to support it and using it is not expensive (in terms of required setup or processing cycles) I''ll use it. If the code is not there yet, or it is expensive to use, I''ll introduce a mock.> Do I eventually need to replace all the mocks by real objects?You don''t ever *need* to replace the mocks with the real objects, but you certainly can. The reason you don''t need to is that the Stories/Scenarios will fail when there is a mismatch between a mocked object and the real object. As to whether you *should* replace them, there are several schools of thought that generally resolve around responsibility and behaviour. For example, if we call foo.validate and that, in turn, calls validator.validate(self), where is the responsibility for validation? Some say it is foo''s responsibility, some say it belongs to the validator. That debate is out of scope for this discussion, but there are plenty of other discussions on this list that you can mine for ideas about this. Another factor that comes into play is the level of complexity of the setup. If you have to mock 3 layers deep, then maybe it''s better to use the real object. Of course, if you have to mock 3 layers deep, there might be a design problem.> And is it bad to do partially stubbing on objects, or does this indicate an > object should provide more information about its state?Well, it''s always better if you can avoid revealing information about state. Tell, Don''t Ask. But sometimes it is a necessary (or at least very useful) evil. And even when you''re just telling (i.e. no state-exposure necessary) the same question might come up. It really depends on context. I think it''s reasonable to ask that question whenever you''re using partial mocking/stubbing. Sometimes the answer is going to be that the object should respond to some new message, sometimes not.> For instance, take a look at this pastie http://pastie.caboo.se/102174, is > this a good way to write an example for a behaviour or am I taking a wrong > approach?In the text above the code under development, it says "Read the repositories from a file, notify the user for updates in all repositories," but the example says "should call notify_if_updates on every repository." This is pretty interesting, because the example uses an implementation-specific description, whereas the comment describes behaviour at a higher, more abstract level. So I''d start by changing the example to read "should notify the user if there is an update in any repository", with another example (likely several others) that reads "should not notify the user if there are no updates to any repository". Of course, this starts me thinking that notifying the user is really not Base''s responsibility, and that notify_if_updates should accept a notifier, listener, callback, etc. at which point the example is "should provide a callback to each repository to use if the repository has updates." So, the feeling I get from looking at this particular example/code is that it started from the code, not the example. I could be wrong - that''s just how it feels to me.> I feel the need for some small, simple, clean example programs, to take a > look through. > Maybe, I just need to put my current pet project online and let people shoot > at it.That would certainly be a powerful learning experience for you if you have the stomach to absorb criticism that is only sometimes constructive. It would probably be so for all of us. One thing to keep in mind if you do this experiment is that BDD is a process, and you''ll be showing and getting feedback on a result. There is something to be learned from the result, but the real money is in the process, so you''ll have to do some extrapolating from the criticism and apply it back to the process - unless of course you want to turn it into a complete tutorial with step by step explanations of every decision you made along the way. I can tell you from experience that it is a LOT of work ;) Cheers, David> > > - Matthijs > > > On 9/30/07, Pat Maddox <pergesu at gmail.com> wrote: > > On 9/29/07, Matthijs Langenberg <mlangenberg at gmail.com> wrote: > > > Many posts on this list are about using RSpec with Rails and that''s the > way > > > I''m also using RSpec all the time. > > > Unfortunately there isn''t that much info about using RSpec for > standalone > > > Ruby projects. > > > > I don''t think that matters much, the principles are the same. You > > write stories for features, and write specs to drive object > > implementation. In fact I would say that Rails presents some unique > > challenges for BDDing, and that a "pure" ruby project is easier! > > > > > I must admit I''m really having a hard time writing the very first > example(s) > > > for a fresh standalone Ruby project. I haven''t really got a clue where > to > > > start, how to call the first example and how to describe it. > > > > Begin at the beginning :P > > > > There are a couple approaches. First thing I would do is write a > > story for one feature you want in the system. Having that story means > > that you stay focused on one particular task and building the > > infrastructure that will be used. I actually wrote a blog post a > > while back on what I call "design deep, not wide" [1] > > > > On a simpler level, stories represent real progress. When you''re done > > with a story you should have actual value, and that is fulfilling and > > motivating. > > > > Also, you can start with smaller stories and build out from there. In > > Dan North''s article about introducing rbehave [2] he works with simple > > objects instead of a full application stack like you might in Rails. > > When I first read it, I thought a standard spec might be more > > appropriate. Once it hit me though (which was a couple months later), > > I fell in love with that approach. > > > > To give you an idea, here''s the starting code: > > > > Story "transfer to cash account", > > %(As a savings account holder > > I want to transfer money from my savings account > > So that I can get cash easily from an ATM) do > > > > Scenario "savings account is in credit" do > > Given "my savings account balance is", 100 > > Given "my cash account balance is", 10 > > When "I transfer", 20 > > Then "my savings account balance should be", 80 > > Then "my cash account balance should be", 30 > > end > > > > Scenario "savings account is overdrawn" do > > Given "my savings account balance is", -20 > > Given "my cash account balance is", 10 > > When "I transfer", 20 > > Then "my savings account balance should be", -20 > > Then "my cash account balance should be", 10 > > end > > end > > > > Eventually he sticks objects in there as he implements them, but at > > least at the very beginning there''s no code to speak of. It''s just a > > user story. The beauty of it is that all you''re doing is specifying > > acceptance criteria - what it means to be "done." One scary part of > > doing lower level specs is on some level you''re designing code without > > any real sense of direction. You might not necessarily know what > > objects you need. While specs are excellent for discovering the > > behavior of objects, as far as what operations they perform and > > interactions they have, they don''t do much to help with the desired > > behavior of the system. > > > > So, basically, writing stories forces you to think about what you want > > to achieve, and gives you a clear way to measure progress. You know > > where you want to end, and you know all the steps it takes to get > > there, and that gives you the knowledge of where to start. > > > > > I want to use the outside-in approach, but that suggests the first > example > > > you write should specify the workings of the whole project, right? > > > I alway catch myself focusing on dependancies and start from the inside > > > instead of the outside. (if I implement this first, I can use it as a > > > building brick for that feature, and if that feature is implemented I > can > > > work on that other feature.) > > > > This is where mock objects yield their greatest benefits. A lot of > > people think mock objects are good only for isolating expensive > > resources, but they''re fantastic in allowing you to design well in > > chunks. For example, something as simple as: > > > > customer.place_order some_item, 12 > > > > Will require that I have a customer class, a place_order method, an > > item class, and probably an order class somewhere. I''m adding a > > little feature, and all of a sudden I have to implement all these > > classes, at least in bits, and because I''m only handling a little bit > > of the behavior I don''t have any idea how they''re going to be used in > > other parts of the system. It''s scary because there''s more pressure > > to get it right the first time. > > > > mocks, otoh, allow you to defer all of that until later. When working > > on a feature, I can concern myself only with that feature and not > > worry about all the plumbing that it may need. A couple things happen > > there > > > > 1. I tend to end up with a clean, layered architecture. This happens > > because I''m only working on one layer at a time. When I''m bouncing > > back and forth between layers, I have to be extra mindful of what I''m > > dealing with, otherwise stuff that should be in one layer creeps into > > another and now I''ve got a muddled, difficult to understand design. > > 2. My life is easier! With mocks, I can isolate my thinking to a > > certain level or chunk of the code. Instead of pushing and popping > > all kinds of stuff on my mental stack, I limit the number of little > > things I need to think about at one time. I wasn''t blessed with > > unlimited brain space, so that''s a huge win for me. It also creates > > extra room to think about what I''m doing at a higher level and keep > > everything in perspective. > > > > It''s interesting, because your questions really boil down to being > > overwhelmed with what you have to do. It''s a feeling I know all too > > well. Fortunately RSpec provides two tools that do a fantastic job in > > easing the uncertainty. First you have user stories which help give > > you direction in the project. You know what you want to get done, > > have a good measure of progress as you implement it, and finally have > > a clear understanding of when you''ve completed it. On a lower level, > > mock objects help keep your thinking focused instead of running off in > > all different directions writing the all the infrastructure that it > > may take to write one line of code. You become less likely to code > > yourself into a corner, and you keep your mental stack in check. > > > > I hope that was helpful. I completely understand sitting at the > > keyboard wondering just what the hell I should be doing. I''ve found > > that RSpec helps me out a great deal both in terms of capturing > > desired business outcomes and in implementing the code to achieve > > them. It can take a while to really get it, but you may come to find > > that once you do you''re hooked. > > > > Pat > > > > [1] http://evang.eli.st/blog/2006/12/18/design-deep-not-wide > > [2] http://dannorth.net/2007/06/introducing-rbehave > > _______________________________________________ > > rspec-users mailing list > > rspec-users at rubyforge.org > > http://rubyforge.org/mailman/listinfo/rspec-users > > > > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
On Sep 29, 2007, at 5:43 PM, Matthijs Langenberg wrote:> Many posts on this list are about using RSpec with Rails and that''s > the way I''m also using RSpec all the time. > Unfortunately there isn''t that much info about using RSpec for > standalone Ruby projects. > > I must admit I''m really having a hard time writing the very first > example(s) for a fresh standalone Ruby project. I haven''t really > got a clue where to start, how to call the first example and how to > describe it. > I want to use the outside-in approach, but that suggests the first > example you write should specify the workings of the whole project, > right? > I alway catch myself focusing on dependancies and start from the > inside instead of the outside. (if I implement this first, I can > use it as a building brick for that feature, and if that feature is > implemented I can work on that other feature.) > > So, where do I actually need to start?I sympathize with your position. I imagine it''s much easier now that the story/rbehave stuff is around. In the past what I''ve done is written a prototype (usually a functioning one) - and have done it code-first, with no tests whatsoever. (I''m also thinking of Paul Graham''s words - all large programs start as small programs/scripts). Once I have that prototype, I rewrite the code, this time going test first, and making it Object Oriented. If I ever need to refer back to that old code, I can, but, at the same time, now I have written something slightly different, which is architectured better, and has tests to back it up. Just to give you an example of this, a few months ago I wrote a backup system. The core of it was just using rsync - very much like a simple script. But soon I wanted much more - backup deletion which would happen automatically, based on rules specified in a DSL. So I rewrote the core of the system test first, and was then able to layer the rest of the features on top and around that. Going on the 37 signals mantra: What is the most important feature of the system? That''s what you should be writing specs for. They may happen to be quite high level - that''s what your stories are for. Write one story (or a high level spec which you can mark as "pending"), and drill deeper into that, writing specs for the modules/ classes that it will take to make that initial story going. Hope that helps, Scott