Easy to use correctly, hard to use incorrectly – Christophe Addinquy
Easy to use correctly, hard to use incorrectly By Christophe Addinquy As agilists, we do our best and are continuously looking for technical excellence. This is in fact stated by the agile principles.
Figure 1: Extract from the agile principles1
Hopefully, it’s pretty simple to gather expert advises in our quest for excellence: • Kent Beck’s implementation patterns2 • The pragmatic programmers set of rules3 There are in fact more sources than that. Much more than I can keep track of. They are all smart insights. But we end up with an insanely long list of expert advices. It’s too much for me. Another good (yet different) advice is to travel light. For nearly 20 years, I now rely mainly on only one, given by Scott Meyers:
Make your interfaces easy to use correctly and hard to use incorrectly4 5. 1
The agile manifesto (2001) : http://agilemanifesto.org/principles.html Implementation Patterns – Kent Beck – Addison Wesley / Signature series 2007 – ISBN : 02 Implementation Patterns – Kent Beck – Addison Wesley / Signature series 2007 – ISBN : 0321-41309-1 ; EAN : 978-0-321-41309-3 3 The Pragmatic Programmer: From journeyman to master - Andrew Hunt & David Thomas Addison Wesley 2000 - ISBN: 0-201-61622-X 4 Effective C++, 55 specific ways to improve yours programs and designs, 3rd edition - Scott Meyers - Addison Wesley / Professional Computing series 2005 - ISBN: 0-321-33487-6 ; p. 5 97 Things Every Programmer Should Know – Kevlin Henney edt. – O’Reilly 2010 – ISBN : 978 0 596 80948 5 ; p. 2
1 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy In the rest of the paper, we’ll see this principle declines in different areas: • • • •
Coding practices Design User interfaces Development processes.
An advice, not a rule What is the opposite of this advice? In fact, there is no one, but three of them:
Figure 2: The opposite sides of Scott Meyers advice
You can just be wrong in one way: • By make your interfaces hard to use correctly while still being hard to use incorrectly. • Or by keeping your interfaces easy to use correctly and unfortunately making them easy to use incorrectly as well. Of course, the worse case scenario is to be wrong both ways and making your interfaces hard to use correctly and easy to use incorrectly! Fore sure, we want to stay away of this last case. But is there some degree of acceptability between these two extremes? Well, making acceptable nothing but the extremes is hardly a reasonable choice. That’s why I don’t consider Scott Meyers sentence as a rule, but a direction we want to be close to. 2 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy
Figure 3: Consider Scott Meyers advice as a compass
We’ll take it as a kind of compass in our following examples. Speaking of that, I hope you’re ready, because we’re starting right now.
It all starts with some code… Consider the following code sample: Challenge #1 class ProcessEngine { ... int method1 (void* arg1, void* arg2, void* arg3); ... };
It may looks like a joke at first. In fact every element of this one come from a real life example I met some day. I just merge all of them. If I summarized the problems we have here, we can tell: • The name of the method doesn’t help me: I have no idea what it’s all about. The surrounding class doesn’t help me more, in fact. • The name of the parameters shares the same level of imagination. It will be hard to pass actual parameters with such level of information. • To make things worse, the type of parameters cut down all my hopes. They are all pointers on (literally) anything. • Compared to that, the return type seems to be a minor problem. Even if I don’t know what is expected.
3 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy Next question is: where does this example lie in? Answer is:
Challenge #1: Hard to use correctly, easy to use incorrectly It’s hard to use correctly, because we have to figure out by ourselves what is the purpose of the method and also the kind and nature of the parameters we have to pass It’s also easy to use it incorrectly because we can pass any Type as parameters and because it’s an int, we can use the return type for … well, many things! Obviously, one of main problems here is related to names.
The name: our intention revealed Names shouldn’t be chosen lightly. Bad name convey misunderstanding, therefore making the element easy to be used incorrectly. Let’s have an example. bool isFinished = iterator.end();
The meaning of “end” is not as clear as it may seem at first. It can be: • Move the iterator to the end. • Tell if the iterator reached the last element. • Tell if the iterator is over the last element. The name is not terrible, but we can do better with some discipline. bool isFinished = !iterator.hasNext();
We no longer have doubt about the meaning of the hasNext method: it should return “true” if there is still at least one element over the current one. In short: naming should reveal the intention6 7.
Consistency Challenge #2 Consider the following piece of code: public class JoinAccount extends Account { public void addAccount(Account newAccount, DateTime activeFrom) { } public void removeAccount(DateTime activeTime, Account accToRemove) { } 6
Implementation Patterns – Kent Beck – Addison Wesley / Signature series 2007 – ISBN: 0321-41309-1; EAN: 978-0-321-41309-3, p. 79 7 The Practice of Programming - Brian W. Kernighan & Rob Pike - Addison Wesley / Professional Computing series 1999 - ISBN: 0-201-61586-X, p. 4
4 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy }
Here, the problem is less obvious. In fact it seems almost OK, except for the parameters permutation between the two methods. It may leads to some confusion for the user who gat some habits. But it doesn’t hurt because the compiler will raise the problem if you give the wrong actual parameters. Therefore:
Challenge #2: Hard to use correctly, hard to use incorrectly Consistency will help the user to find out how to use a method. Break it only when you have strong argument about it.
Good habits to prevent mistakes Take a look at this C++ code. Nothing looks wrong at first. int processEngine::method2 (Motor& motorToActivate, double ignitionPower) { Launcher* launch1, launch2, launch3; ... }
First, there is at least good news: the parameter motorToActivate is passed as a reference, not a pointer, making it safe against a null pointer problem. However, the 3 local variables don’t behave as expected. Because of the Launcher* we believe it’s a 3 pointers declaration pointers statement. It’s not. The pointer declaration applies to the first element the remaining two are values. The space arrangement makes it error prone. Of course it’s a syntax rule you should know, but why make it easy to fail, while a simple layout may help you? int processEngine::method2 (Motor &motorToActivate, double ignitionPower) { Launcher *launch1(0), *launch2(0), *launch3(0); ... }
Also, declaring unassigned pointers is not the best design we take care to initialize them to 0, so any attempt to access them will fail.
Tricky little test A little while ago, I read a Joel Polsky post8 about hiring tests. In this post, the author claim that C and C++ long timer developers wrote their tests in a very special way. I do. Do you ? Here a classic C/C++ test: 8
Joel on Software – Joel Spolsky – Apress 2004 – ISBN : 1-59059-389-8 ; EAN : 9 781590 593899, p. 164
5 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy if (countDown == 0) { ... }
So far so good. But mistakes happen. On a loosy day, you may write: if (countDown = 0) { ... }
Unfortunately, it doesn’t fail. But it doesn’t perform what you expect either. In fact it assign 0 to countdown, and because the assignment succeed, this operation returns 1, executing the “true” condition of the test each and every time! There is a simple way to avoid the problem, even if it makes the code looking weird: if (0 == countDown) { ... }
If you do the same mistake here, the compiler will protest!
On programming languages Programming languages can also be easy to use correctly and hard to use incorrectly.
What kind of type system? Let’s be straight: it’s all about static typing versus dynamic typing! I personally take a side on this point. Some don’t and try to compare both approaches.
6 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy
Figure 4: Dynamic vs static typing
Dynamic typing languages hold the reputation to be more expressive and more productive. However the typing system is not check at compile-time and depend on the execution path. While dynamic typing aficionados argue that there’s no excuse to not write tests and even that tests are faster than long compilation times, I do believe that testing can be escaped or missed, where compilation can’t. In this way, I found static typing easy to use correctly and hard to use incorrectly (depending on the other weaknesses of the language) and dynamic typing at lease easy to use incorrectly.
When the language enforce case convention… Nearly each and every project publishes its own style guide to enforce coherent conventions across all developers. That’s a good thing, because languages don’t enforce that. However the creators of the Ceylon language decide to enforce these conventions into the language!
7 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy
Figure 5: Ceylon names conventions in practice
Ceylon class names must start with an uppercase, and variables, attributes, parameters and methods need to start by a lowercase. Maybe Ceylon could go even further, but it did an interesting move: it settle unimportant decision where there is no value to discuss. By doing so, it also guarantee a coherence not only inside a project, but also across all Ceylon projects … and save all the conventions discussion time!
Design, design… The mighty accessor Challenge #3 Consider the following class: package com.addinquy.etuc; import org.joda.time.DateTime; public class private private private
Person { String firstName; // Mandatory String lastName; // Mandatory DateTime birthDate; // Mandatory
private String socialSecuNumber; public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public DateTime getBirthDate() { return birthDate; } public String getSocialSecuNumber() { return socialSecuNumber;}
8 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy public void setFirstName(String firstName) { this.firstName = firstName; } public void setLastName(String lastName) { this.lastName = lastName; } public void setBirthDate(DateTime birthDate) { this.birthDate = birthDate; } public void setSocialSecuNumber(String socialSecuNumber) { this.socialSecuNumber = socialSecuNumber; } }
Maybe you don’t think there is something wrong here. Actually, many frameworks require creation of such classes, with Hibernate coming to my mind. But it’s not only this one. This design is so common that many IDE propose shortcuts to generate these getters/setters stuff. Even some languages consider a new feature called “properties” that free you from all these getters/setters code. It’s all pathetic. There are at least 2 problems with that: • It avoids any form of abstraction on the class. • It’s leaky, because nothing enforces consistency. Let me illustrate this second point. package com.addinquy.etuc; import org.joda.time.DateTime; public class PersonService { public Person createPerson(){ Person p = new Person(); p.setFirstName("Christophe"); p.setLastName("Addinquy"); /* * I'll finish it later... DateTime dt = new DateTime(1963, 12, 5, 0, 0, 0); p.setBirthDate(dt); */ return p; } }
The comment on Person said that the birthDate attribute was mandatory. But nothing enforces that. Actually nothing enforce any mandatory field at all. Or any form of coherence when it applies between those attributes. For me, the Person class is probably designed by this guy:
9 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy
Figure 6: The getter/setter designer
That’s not a so much clever design at the end
Challenge #3: (almost) easy to use correctly and easy to use incorrectly The solution is an idiom called RAII9 for Resource Acquisition is Initialization. Following this design, we initialize the mandatory attributes through the constructor and remove the setters when changing the attribute value after instantiation doesn’t make sense. Here the refactored class: package com.addinquy.etuc; import org.joda.time.DateTime; public class private private private
Person { String firstName; // Mandatory String lastName; // Mandatory DateTime birthDate; // Mandatory
private String socialSecuNumber; Person(String firstName_, String lastName_, DateTime birthDate_) { firstName = firstName_; lastName = lastName_; birthDate = birthDate_; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public DateTime getBirthDate() { return birthDate; } public String getSocialSecuNumber() { return socialSecuNumber;} public void setSocialSecuNumber(String socialSecuNumber) { this.socialSecuNumber = socialSecuNumber; } 9
Effective C++, 3rd edition - Scott Meyers - Addison Wesley 2005 - ISBN: 0-321-33487-6, p. 70
10 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy }
The previous mistake can’t happen any more, because without the birth date, you cannot instantiate the Person class. package com.addinquy.etuc; import org.joda.time.DateTime; public class PersonService { public Person createPerson(){ Person p = new Person("Christophe", "Addinquy" , new DateTime(1963, 12, 5, 0, 0, 0)); return p; } }
A question of protocol Very often, we have to deal with interfaces for which there is a precise contract usage. Challenge #4 For the following interface: package com.addinquy.etuc; public interface IPersonService { public boolean checkConsistency(Person p); public void process(Person p); public void finalize(Person p); }
The implementation part of this interface would like likes that: package com.addinquy.etuc; import org.joda.time.DateTime; public class PersonService implements IPersonService { @Override public boolean checkConsistency(Person p) { // Trust nobody return true; } @Override public void process(Person p) { // Do whatever is needed (if consistency is checked) } @Override
11 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy public void finalize(Person p) { // Maybe some cleanup ? } public Person createPerson(){ Person p = new Person("Christophe", "Addinquy" , new DateTime(1963, 12, 5, 0, 0, 0)); return p; } }
We have a usage contract of this kind: package com.addinquy.etuc; public class ServiceInvokator { private PersonService ps; public void doStuff() { Person p = ps.createPerson(); if (ps.checkConsistency(p)) { ps.process(p); ps.finalize(p); } } }
An important concern is that process and finalize methods should be called only if checkConsistency return true. The interface offers a not so bad abstraction, but it remains easy to misuse the protocol
Challenge #4: Easy to use correctly and easy to use incorrectly The solution is to wrap the PersonService protocol inside a driver method. This is the Template Method pattern10. In Java, this can no longer be an interface, but an abstract class because of the presence of some code! package com.addinquy.etuc; public abstract class AbstractService { public void doProcess(Person p) { if (checkConsistency(p)) { process(p); finalize(p); } } public abstract boolean checkConsistency(Person p); public abstract void process(Person p); 10
Design Patterns - Erich Gamma, Richard Helm, Ralph Johnson & John Vlissides - Addison Wesley / Professional Computing series 1995 – ISBN : 0-201-63361-2, p. 325
12 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy public abstract void finalize(Person p); }
Of course, the design of the subclass must be changed accordingly: package com.addinquy.etuc; import org.joda.time.DateTime; public class PersonService extends AbstractService { @Override public boolean checkConsistency(Person p) { // Trust nobody return true; } @Override public void process(Person p) { // Do whatever is needed (if consistency is checked) } @Override public void finalize(Person p) { // Maybe some cleanup ? } public Person createPerson(){ Person p = new Person("Christophe", "Addinquy" , new DateTime(1963, 12, 5, 0, 0, 0)); return p; } }
This design is much more confortable and less error prone to use: package com.addinquy.etuc; public class ServiceInvokator { private PersonService ps; public void doStuff() { Person p = ps.createPerson(); ps.doProcess(p); } }
Unfortunately, we’re not done! The design is still leaky: we can still call the primitive methods directly, even if we have the driver method at our disposal. Let’s fix this: package com.addinquy.etuc; public abstract class AbstractService { public void doProcess(Person p) {
13 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy if (checkConsistency(p)) { process(p); finalize(p); } } protected abstract boolean checkConsistency(Person p); protected abstract void process(Person p); protected abstract void finalize(Person p); }
This one is much better. But still, there is one weakness. Something we can do, not from the client side, but from the subclass: public class PersonService extends AbstractService { @Override public void doProcess(Person p) { // gnarf, gnarf ! }
I know, this time it requires bad will! However this leak is easy to fix: package com.addinquy.etuc; public abstract class AbstractService { final public void doProcess(Person p) { if (checkConsistency(p)) { process(p); finalize(p); } } protected abstract boolean checkConsistency(Person p); protected abstract void process(Person p); protected abstract void finalize(Person p); }
The final statement prevents the driver method to be override. And this this time, we’re done!
A safe decoration You are probably familiar with the Decorator pattern11. This construction allows the interception of a service to enhance it. The corresponding UML structure is bellow.
11
Design Patterns - Erich Gamma, Richard Helm, Ralph Johnson & John Vlissides - Addison Wesley / Professional Computing series 1995 – ISBN : 0-201-63361-2, p. 175
14 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy
Figure 7: The Decorator UML representation
When instantiated, the caller to component chain will be structured like that:
Figure 8: Chain of decorators
This time, I won’t bother you with my little tricks and directly provide you my best design. Challenge #5 Here the service interface with its business service exposed: package com.addinquy.etuc; public interface IPersonService { public void process(Person p); }
From the Decorator perspective, we have this superclass: package com.addinquy.etuc; public abstract class AbstractDecorator implements IPersonService { IPersonService ps; AbstractDecorator(IPersonService ps_) { ps = ps_; } @Override final public void process(Person p) { beforeProcess(p); ps.process(p); afterProcess(p); }
15 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy protected void beforeProcess(Person p) { } protected void afterProcess(Person p) { } }
Seriously, I dis my best here. You will recognize: • The RAII idiom: you can’t instantiate a decorator without a decoree. One source of problem dismissed! • The decoration is embedded into a Template Method, there is no confusion about the call of the decoree. Of course the process method can’t be override and you even have the choice to decorate on the call or during the return (or both)! Unfortunately again, there is still perhaps a little leak. Do you remember of the implementation of the Person class before we apply the RAII idiom? If we use this class, there is an opportunity to misuse the design. package com.addinquy.etuc; public class DecoratorSave extends AbstractDecorator{ DecoratorSave(IPersonService ps_) { super(ps_); } protected void beforeProcess(Person p) { p.setFirstName("Toto"); } }
Challenge #5: Easy to use correctly and (almost) easy to use incorrectly We may reduce the risk by using the RAII flavor of the Person class. But it doesn’t mean there is no setter. Unlike C++ where we can use const to make the Person parameter immutable, there is no easy way to make the parameter immutable (final makes the pointer immutable, not the pointee). We would have to perform a complicated design involving a wrapper to tackle the issue. At this point, it’s a question of balance. The overhead of complexity doesn’t worth the issue addressed. I won’t go that way.
A high-level design example: convention over configuration Challenge #6 The Wicket framework manages the behavior of HTML pages elements directly through Java code without any insertion of “non HTML code” in the pages. It works the following way: Start with a classic plain old HTML file.
16 / 27
Easy to use correctly, hard to use incorrectly â&#x20AC;&#x201C; Christophe Addinquy <html> <head> <title>Cheesr - checkout</title> <wicket:link> <link href="style.css" rel="stylesheet" /> </wicket:link> </head> <body> <h1>Cheesr</h1> <form wicket:id="form"> <h3>Check out</h3> <p>Please enter your billing address.</p> <table> <tr> <th>Name</th> <td><input wicket:id="name" type="text" /></td> </tr> <tr> <th>&nbsp;</th> <td><input type="button" wicket:id="cancel" value="Cancel" /> <input type="submit" wicket:id="order" value="Order!" /></td> </tr> </table> </form> </body> </html>
The single taste of Wicket here is the id inserted on elements we want to manage through the Java code. Here the way the Java code handle these elements: public class Checkout extends CheesrPage { public Checkout() { Form form = new Form("form"); add(form); form .add(new TextField("name", new PropertyModel(address, "name")).setRequired(true)); form.add(new Button("order") { @Override public void onSubmit() { Cart cart = getCart(); cart.getCheeses().clear(); setResponsePage(Index.class); } }); add(new ShoppingCartPanel("cart", getCart())); } }
17 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy This simplified Java code reference the fields’ identifiers of the HTML code bellow. However, there are no explicit elements linking the HTML page to the Java class. This is done because both resources share the same file name are located in the same directory12!
Figure 9: Directory structure of a Wicket project
A little mistake in one of the resource name is enough to prevent the code from working, without any notice from the framework or the compiler. On the other hand it makes server-side GUI development tremendously simple!
Challenge #6: Easy to use correctly and easy to use incorrectly There is no workaround on these situations, because the framework is built on this concept. It’s a question of balance and judgment: does the price to pay worth this comfort? My personal answer here is: yes. Just keep it mind that is not a perfect answer.
From design to user interfaces User interfaces can be evaluated in the same way. In the end, we want our user interface to be intuitive; we want to reduce the user adoption friction. In the same time, we don’t want them to be misleading. In one sentence: we want them easy to be use correctly and hard to use incorrectly. Challenge #7 Meet Chiptune! This nice vintage web site (it is a Web site actually) let you do something I still really understand, once you figure out how it works…
12
Wicket in Action – Martijn Dashorst & Eelco Hillenius – Manning 2008 – ISBN: 1932394982 ; EAN: 978 1932394986, p. 15
18 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy
Figure 10: Chiptune
Try it for few minutes. I give you a hint: try the double click (I know, this is HTML…). The bright side is: until now, I was unable to do some damage. Hence the verdict is:
Challenge #7: Hard to use correctly, hard to use incorrectly We can try another one. Challenge #8 SH Marketing is supposed to be a very serious business. Looking at the landing page, it’s hard to tell where to go next!
19 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy
Figure 11: SH Marketing
It turns out that that they “gamified” the home page. You have to chase out the wheels on the left. Some of them will move ahead of the mouse, some others are actually clickable and lead you to SH Marketing divisions. It’s supposed t be fun, like some kind of “kill them all” game where you in fact want to kill SH Marketing past the first minute. At the end of the road, you didn’t kill anything, fortunately. Here again:
Challenge #8: Hard to use correctly, hard to use incorrectly Is it so hard to design something valuable? Challenge #9 Meet Capitaine Train. You can directly book a ticket right from the landing page. This one is also free from distraction, filled with just what’s needed to specify the ticket, letting you choose the remaining options.
20 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy
Figure 12: Capitaine Train
This service is so confident in the user experience it provides that it defies the official railway service based on this only argument! It’s easy, it’s quick and help you avoid mistakes. The verdict is easy.
Challenge #9: Easy to use correctly and hard to use incorrectly
Up to the next level: evaluation of processes Processes or more specifically development processes can be assessed this way too. Perhaps with mixed feelings, as we’ll see.
The Scientific Management Challenge #10
21 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy First things first: the Principles of Scientific Management, also known as “Taylorism” is by many ways the father of all processes13. The principle looks simple.
Figure 13: The principles of the Scientific Management
The management is in charge to study the most efficient way to perform the work at hand. Then the manager establish a recipe of the work decomposition as well as productivity objectives that matches this more efficient way to do this work. The manager is in charge to teach the worker and then to control the productivity. While the system is working, he collects the feedback and may improve the process. This process looks rather simple, even if the careful analysis of the tasks may require some knowledge. However, we shouldn’t miss the basic postulates of Frederick Taylor: • The work to be considered must be simple enough that it can be deterministically decomposed into a successive discrete set of elementary tasks. • The considered worker is “stupid” and can’t know or imagine by himself the way to do his works. • The worker is lazy and tries to work as slow as possible.
13
The Principles of Scientific Management – Frederick Winslow Taylor – ISBN : 9781444432312
22 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy • The basic needs of the worker are low. About the second level of Maslow’s hierarchy of needs, I mean safety. So the compensation these worker expect from their work is basically money. Considering these postulates, we can conclude that, even if the principles of scientific management are simple, it’s very easy to misuse them by ignoring these postulates. In fact that’s what we do today especially with knowledge workers. So we can safely qualify this one:
Challenge #10: Easy to use correctly, easy to use incorrectly Unified process Challenge #11 Fast forward, before the agile processes. The unified process is a classic iterative process but less deterministic and mechanical than Scientific Management. It looks like that.
Figure 14: Unified Process
The unified process is a framework can be seen from 2 viewpoints: The project management frame14: • The vertical axis show a set of 9 disciplines, by mean of domain of practices such as requirements management, design, tests, etc. • The horizontal axis outline the 4 main phases inside which we practice iterative development. The process itself15 can also be decomposed in a set of concept: 14
Software Project Management: A Unified Framework - Walker Royce - Addison Wesley 1998 ISBN: 0-201-30958-0 15 The Rational Unified Process, an introduction, third edition – Philippe Kruchten – Addison Wesley / O.T. series 2004
23 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy • The workflows are large bodies of work with their own lifecycles. Each workflow is described through a set of tasks ordered in a given way. Each workflow belongs to a given discipline. Some workflows are dedicated to specific phases while some others can be considered during the entire project. • The tasks are the elementary unite of work. They are described using some kind of recipes (yes, it looks like Scientific Management at this point in time). Each task involves an actor and produce or enhances an artifact. • The actors are roles played by the project crew. A given role can be hold by several project members, while a given member can play several roles depending the tasks he is in charge. • The artifacts are the outcomes (final or intermediate) of the project. The result from tasks that are performed by actor. Unified Process describes a very large set of workflows, tasks, actors and artifacts in order to cover all possible kinds of software projects. Because everything is not needed for all projects, Unified Process relies on a “process engineer” to tailor the process and keep what’s needed in the given context! However, it’s a natural bias to try to play on the safe side and keep to many stuff in the process “just in case”… Unified Process looks smart but complicated. It’s hard to understand and therefore to follow. And it’s hard to tailor it as well.
Challenge #11: Hard to use correctly, easy to use incorrectly Extreme Programming At the end of the nineties, came the agile methods. The first to emerge was Extreme Programming. Let’s investigate Challenge #12 Extreme Programming16 is most of time described by a set of 13 interconnected practices.
16
Extreme Programming Explained: Embrace change, 2nd edition – Kent Beck & Cynthia Andres – Addison Wesley / XP series 2004 – ISBN: 0-321-27865-8
24 / 27
Easy to use correctly, hard to use incorrectly â&#x20AC;&#x201C; Christophe Addinquy
Figure 15: Extreme Programming practices
Much less known, there are also 5 values and 4 principles, just like the agile manifesto.
Figure 16: XP values and principles
Kent Beck attitude toward Extreme Programming is very simple: all the practices must be applied all the time. Itâ&#x20AC;&#x2122;s quite challenging to do, but the contract is also quite simple.
Challenge #12: Hard to use correctly, hard to use incorrectly 25 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy
Scrum Challenge #13 Today, the standard meaning about doing an agile project is performing Scrum. The Scrum framework is pretty simple.
Figure 17: The Scrum cycle
The key factor of Scrum success is probably its simplicity17: 2 artifacts, 3 cycles, 3 roles and one outcome. That’ it! But behind this apparent simplicity, we observe today a broad range of “agile compliancy” for Scrum project. I even not mention project that claim to follow Scrum where in fact they just rename their old practices with the Scrum vocabulary! What happened? The Scrum framework is in fact like empty shelves. It’s both its strength and its weakness. This is strength, because it makes the process easy to handle18. That’s one of the main adoptions reasons. Scrum doesn’t lock you also with a fixed set of practices, but invite you to choose the ones that fits your context or your maturity level. It’s a great room for improvement. However, by lacking mandatory practices, Scrum make easy to pretend agility without any quality practices such as TDD, refactoring or even continuous integration. The conclusion is inevitable: 17
Essential Scrum, A practical guide to the most popular agile process – Kenneth S. Rubin – Addison Wesley / Signature series 2013 – ISBN : 978 0 13 704329 3, p. 15 18 Scrum in five minutes : http://freethinker.addinq.uy/post/70331188510/la-gallerie-de-mesphotos-de-lagile-tour
26 / 27
Easy to use correctly, hard to use incorrectly – Christophe Addinquy
Challenge #13: (almost) easy to use correctly, easy to use incorrectly
Conclusions Meyer’s rule on the product In the first part of the article, we’ve seen that the rule can be applied and help us at all levels: • • • • •
Coding practices Language evaluation Design Architecture User interfaces
We could even found other spots where this rule could be applied19. But I think you understand the basic idea.
Meyer’s rule on processes Things that work on product don’t apply in the same way on people. Dealing with people is dealing with complex systems. In this way, Meyer’s rule doesn’t qualify a process as “good” or “bad”. It’s more a way to draw our attention on difficulties to deploy the process and/or possibilities to get misuses.
19
The presentation support for Agile Tour Brussels: http://freethinker.addinq.uy/post/65939644176/facile-a-bien-utiliser-difficile-a-mal-utiliser-la
27 / 27