Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I'm not really a fan of the story-point example. The article begins with:

> it’s something that you get when you delay design decisions for later

But then presents us with a problem where we can "spend" 21 story points now, knowing we won't have to do much refactoring later. How do we know this? I thought the whole point was we couldn't see enough of the picture to make a stable design.

Instead of talking about how patches, hacks, and workarounds impact code, I'd like to see discussion on how you move forward when you know the requirements are going to change, but don't know how.



If you implement a robust permissioning system that has permissions related to group membership and one-off permissions related to a single user then MOST of your problems are solved. Nearly all new permission requirements can then be made without touching the code at all, or in more than a couple of places.

The idea is to choose a new design that scales better. If you have M permissions and N permission checks then each new requirement might cause M * N changes to the codebase.

If you have a reasonable permission system you might end up having to make N changes to the codebase (worst-case) or perhaps only M modifications to permissions or perhaps both. But in that case it's M + N changes, rather than M * N. For any values of M and N greater than 2 (and very nearly all of them will be) M + N is smaller than M * N.


The issue I deal with isn't in choosing a design that scales better, it is uncertainty in how things will scale. Say I need to handle group permissions depending on the context. I could hard-code the permissions changes for the one group that needs it now, or I could abstract and generalize context-switching behavior into its own component, ensuring changes to future groups will be easy and low-cost.

But, what if I never get a second group that needs this? While hard-coding values was an ugly shortcut, I may never have a need to revisit the code. If I had gone with a generalized solution, I'd still have to contend with maintaining all that code.


That's an interesting point. Here's my take:

If you ask someone who knows about the business rules if something could EVER happen and they say "no" they're probably wrong, but not maliciously so. Be cautious when taking their word for something. Even if the CEO signs off on the idea of "such and such never needs to be able to do x, y or z" the second a big contract does need it, it all goes out the window.

As a result whenever possible choose solutions that give you SOME flexibility without necessarily creating a supremely robust, exhaustive module.

In this particular case, once you realize that you're going to have more in the way of permissions other than global can/can't do, it's time to be smart. Being smart might only mean creating a function which takes some context like userid and "permissions token" and/or the URL that the person is visiting and then doing a hardcoded permissions check for say one of a dozen userids who are basically root versus everyone else who isn't.

Yes you didn't make a giant scalable system of awesomeness including a web-based permission editor. But you did make a function you can insert every time a new permission item gets created and eventually a system could be created for storing those in the database such that users can eventually be mapped to permissions also in the database.

So if you want to hard-code those values into a single page, which then grows into two pages, which then grows into four pages which then grows into 29 pages that's the wrong solution. But if you want to hardcode those into a function which you then call, that's a good enough solution for now that doesn't hobble you later. Putting the function call in adds very minimal overhead in terms of execution and ranges from slightly negative to moderately positive on maintainability.

Parts of software development are similar to being a speculator in a financial market. You need to have a fairly intuitive grasp of what's going to be a "good bet" for spending a little more time now which has the potential to pay off big in the future.


"I'd like to see discussion on how you move forward when you know the requirements are going to change, but don't know how"

I've found requirements do not change nearly as often as you would think. Only maybe 10% of the changes I make come from a requirements change.

Take for instance the articles permissions example. Is that a change in requirements or a lack of understanding the requirements and domain?

Sometimes it is a genuine requirements change. Maybe the company has recently adopted a new security policy, or maybe you are selling to a new customer and they require permissions even though none of your existing customers do etc. More often than not though the requirement has always existed but the dev team didn't know about it or didn't have time to deal with it.


In my line of work, either I'm building a new component, or I'm dealing with requirements change. So dealing with the shifting sands of what the system should do is a major concern.

Requirements come and go for me. And losing requirements can be just as disruptive as getting them. Worried about how component X will handle users? Well, we don't ship component X anymore, so any refactoring work you've done is wasted.

I might be the odd one out with requirements changing all the time, but I don't get the choice between good design and fast design. I have to creep forward in my architecture, like I'm fumbling around in the dark, because what my system should do today may not hold until tomorrow.


"In my line of work, either I'm building a new component, or I'm dealing with requirements change. So dealing with the shifting sands of what the system should do is a major concern."

And that is simply the case with certain lines of work.

To help me determine which requirements changes are simply a failure in the requirements process I ask myself:

"If I had shipped feature X a month ago would it have had business value?"

If the answer is no then I'm likely dealing with a legitimate requirements change.

For example: If I worked in the tax industry and the government changes tax laws then shipping these changes months before would not deliver any business value.

Or if I have to make a requirements change because of an external dependency changing. No extra value.


Sounds like you have a good idea of what I'm on about. Still leaves me searching for a way to deal with my system.

Take your tax-software example. You need to start work before the law is written, but there could be changes in the law that require a rework of business logic. What do you work on? How do you prioritize? And how do you deal with that subsystem that no longer has a reason to exist?

In my domain, technical debt is not really a choice I make. It is something that happens as the system ages. I wish I could get someone to speak to that.


In the case of the tax software there's a big question I have:

Do you have a rules engine already or not?

If you're hodge-podging it all together and all the rules are implicitly defined by the code as it exists you're in a bad spot. Knowing that the rules will change every year your goal isn't to grind out this year's changes really hard for six months (and then even harder for another moth to change the final changes) and then slack off for five months.

Instead you should implement a system such that the specifics of the changes are captured in the rules. Once the new drafts come out you need to look for what all the possible new rule categories are, what additional data needs to be captured, etc. But then once things are finalized it's a matter of tweaking the rules slightly to capture the final wording of the bill.

This may not be something that applies to you, though. What area do you work in? How does the debt pile up without choices being made?


I work in government contracts, so your example of complying with the tax code was oddly relevant.

There are plenty of places that follow along your example: I can build a general solution that will withstand a wide range of changes. This doesn't change the fact that a change could come along that I didn't anticipate. What I would call "debt" is more the result of changes in requirements than choices the team made.

You can still frame dealing with change as classic "technical debt", except the full cost/benefit of each design can't be well known. Instead it looks more like "technical investment"; you try make a design that will pay off, but you don't have a guarantee that it will.

I find myself hedging a lot of my designs, and rarely am I able to justify spending a lot of time up front on any architecture.


"I thought the whole point was we couldn't see enough of the picture to make a stable design."

While still technical debt it is not the type the article is talking about or using in the example.

FTA: "At this point the developers realize that the code is starting to get messy and the solution is refactoring it to have a decent permission system."

I.e. You are at the point where you realise you need a better design and know the rough solution. Do you keep putting band aids on your solution or do you properly refactor?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: