A constraint is an artificial challenge during an exercise designed to help participants think about writing code differently than they would otherwise. Some constraints are an exaggeration of fundamental rules of object oriented design and are applicable during your day to day work. The more extreme ones might still help you understand the underlying concepts of object orientation.
Brutal Coding Constraints
The Brutal Constraints constraint is a composite constraint like Object Calisthenics, a combination of several constraints, some of them already difficult enough on their own. One particular combination that we like is
- No Conditionals, i.e. no
if
,unless
or?:
operator.while
can be used as conditional too and is not allowed as well.
- No Loops, i.e. no
for
,while
,do
orrepeat until
or whatever repetition constructs your language offers. Together No Conditionals and No Loops are sometimes called Cyclomatic Complexity One.
- TTDaiymi (TDD as if you Meant it), a very strict interpretation of the practice of TDD. This is optional, a "bonus" constraint for experienced developers. If you never heard about it, just ignore this one.
- No Naked Primitives, i.e. wrapping all "primitive" values, e.g. booleans, numbers or strings. Also general purpose containers like
List
,Map
orSet
are considered primitive. In extension all generic types of your language are primitive because they are not from your domain. A generic date (e.g.java.util.Date
) is not from your domain even if you use dates, because it either does not define all methods you need or it defines other methods you do not need.
- No void, i.e. all functions must return something, methods with no return value are forbidden.
- Immutable, i.e. all data and data-structures must be immutable.
Violating the Rules
When practising these Brutal Constraints with some kata, Martin and I were not able to find an implementation that would satisfy all constraints right away. We usually allowed violations in the beginning and refactored towards the constraints after the green phase. Sometimes we would leave a violation in for a few red-green-refactor cycles. It helped us to go through the list in each refactoring step to make sure we did not forget any constraint. It happened that we had put a condition somewhere in the code and forget about it - we are just that used to using conditionals and loop constructs. Because participants often ask for it, here is a list when to be strict about the rules. It is allowed to violate constraints:
- temporary until you fix them during the next refactoring step;
- temporary until you fix them after triangulating a solution, probably during a larger refactoring step after several cycles, e.g. after the third test;
- if an used framework requires it, e.g. using a
Runnable
needs avoid run()
method; - if the testing frameworks requires it, e.g. JUnit test methods are void methods and
@Parameterized
tests needList<Object[]>
which is a primitive container.
Difficulty
As I said before, Martin and I aimed for a really difficult exercise and I think we offered the only expert level session at ATD2014. And yes, this exercise was hard. The difficulty of each constraint was multiplied by their combination. For example I wrote about combining TDDaiymi, No Naked Primitives and No Conditionals last year. The attendees of the workshop agreed, "it was really difficult" up to "WTF" ;-). Brutal Coding Constraints are definitely too difficult for programming beginners, who even struggle with the concept of immutability.
An exercise like the Brutal Constraints can get frustrating easily. We told the participants that we made the session impossible on purpose, so they would not feel bad when getting stuck. When creating the workshop we got stuck ourselves several times, so we knew what to expect. During the session we paid close attention to the participants' mood and were prepared to offer hints on how to proceed without violating constraints. All participants worked hard and enjoyed the exercise.
Why practise like that?
When we prepared for the workshop we experimented with these constraints several times both in Java and JavaScript. It was difficult and interesting at the same time. I discussed some of our findings already. Also the ATD2014 participants liked the exercise. In the feedback round several people said that the constraints forced them to "think outside of the box" and that they liked the opportunity to "deviate from usual way" how they create software.
What about Functional Programming?
The Brutal Constraints focus on Object Oriented Programming. No Naked Primitives is the main driving force to create more types. On the other hand, constraints 1, 2, 5 and 6 might not challenge in Functional Programming. Instead of explicit conditionals some languages provide an
Option
or Maybe
type and filter operations remove unwanted elements from containers. Most loops are unnecessary because containers provide map
, foreach
or similar operations. Also a recursive function call is not a loop. Pure functions and immutability are base concepts of functional programming anyway. I would like to see a solution following the above constraints in Clojure or Haskel. I am unsure how No Naked Primitives translates into Functional Programming.The Assignment
In general the actual assignment, i.e. the problem that participants are asked to solve, does not matter for a kata but we wanted a problem that did not support the constraints. (Evil grin ;-) Such a problem would have a linear or higher dimensional structure with a need for looping (which is not allowed) and business rules, which are conditionals (which are not allowed either). We started with the classic Game of Life but it took us too long to reach a point where the constraints forced us to think harder. So we switched to a smaller problem, finding the winner of a game of Tic-tac-toe, which worked well for us.
Hints for Facilitators
If you plan to host your own Brutal Constraints exercise, your first priority is to help the participants to meet the constraints. It is easy to miss an
if
or a void
method. We recommend printing the list of constraints and TDDaiymi rules as handout for each pair in the workshop. Second you need to pay attention to people's mood, as I described above.For a short workshop it would help to force participants into situations conflicting with the Brutal Constraints as early as possible. One way to do this is to start with a prepared code base that already contains the first loop or conditional which needs to be removed. But then the list of supported programming languages for the workshop is small, ruling out less popular ones. Another way is to ask participants to follow a list of predefined test cases. While this allows any language, it impedes the creativity of solution finding. We still have to find a good list of test cases though.
Moar Brutality
But why should we stop here? We can make the exercise even more difficult. A suitable constraint to add is No Duplication, i.e. being very aggressive about duplication in the code. Unfortunately detecting duplication is less straight forward than following constraints 1, 2, 4, 5 and 6 which just deny certain reserved keywords or library classes. Another option is to add Baby Steps to force smaller working steps and Baby Steps has been combined with TDDaiymi already. When practising the constraints we committed every five to six minutes without problems.
Credits
Thanks to Martin Klose for creating the Brutal Coding Constraints with me. Pair facilitation is just so much more rewarding than solo work.
3 comments:
The more I dive into functional programming, I have the gut feeling that these constraints listed above (or the Object Calisthenics) try to mimic, or recreate the features of, FP in OO. You listed how various points are implicitly solved when doing FP.
For instance, my pet-peeve to look for implementations without using conditionals (if) was solved when I stumbled over that fizz-buzz implementation using Lambda Calculus.
Does the current trend of FP also reach our practices as well?
Hey Christian, remember that you can also avoid ifs by old-school OOP polymorphism!
I definitely agree that FP also reaches our practice as FP gets more and more main-stream. But these rules also helped me to deepen my understanding of pure OO, esp. rules (3) and (4). And as Sebastian said, you can chose how to "fix" the missing if/loop, there are many possibilities.
Post a Comment