Dan North (father of BDD) responded to some dialog over on the Google BDD group with a very insightful look at what the "Context" of a specification really is. For me, this was an eye opening post and I'm already seeing ways to improve my specification tests. His post is worth quoting in it's entirety: Let me describe where the idea of contexts ("givens") came from. We started out by writing each story on the front of an index card, and on the back we'd draw a line down the middle to create two columns. Then we would label the columns: "I do this" and "This happens". (I think it was Ivan Moore who first showed me this.) It's incredibly simple and it worked well for describing the acceptance tests. I do Y, and Z should happen. If it doesn't I'm not done yet. Once it does I can go to the pub! Then I showed that to my business analyst friend Chris Matts, and he said: that doesn't make sense. I do Y and *anything* could happen! I request cash from an ATM and it could give me cash. Or it could refuse because I'm overdrawn. Or it could retain the card and call the police! You're missing a context. So we evolved it into *Given X*, When Y, Then Z. So now "the context" is simply another way of saying "which scenario is this?". It's the scenario where my account is in credit, or the one where I'm overdrawn, or the one where the card was reported as stolen. Like on Friends where each episode is called "The one where...". This means the scenario titles are typically just a description of the context, and the givens set up that context. In other words, you discover the contexts as you describe which scenarios you are interested in (and more importantly which ones you aren't). Cheers, Dan Solid gold, Dan! and thanks for the insight!
Earlier today, I had a conversation with a coworker concerning dependency container, dependency injection frameworks, and the root dependency inversion principle. My advice in the end, was to completely avoid the use of DI tools until the team as a whole understands the cost, benefits, and potential pains of manual dependency injection (pain being relative, and usually a sign of a learning opportunity). Part of the conversation also revolved around what constitutes the complete overuse and abuse of DI or IoC tool - which I can easily speak about due to extensive personal, self-inflicted, love-affair-of-IoC induced pain over the last year. However, the one thing I could not speak to was the correct use of a DI / IoC tool, because I believe that I have never used one correctly - or at least, my limited experience in using one correctly is so limited, I can't seem to separate it from the incorrect use. I’ve heard other developers (Jeremy miller, jimmy bogard, and others) say that they want to see as little of a dependency container / injection tool in their code as possible. This gets to the heart of what I was trying to convey earlier, but I’ve never had a good understanding of where you would actually allow a dependency tool to be used under those guidelines. On the way home from work tonight, I had (what I think is) a small epiphany around the idea that the dependency container should be limited to two key areas: the various implementation specifics (UI, database, etc) and the application layer. I think the use in the implementation specifics, for whatever use they're needed, is valid since these implementations are not unit tested to begin with. But I would highly recommend limiting the container’s use in these scenarios, for the same over used, abused reasons that I'm so intimate with already. More appropriately, the application layer seems to be the appropriate location to resolve the dependencies by using the DI tool to instantiate the object that needs the dependencies, automatically resolving the dependencies for us – not requesting the dependency directly. The best example I can think of, off-hand, is a workflow coordination service in the application layer. Let’s say your workflow moves from FormA to FormB in a windows app. The workflow class would use the DI tool to instantiate the ProcessAPresenter, which would resolve the registered IProcessAView as a constructor dependency. Then when this form is done, the workflow coordination class would use the DI tool again to instantiate the ProcessBPresenter and resolve the IProcessBView (and ISecurityService and whatever else) constructor dependencies. The key here is that we are allowing the application layer to use the DI tool, and not the other way around – not letting the DI tool instantiate the application layer - and not using the tool as a simple IoC container to resolve dependencies internally from the object that needs the dependency. These are primitive, unverified thoughts at this point, and need to be taken as such. I think this is a good start for a correct use of a DI tool, though. Additional implementation experience within this model would help to expose additional constraints and allowed uses, I would imagine. How are you using your DI / IoC tools? What are your thoughts on the subject? Your pains, your joys, your sorrows? And from a purely selfish perspective - am I on the right track, here?
There's been a lot of recent talk about what is "done" in the Lean / Agile development communities, and the primary focus of these discussions has been focused on individual features or stories and the need to get them completely "done" (dev, test, acceptance test, documentation, delivered to customer) before they can be considered done. I wholeheartedly agree with this philosophy, to the point where I active introduce painful elements of software development to my team members, because the work must be done before we can deliver to the customer. All that being said - I think we're missing out on some potential benefit by not applying "done" at various and different levels of our software development projects. For example, the concept of "done" can be applied to an iteration. What constitutes an iteration being "done"? It's certainly not just the time-box of 2 weeks, 1 month, or whatever our iteration length is defined as. However, that time box is still important. We don't want arbitrary lengths of iterations. So how do we know when an iteration is completely "done" versus just being over? My initial thoughts revolve around a pass/fail checklist, similar to the swim lanes (or kanban board, if you want to call it that) that our stories go through. At this point, I would likely include the following: - Iteration length passed
- All stories in iteration "done"
- Code reviewed (possibly part of story being "done")
- Software is in a stable, working state
- Software acceptance tested by customer (or customer representative / SME)
- Retrospective held
There's probably some additional items to include here - this is just my initial idea list. Like the user story "done" criteria, an iteration cannot be considered "done" until all of the items in this list have been checked off. We don't give partial credit for a story making it to "in test", when there are 2 more columns to move through - the story is not done until it's completely "done". The same should apply to the iteration. Why bother making an official "done" list for iterations? For the same simple reason we do this for user stories - transparency and visibility into bottlenecks and problems. It's easy for a team to ignore problems like broken software at the end of an iteration - "oh, it's just XYZ... i'll take care of that tomorrow" - when we don't have the same accountability as we do in our stories. By making the iteration a pass/fail set, we expose those problems for the world to see. This exposure is a great motivational tool - who wants to be caught with an un-"done" iteration because of a "simple" bug? Do you and your team have an iteration "done" list? Do you even have a user story "done" list? It's all about exposing weakness and waste, then eliminating it and creating the official iteration "done" list is just one more step along the path. Don't stop there. What other processes - higher or lower level - can we standardize and improve?
The one and only goal in software development is to provide useful, functional software that creates value for the customer or consumer. Period. End of story. Not open for discussion or opinions. If you want to deliver software that the customer or consumer wants to use, likes to use, and ultimately does use to help solve problems and/or automate business process, etc, then you must know what the customer or consumer values. In other words - you can't identify your software's 'value' if you don't know who/what ALL of your customers are. I'd put money down to say that most software developers - perhaps most software development companies - have no clue how many customers and consumers there really are for any given software project. The one consistent answer that I would expect from every developer or company is that the person, group, or company paying money for the software is the customer. This is 100%, absolutely true. In addition to the paying customer, though, there are many other customers or consumers that need to be identified. As a starter, consider the following list for the customers / consumers of your software: - The paying customer
- Integrated external systems
- API consuming systems
- Software Testers and Test Lab personnel
- Technical and documentation writers
- Software developers (the ones writing the code!)
I know, I know... how could a software developer possibly be considered a customer or consumer of the software that they are writing? The answer should be obvious - who reads and writes the code? who maintains the code and needs to understand how the code is structured so it can be maintained? If you don't believe that your software developers are first class consumers of the system that they are writing, I would bet that you have a horribly complex kludge of code that no one wants to work on. If your developers are considered first class consumers of the code they are writing, I would bet that your team is happy and is constantly working toward better code - simple, readable, maintainable systems that are fun to work on. So, who are your customers or consumers? What value do they need in your system and from your system? And, how are you and your team responding to those value needs (if at all)?
Derick’s (brand new, just thought of it, but is now elevated to ‘mantra’ status for me) golden rule of Acceptance Criteria: If it’s not usable by every team member, it’s not Acceptance Criteria. And I do mean every team member - Customers, Testers, Tech Writers, BAs, Developers, UX Designers, and anyone else on your team. You can specifying the technical or UI details in the story’s detail, but it’s not acceptance criteria – it’s Technical Criteria, or UI Criteria, or Test Automation Criteria, or … etc. Generally speaking, don't include these alternate criteria in the story detail – let the specific team members determine their specific criteria and record it how they need to (through unit test for devs, interaction design mockups for ui peeps, etc).
The entire team – BAs, Devs, UX, Testers, Tech Writers, Customers and Management (especially customers and management) – all need to understand that the first few iterations of a team that is trying to convert to an agile methodology, will be slow and painful. You won’t get as much done as you think you should. You’ll run into constant problems, questions, points of clarification, and unknowns. Iterative development processes expose every single problem that your team never knew it had, and more – and if you’re honest and working with integrity, you won’t whitewash the problems and try to hide them; rather, you’ll embrace the transparency that iterations create and use it to drive improvement in your team. Converting to Agile is painful and it’s embarrassing at time. There's no question that it’s difficult to convert – especially if the team has any significant habits or experience from previous projects (and who doesn’t, aside from entry level people). Work through the pain, solve the problems one at a time and continue to improve the process. Eventually, the team will find it’s groove and productivity will increase. Over time, if the team truly is honest with itself and is continuously solving problem, productivity should skyrocket and you’ll wonder how you ever worked without iterative / agile methodologies. The key is - don’t expect it to be perfect… ever… take one step at a time and never stop moving forward.
In addition to our 'Code Review Challenge' that I discussed recently, we have been using another retrospective game - 'Name That Standard'. The idea is fairly simple. At the beginning of any retrospective, we go around the room and ask each team member to list out a standard that we are using in our project. This can be any standard that anyone feels the team is using or needs to be using, including coding conventions, architectural patterns, business and project management processes, communication means, etc. The intention is similar to the intent of 'The Code Review Challenge' - socialization of the the system. Only in this case, we are applying the term 'the system' at a much higher level - our organizational and project management / implementation system as a whole. Some thoughts on running 'Name That Standard': - Require not only naming of the standard, but accurate description of the standard and an example of where it is used. Alternatively, you may want to list a brief description out on a projector or whiteboard and see who can name the standard being described.
- Encourage the team to think about the team as a whole, not just their area of responsibility.
- Encourage the team to list standards that they don't understand, so that the rest of the team can chime in with assistance and help the team member in question grow
- Don't just let people yell out standards. go around the room, one person at a time. we got a little chaotic at first, and it was hard to know who said what.
- Encourage people to ask questions like 'i thought we were using this standard, but i saw someone else doing that standard'
- Encourage the standards to become more and more low level and detailed, over time (over multiple iterations)
- Encourage the standards to evolve and change for the better, over time (over multiple iterations)
In our implementations of this game, we've managed to get a fairly good list of standards written down and also resolved some questions on what standards we actually are using. For example, we had 3 dynamic mocking frameworks in our code base - Rhino Mocks, Moq, and a home grown one that we lovingly called 'BrandoMocks' (named for our team member, Brandon, who wrote it for fun one night). The end result of that discussion was to throw out Moq and BrandoMocks, adopting Rhino Mocks as our standard for this project. Having done 'Name That Standard' in two consecutive iteration retrospectives, I think I can say that it has been very successful. The team as a whole is becoming more and more aware of the standards that we are using, and the individual members are beginning to contribute more and more to the standards. With each passing iteration, and each new technique for creating collective ownership and socializing the system, I see the team coming together and really forming a team vs. a bunch of individual developers working on the same system.
My team tried out 'The Code Review Challenge' in today's retrospective. Overall, I think it went pretty well for the first time that we've tried this. Here's some initial thoughts after our first attempt. - Make sure the team knows what's going on before you start. I was not leading the review, and I had to step out right when it started. I believe the team lead explained the idea, but I'm not sure I had fully explained to her. In the end, ensuring that each team member is comfortable with the idea and the process is important.
- Encourage discussion with the group during the review. Don't force the talk from the reviewer, but ask questions that will help lead them to conclusions and descriptions of what is going on.
- Don't expect everyone on the team to be able to recognize the same standards, practices, or issues. each team member will have a different understanding of the standards that we are trying to apply, at any given time. encourage learning help others to see what you see.
- make sure everyone on the team has a chance to review someone else's code. i think we ended up with a good mix of people reviewing and being reviewed, but it wasn't planned, it just kind of happened. next time around, we're going to ensure that it happens by planning ahead based on the work done by the people in the review.
i think there was a lot of benefit in doing the reviews in this manner. we ended up with a lot of good comments, suggested improvements, etc. i'm happy to say that the code review challenge was a success and that we'll continue to do it in future retrospectives and reviews.
A Food Network Challenge During this season's 'The Next Food Network Star', there was an episode where the contestants had to cook a dish and review it in front of a camera, describing it's visuals and taste. The twist to the challenge was that they were assigned someone else's dish to review, after everyone had already cooked. Once the assignments were made for who was going to describe who's dish, they were not allowed to see the dishes anymore. A given contestant was then put in front of a camera and had their assigned dish uncovered in front of them. From that point, they had 90 seconds to describe the dish that was in front of them - that included figuring out what it was, what it looks like, what it tasted like and what it smelled like. This was a rather tough challenge to watch, and a few of them didn't do so well. A Code Review Challenge What if we take the Next Food Network Star's challenge and apply it to code reviews? When we sit down in a code review session, rather than having the person who wrote the code doing the driving and telling us what is going on, have someone who has not seen the code do the driving - read the code, read the unit tests, etc - and describe to us what is going on. 90 seconds wouldn't be nearly enough time, though, so we'd have to change that time limit based on the size and complexity of the functionality being reviewed. Other than that, though, it seems like it would be a great way to test the team's ability to pick up an area of the system that they have not seen before and quickly learn it so that they can work in it. Standardized Work - Judging Code And Code Reviewer There are 2 real benefits to the code review challenge, as I see it: - Judging how well did the coder apply our coding and development standards
- Judging how well the reviewer can recognize and describe the standards being applied
We are now building our system from User Stories, with Context / Specification style unit testing. One of the intents of this style of unit testing is to provide an easy-to-read and easy-to-learn set of examples for developers that need to know how to do something or how something works in the system. If the unit tests are properly written and expressive of the code's intent - it should be really easy to see what's going on. If we have good standards in place, a developer should be able to find the code in well organized areas, easily, and know where to look for the various components and parts. It seems to me that the code review challenge would help to prove a number of these key factors in our projects and our teams: - Coding and architecture standards
- How well the standards are known
- How well the team follows the standards
- Expressive Code
- How easy is it to read the code
- How easy is it to understand the code's intent
- Maintainable Code
- How easily can the code be changed and extended
- How quickly the team can socialize and collectively own the system
A Challenge In Name, A Learning Experience In Practice I would avoid applying any sort of point system or other reward / incentive for the code reviews. It seems that this could easily backfire and cause junior team members (in skill or time on the team/project) to feel intimidated or feel that it's an unfair process comparing them to the senior level team members. The intention of the code review challenge is not to cause dismay in any team member, but to create a learning environment by continuously challenging every member of the team. Ultimately, the code review challenge should foster the socialization of the system and lead to a strengthened sense of collective ownership, resulting in a better system. Nothing New Under The Sun? With all that being said - I'm doubtful that I'm the first person to ever hold a code review like this. I'd be interested in knowing if there's any standard development practices (Agile or otherwise) that are heading in the same direction. Any advice or opinions of you, the reader, would also be very welcomed. If you know of a resource that describes the same basic ideas or if you have any input to help me improve the idea, please leave a comment and let me know.
Some coworkers were recently working on an object model for a simple security system. After some discussion with them, we came up with this basic model: A permission is defined as an activity that can be assigned to a user, or group, and can be allowed or disallowed. From a Domain Driven Design perspective, we're stating that the Permission is the aggregate root. The User object itself, while involved in this aggregate, is divorced from this aggregate's relational model - you can load and work with a User object without having to load or worry about the Permission hierarchy. The addition of the "UserGroup" is solely for the many-to-many relationship between User and Group mappings with NHibernate and is not actually part of the object model's code. Once we had this model in place, we wanted to have a simple query that allowed us to load a given permission object by activity name, for a user - whether the user was assigned directly or via a group. At a high level, this model and query should be fairly simple to work with. It turned out to be a massive learning curve in NHibernate, though. After much trial, error, and Google searching, we ended up with this NHibernate query code: ICriterion userIdMatches = Restrictions.Eq("Id", userId);ICriterion activityNameMatches = Restrictions.Eq("Name", action);ICriterion userIdAliasMatches = Restrictions.Eq("u.Id", userId); DetachedCriteria groupPermissionCriteria = DetachedCriteria.For<Permission>() .SetProjection(Projections.Property("Group")) .CreateCriteria("Group").CreateCriteria("Users").Add(userIdMatches);ICriterion groupSubquery = Subqueries.PropertyIn("Group", groupPermissionCriteria); DetachedCriteria permissionCriteria = DetachedCriteria.For<Permission>() .CreateAlias("User", "u", JoinType.LeftOuterJoin) .Add(Restrictions.Or(userIdAliasMatches, groupSubquery)); permissionCriteria.CreateCriteria("Activity").Add(activityNameMatches); ICriteria executableCriteria = permissionCriteria.GetExecutableCriteria(Session); result = executableCriteria.List<Permission>(); return result;
There were a lot of lessons learned and a lot of parts that eventually got put together. Here's a quick run-down of what we ended up with and why.
- The ICriterion's at the top of this code block are there to provide a little better readability in the real query code below.
- The groupPermissionCriteria is set up to find a permission object where the specified userId belongs to a Group that belongs to the Permission - i.e. find permissions where the user is assigned via a group. The learning curve from this perspective was the SetProjection call. Though we are not entirely sure what a projection is at this point, we did find out that it was necessary for us to set this projection so that the detached criteria could be used as a sub-query.
- The groupSubQuery is the conversion of the groupPermissionCriteria into an ICriterion so that we can do a logical Or with it in the primary query construction.
- The permissionCriteria object sets up the core criteria logic and ties together the group permission assignment with the user permission assignment.
- CreateAlias is used so that we can shorten the criteria for loading by the User assignment directly. The JoinType on the alias needs to be Left Outer Join so that we will return a proper Permission object even when there is no direct user assignment.
- After creating the alias, we can add an "Or" criterion to the query and specify that we want to match based on the user's direct assignment or a group's assignment.
- The last line of the criteria simply adds the Activity criteria to load by the activity name.
The resulting SQL will load the permission by Activity name AND (User assignment OR group assignment where the user is part of the group).
SELECT this_.PERMISSIONSID as PERMISSI1_0_3_, this_.IS_ALLOWED as IS2_0_3_, this_.ACTIVITYID as ACTIVITYID0_3_, this_.USERID as USERID0_3_, this_.GROUPID as GROUPID0_3_, activity1_.ACTIVITYID as ACTIVITYID4_0_, activity1_.ACTIVITY_NAME as ACTIVITY2_4_0_, activity1_.DESCRIPTION as DESCRIPT3_4_0_, activity1_.INACTIVE_DATE as INACTIVE4_4_0_, u2_.USERID as USERID3_1_, u2_.USER_NAME as USER2_3_1_, u2_.INACTIVE_DATE as INACTIVE3_3_1_, group6_.GROUPID as GROUPID1_2_, group6_.GROUP_NAME as GROUP2_1_2_, group6_.INACTIVE_DATE as INACTIVE3_1_2_ FROM PERMISSIONS this_ inner join ACTIVITY activity1_ on this_.ACTIVITYID=activity1_.ACTIVITYID inner join USERS u2_ on this_.USERID=u2_.USERID left outer join GROUPS group6_ on this_.GROUPID=group6_.GROUPID WHERE activity1_.ACTIVITY_NAME = :p1 and ( u2_.USERID = :p2 or this_.GROUPID = ( SELECT this_0_.GROUPID as y0_ FROM PERMISSIONS this_0_ inner join GROUPS group1_ on this_0_.GROUPID=group1_.GROUPID inner join USERS_GROUPS users5_ on group1_.GROUPID=users5_.GROUPID inner join USERS user2_ on users5_.USERID=user2_.USERID WHERE user2_.USERID = :p3 ) )
Using a sub-query to load based on the group is not the most optimal way of loading the permission for the group assignment. However, since all of the joins in the main query and the sub-query are done on primary and foreign keys in the tables, performance should not be an issue. The only real performance concern for this query is the activity name in the where statement. A simple unique constraint and index on the activity name, though, will solve that problem.
|