18

I often find myself embracing "now is better than never" when I'm advancing the DRYness of a design. Typically, I find that I need to cultivate an understanding of the One Authoritative Location for a piece of knowledge in the context of a system of other pieces of knowledge. Thus, I tend to design the system 'now.'

Conversely, this practice causes me to build fairly far in advance, despite a reasonable chance that I ain't Gonna Need It.

How do these two patterns square up?

What practices do you use to ensure that they play nice?

How do you teach them together without creating confusion?

1
  • 2
    Look before you leap. But he who hesitates is lost.
    – mmyers
    Apr 27, 2011 at 16:22

8 Answers 8

27

I try to think far ahead too, but usually not in code. I brainstorm and take notes, hopefully organizing things well enough so that I can refer back to them.

I lean more towards "you ain't gonna need it" with respect to code, but "now is better than never" with design.

When starting off building a new system it is tempting to want to build everything now, but it can also sap your momentum and morale. I tend to think about the overall design and try to draw a direct line through it -- come up with an end-to-end skeletal architecture and build that first, applying sound design principles so that I can later evolve it and refactor to bring in new features.

Build the simplest end-to-end representation of the system that can work; do that first, and then you have something to reflect on. That tends to help crystalize all those vague "what if" questions and help you nail down what you need to build next.

1
  • 3
    +1 leaving a place for something in the design does not mean you have to build much of it out initially. WAY too many people get on a absolutist kick that nothing should be considered before request and leave themselves in a situation much worse than if they had built the whole thing with no customer input whatsoever.
    – Bill
    Apr 27, 2011 at 18:29
10

YAGNI means things get done when they need to get done and not before. It doesn't mean they never get done, not unless they are never needed. It means you only do what gives the customer immediate business value. What immediate business value means is subjective to every customer and every project.

In either case, you can't lose anything with YAGNI.

In the other case, you lose time writing code that never gets used, and writing tests for code that never gets used, and writing documentation for code that never gets used, and maintenance on code that never gets used, people wondering what this code does, and if it ever gets used, ad nauseum.

Example

If I am working on a prototype/proof of concept or 1.0 version of an application then I don't need a design to scale to level of Facebook. Hell I don't need a design to scale to the level of Facebook, until I start seeing that I have that kind of traffic.

Do you think Zuckerberg designed the very first version of Facebook to scale to 500 Million users? No, he designed and built it to do just want it needed to do and no more. If he had tried to waterfall the design for 500 Million users from day one, Facebook probably would have never been released period.

The practical way to do things is how he did it. He started out with PHP and MySQL, and the redesigned and rewrote as needed based on business value, scaling to millions of users was of tremendous business value, but not at day 0. At day 0 just launching something was the tremendous business value.

He planned on redesigning and rewriting. Which is a different mindset than planning for the kitchen sink and never actually developing or delivering anything useful that is complete.

Planning on end of life for a code base, and rewrites is Agile and future proof. Trying to come up with some undefined goal of "flexible" just ends in failure every time. You are designing without any need and wasting time you could be developing what is of business value instead of wishful dreaming about features that will never be used.

2
  • 2
    If your design is bad (e.g. inflexible) you can lose a lot with YAGNI. Apr 27, 2011 at 17:01
  • 1
    @EricSchaefer - not if it meets the goals and provides value to the business and you don't have a lot of time invested, you just throw it out less is lost than never delivering your magical infinitely flexible system that will never be complete and ship and if it does, it will be a configuration nightmare.
    – user7519
    Jun 28, 2011 at 15:54
6

The Zen of Python way says :

Now is better than never. Although never is often better than right now.

The idea is that it's not because you can define something now that you should. Do you need it now?

  • Yes : do it now!
  • No : don't do it! Wait for the need! YAGNI!

The cases where this is less obvious is in refactoring cases. Should I apply DRY every time I can? The answer isn't clear because there are times where applying DRY costs more (in time spent) than duplication. However, on the long term, applying DRY until you have technical/performance reasons to not is always good.

So, YAGNI until you do, then DO IT NOW. Don't Wait!

3

I don't think they play together at all. I think you either lean one way or the other. And I lean towards YAGNI.

But for what it's worth, I don't agree with the second proposal, that "Now is better than never." If a requirement is important, than it will have to get done. So "never" is not a possibility. If it is not important, than "now" is not better -- "never' is better.

Just my two cents.

6
  • And now the million-dollar question: What does "important" mean?
    – Aaronaught
    Apr 27, 2011 at 16:41
  • 1
    "Important" means it is an acceptance test.
    – kindall
    Apr 27, 2011 at 16:52
  • 2
    Important means the client doesn't pay if it isn't there. Apr 27, 2011 at 17:31
  • 1
    @Christopher, that could be interpreted as encouraging unprofessionalism. E.g. protecting against SQL injection is important even if the client wouldn't know what it is and certainly won't test for it before paying. Apr 27, 2011 at 19:14
  • 1
    A sophisticated customer will make it important. This is why many customers balk at my quotes. They say: Why do I need all that stuff when I can get it done in 1/4 the price at Rent-A-Coder? I tell them: "Good Luck, you'll need it."... The other reason I put the sql injection protection and all the other stuff is that I don't want to get frantic phone calls about how the database is all corrupted and there's no backups; "Oh my God it's all your fault what are we going to dooooooo!!!!" screaming contests. [/bitter_experience] Apr 27, 2011 at 19:51
3

If "never" is the implication of "not now", then your design is flawed.

Local decisions you make should be transparent to the rest of a system.
For example, if you have a component CookieSource, that requires a CookieFactory to turn the CookieRecipes it knows into Cookies, based on some input parameters of yours, then CookieSource need not and thereby must not depend on how CookieFactory is implemented and how CookieRecipes are represented.
If the CookieFactory is in fact a Bakery, that can take any Recipe into according Pastry shouldn't matter. And unless you need that functionality, there is no need to implement it. And there is no reason in the world why you can't add it afterward, except if there is no clear abstraction barrier between CookieSource and the services it uses.

When building software, add functionality as needed and try not to lock yourself into any decisions you make. Instead lock the decision into a suitable abstraction.

2

The simplest solution I found is to expect changes when writing code up front. When I'm passing some bool to a function, I typically change it as soon as possible to a flag/enums so it's a) more readable and b) easy to extend. Similar, if I notice that I'm passing a bunch of parameters around where it smells like I'll need one more, I typically create a special structure. The hope is that YAGNI it, but if you do at some point, it won't break all users horribly right away and the "grunt work" is already done. Often enough, you can also just add some comment like /* future additions go in here */ or so so it's clear that it's not implemented yet but here's the place to add it. That usually helps the most, as I found interface refactoring later on to be most time-consuming.

2
  • I like this philosophy in principle, but in practice I find that migrations are painful enough to make me think twice. Do you ever find that migrating your models stands in the way of expecting changes? Apr 27, 2011 at 16:28
  • The good thing about this approach is that changes are less painful; there's still lot of work involved. I'm not sure what you mean with migrating models -- I'm definitely on the YAGNI side, but I prepare for the worst :)
    – Anteru
    Apr 27, 2011 at 17:04
2

How do these two patterns square up?

They're orthogonal and have nothing to do with each other.

What practices do you use to ensure that they play nice?

Um. Do them both? What more can there be?

How do you teach them together without creating confusion?

YAGNI describes features as seen by the users. You don't need fancy.

Now is better than never describes the process. Write tests now. Write code now. Don't while away the hours contemplating design alternatives. Build something rather than talk about building something.

1

Design with future extensions in mind, but don't implement those extensions until you need them.

The example that springs to mind is when Netflix first started, you could only have one queue associated with each account. They later hacked on support for multiple queues. Because it wasn't designed that way from the beginning, it became more and more difficult to maintain, so they decided to discontinue that feature. After a customer uproar, they bit the bullet and did a redesign to integrate multiple queues properly.

If someone at the beginning had allowed for the possibility that they might want multiple queues later, they could have saved themselves a lot of long term grief for very little additional short term effort. They didn't have to actually implement multiple queues right away, just make sure if they ever did it wouldn't require a massive rewrite or unmaintainable hack.

On the surface, it seems like it would require a fortune teller-like ability to predict future requirements, but in practice things like that tend to stick out to a good programmer when he notices he is hard-coding something, or that a database table is collecting a lot of only vaguely related columns.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.