Sign in to follow this  
  • entries
  • comments
  • views

The "what if?" mantra (aka YAGNI)

Sign in to follow this  


Thank you to Fruny for pointing out that this has already been defined as YAGNI and a example is BigDesignUpFront, both part of Extreme Programming. I'm not gonna delete this journal entry though, took to long to write :P

Any comments on this type of journal posts are more than welcome! I might make some more (and change the F'in Singleton post) if you like this one...


The "what if?" mantra (aka YAGNI) is a anti-design mentality that occurs when you're either to inexperienced with a piece of functionality or just to lazy to design it correctly, thus giving a part of your code more data than it needs. It can also occure when you're trying to hard, just writing code without an actual use for it.


Some symptoms are:

  1. Your class has so many functions it looks like Java: your class has every possible function you could think of, "just in case you need it".

  2. Your function takes so many parameters it looks like Win32 API: your function has one parameter for every variable you can pass it, "maybe some could be used for something".

  3. You're using the F'in Singleton Pattern or F'in Globals (same principle): by making everything singletons/globals you're infecting every piece of your code and all that it touches with symptom nr 2 since now everything can get ahold of all possible data variables you've created. This symptom often leads to Singletonitis.


Some examples on how "what if" thinking destroys your design.

  1. The Java String class has 11 constructors and 65 public methods.
    Because, you know, "What if we want to 'return a canonical representation for the string object'?".
    Don't try to do everything with your class, just do what it was created for: to fill some function in your design. If you notice you "have to" write alot of functions for your class, ponder if some of them can be done outside the class or if they belong to a group of functions you can put in a manipulator class/namespace.

  2. draw_vertices(scenegraph, renderer, vertex_buffer, uv_buffer, attrib_buffer, color_buffer, index_buffer, index_count, bool key_ptrssed, mouse_state, list_of_other_device_states, bool use_vbo);
    Why does the rendering function need to know key and mouse states? Probably because the author thought "What if the rendering should be cancelled if I hold down shift?".
    Don't just throw around responsabilites. Let the renderer render and the scene manager manage the scene, what input does should be completely separate from how the current state is rendered.

  3. Renderer::getInstance()
    A F'in Singleton Pattern if I ever saw one! The author might've thought "What if the AI wants to render a red dot where the NPCs are headed?".
    The game loop can be pretty complicated and you don't want to make matters worse by allowing everyone to change the renderstate and render random stuff at any time. There's a time for updating the game world and there's a time for it to be represented on screen. The logic is separated and so should the code be.


This was spawned by my post in the Singleton Class Cluster thread:

Original post by swiftcoder
...that game loop you showed, obviously the game loop holds the scene-graph, input, etc. And equally obviously it passes pointers to them through to each task (or whatever) that needs them. So give me one concrete reason why this is better having each task retrieve the pointer when and if it needs it from a global? (and 'bad design' is not an acceptable reason)

Because each function should do one thing and do it well. This means that if the function needs something to do it's job (and to do it well) then the function should be given it, and that is what function parameters are for. By making a bunch of F'in Singletons and designing with the "what if?" mantra will make a very confusing function that may or may not change the state of, say, the renderer. If a function doesn't need the input device, why should it be given it? If the AI needs map data from the scene graph, give it to him but don't give him every possible thing in your entire engine because of "what if?". Because that's what you do with F'in Singletons, you say to your entire system (every last piece of code no matter where it might hide): "Would you like some fries with that?". I hope that the "what if?" mantra shines with it's lack of design. Design is about defining a working system, something that should not be thrown away because your not sure if a function should do 1 or 100 things. Do one thing and do it well, and help the function stay that way with clearly defined parameters.


There are four methologies that work in perfect harmony against the "what if?".

Lazy coding
The best cure is actually to be lazy. Although, lazy in a good way of course. That means only code what you need, when you need it. Don't code every possible function you can think of, code the ones you need right now and move on. Don't go around writing functions without clearly needing them, because then you risk that you start filling them with arguments they might or might not need. And you also risk making functions you might or might not need because you don't really know how the class will be used.

? More Effective C++, Scott Meyers
? Code Complete, 2nd edition, Steve McConnell

Refactoring is a good way to get clean functions, when you see code duplication: move out that section of code and only add the function parameters that's needed to make the thing compile and run. This results in functions that are truly needed and that doesn't take more prameters than needed.

? Test-Driven Development: By example, Kent Beck
? Refactoring your tests..., Washu
? Refactoring, Part 1 | Part 2 | Part 3 and 4, Washu

Test-Driven Development
By writing tests first you not only assure that your functions actually behave the way you want, but you design from a "users point of view" which often is different from a "implementors point of view". Do you like using Win 32 API? Do you like having to create 20 variables/structures before you even call a function? My guess is that you don't. Even more so, you don't want to write tests that are useless. And writing tests - that requires you to make them work by implementing the needed classes/functions - just so that it won't be used isn't very productive nor is it any fun.

? Test-Driven Development: By example, Kent Beck
? Are Your Tests Foolproof?, Washu

Minimal scope
Most C++ programmers agree that you should create your objects as close to the using code as possible. There are several benefits for this, but this doesn't not concern us now. A side-step to this thought is to minimize the use scope, note that this doesn't necesserely mean the same as live-time. Try to keep a variables visibility-scope as minimal as possible. To give you an idea, a global variable has the maximal scope. The key implementation "trick" here is to start with the smallest scope possible and expand on need, but only if you really really need to and with the smallest possible step as possible. If you start from the wrong end of the banana then you'll notice that creating a global suddenly makes you use it all over the place, making it non-global will be a pain I would only wish upon my most hated enemies. But eating from the right end and never eating more than you need to, will most definitly not make the object a global.

? Code Complete, 2nd edition, Steve McConnell
Sign in to follow this  


Recommended Comments

Hope you liked it ^_^
I'm thinking of doing some of these sometimes, when I'm lurking on the forums and remembering how it was when I started out programming.

Share this comment

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now