Software requirements change, and there's not much one can do about that except for more frequent interaction with clients.
One can, however, build code that is more robust in face of change. It won't save you from throwing out code that meets a requirement that nobody needs anymore, but it can reduce the impact of such changes.
For example, whenever this applies, use interfaces rather than classes (or the equivalent in your language), and avoid adding operations to the interface unless you are absolutely sure you need them. By building your programs that way you are less likely to rely on knowledge of a specific implementation, and you're less likely to implement things that you would not need.
Another advantage of this approach is that you can easily swap one implementation for another. For example, it sometimes pays off to write the dumbest (in efficiency) but the fastest to write and test implementation for your prototype, and only replace it with something smarter in the end when the prototype is the basis of the product and the performance actually matters. I find that this is a very effective way to avoid premature optimizations, and thus throwing away stuff.
Take the time to keep communication open with the customer that your building the product for. Make milestones and setup a time to display the project to the customer at each milestone. Even if the customer is completely disappointed with a milestone when you show it, you can scratch what you have and start over from the last milestone. This also requires that your work be built in blocks that work independent of one another as Csunwold stated.
Points...
Keep open communication
Be open and honest with progress of product
Be willing to change daily as to the needs of the customers business and specifications for the product change.
Modularize. Make small blocks of code that do their job well. However, thats only the beginning. Its usually a large combination of factors that contribute to code so bad it needs a complete rework. Everything from highly unstable requirements, poor design, lack of code ownership, the list goes on and on.
Adding on to what others have brought up: COMMUNICATION. Communication between you and the customer, you and management, you and the other developers, you and your QA department, communication between everyone is key. Make sure management understands reasonable timeframes and make sure both you and the customer understand exactly what it is that your building.
modularity is the answer, as has been said. but it can be a hard answer to use in practice. i suggest focussing on:
small libraries which do predefined things well
minimal dependencies between modules
writing interfaces first is a good way to achieve both of these (with interfaces used for the dependencies). writing tests next, against the interfaces, before the code is written, often highlights design choices which are un-modular.
i don't know whether your app is UI-intensive; that can make it more difficult to be modular. it's still usually worth the effort, but if not then assume that it will be thrown away before long and follow the iceberg principle, that 90% of the work is not tied to the UI and so easier to keep modular.
finally, i recommend "the pragmatic programmer" by andrew hunt and dave thomas as full of tips. my personal favourite is DRY -- "don't repeat yourself" -- any code which says the same thing twice smells.
get a simple working product out asap so the client can give input.
Basically assume stuff WILL get thrown out, so code appropriately, and don't get far enough into something that having it be thrown out costs a lot of time.
Looking through the other answers here I notice that everyone is mentioning what to do for your next project.
One thing that seems to be missing though is having a washup to find out why the spec. was out of sync. with the actual requirements needed by the customer.
I'm just worried that if you don't do this, no matter what approach you are taking to implementing your next project, if you've still got that mismatch between actual requirements and the spec. for your next project then you'll once again be in the same situation.
It might be something as simple as bad communication or maybe customer requirement creep.
But at least if you know the cause and you can try and help minimise the chances of it happening again.
Not knocking what other answers are saying and there's some great stuff there, but please learn from what happened so that you're not condemned to repeat it.
Like csunwold said, modularizing your code is very important. Write it so that if one piece falls prone to errors, it doesn't muck up the rest of the system. This way, you can debug a single buggy section while being able to safely rely on the rest.
Beyond this, documentation is key. If your code is neatly and clearly annotated, reworking it in the future will be infinitely easier for you or whoever happens to be debugging.
Using source control can be helpful too. If you find a piece of code doesn't work properly, there's always the opportunity to revert back to a past robust iteration.
有时重写是最好的解决方案! 如果您正在为相机编写软件,您可以假设下一个版本也将执行视频、立体视频或 3D 激光扫描,并包含所有这些功能的所有挂钩,或者您可以编写这样一个多功能可扩展的宇航员架构,它可以应对包括喷气发动机在内的下一代相机 - 但这将花费大量金钱、资源和性能,因此您最好不要这样做。
对新角色中的新功能进行完全重写并不总是一个坏主意。
Sometimes a rewrite is the best solution! If you are writing software for a camera, you could assume that the next version will also do video, or stereo video or 3d laser scanning and include all hooks for all this functionality, or you could write such a versatile extensible astronaut architecture that it could cope with the next camera including jet engines - but it will cost so much in money, resources and performance that you might have been better off not doing it.
A complete rewrite for new functionality in a new role isn't always a bad idea.
基本上,我会尝试预测软件的走向,但更重要的是,我抵制住实现任何我能想象到的事情的诱惑。 我所追求的只是在不实现这些功能的情况下尝试让 API 和接口支持可能的未来,希望这些“可能的场景”帮助我想出一个更好、更面向未来的接口。
当然并不总是有效。
Although it doesn't directly apply to your example, when writing code I try to keep an eye out for ways in which I can see the software evolving in the future.
Basically I try to anticipate where the software will go, but critically, I resist the temptation to implement any of the things I can imagine happening. All I am after is trying to make the APIs and interfaces support possible futures without implementing those features yet, in the hope that these 'possible scenarios' help me come up with a better and more future-proof interface.
发布评论
评论(9)
软件需求发生变化,除了与客户更频繁的交互之外,我们对此无能为力。
然而,我们可以构建在面对变化时更加健壮的代码。 它不会让您避免丢弃满足不再需要的要求的代码,但它可以减少此类更改的影响。
例如,只要适用,请使用接口而不是类(或您语言中的等效项),并避免向接口添加操作,除非您绝对确定需要它们。 通过以这种方式构建程序,您不太可能依赖特定实现的知识,并且不太可能实现不需要的东西。
这种方法的另一个优点是您可以轻松地将一种实现替换为另一种实现。 例如,有时为原型编写最愚蠢(在效率上)但编写和测试最快的实现是值得的,只有当原型是产品和性能的基础时,最后才用更聪明的东西替换它很重要。 我发现这是一种非常有效的方法,可以避免过早优化,从而避免丢弃东西。
Software requirements change, and there's not much one can do about that except for more frequent interaction with clients.
One can, however, build code that is more robust in face of change. It won't save you from throwing out code that meets a requirement that nobody needs anymore, but it can reduce the impact of such changes.
For example, whenever this applies, use interfaces rather than classes (or the equivalent in your language), and avoid adding operations to the interface unless you are absolutely sure you need them. By building your programs that way you are less likely to rely on knowledge of a specific implementation, and you're less likely to implement things that you would not need.
Another advantage of this approach is that you can easily swap one implementation for another. For example, it sometimes pays off to write the dumbest (in efficiency) but the fastest to write and test implementation for your prototype, and only replace it with something smarter in the end when the prototype is the basis of the product and the performance actually matters. I find that this is a very effective way to avoid premature optimizations, and thus throwing away stuff.
花时间与您构建产品的客户保持畅通的沟通。 制定里程碑并设置一个时间,在每个里程碑向客户展示项目。 即使客户在展示里程碑时对它完全失望,您也可以从头开始,从上一个里程碑开始。 正如 Csunwold 所说,这还要求您的工作构建在彼此独立工作的块中。
要点...
Take the time to keep communication open with the customer that your building the product for. Make milestones and setup a time to display the project to the customer at each milestone. Even if the customer is completely disappointed with a milestone when you show it, you can scratch what you have and start over from the last milestone. This also requires that your work be built in blocks that work independent of one another as Csunwold stated.
Points...
模块化。 编写能够很好地完成工作的小代码块。 然而,这仅仅是开始。 通常是多种因素的组合导致代码如此糟糕以至于需要彻底返工。 从高度不稳定的需求、糟糕的设计、缺乏代码所有权,这样的例子不胜枚举。
添加其他人提出的内容:沟通。
你和客户、你和管理层、你和其他开发人员、你和 QA 部门之间的沟通,每个人之间的沟通是关键。 确保管理层了解合理的时间框架,并确保您和客户都准确了解您的建筑是什么。
Modularize. Make small blocks of code that do their job well. However, thats only the beginning. Its usually a large combination of factors that contribute to code so bad it needs a complete rework. Everything from highly unstable requirements, poor design, lack of code ownership, the list goes on and on.
Adding on to what others have brought up: COMMUNICATION.
Communication between you and the customer, you and management, you and the other developers, you and your QA department, communication between everyone is key. Make sure management understands reasonable timeframes and make sure both you and the customer understand exactly what it is that your building.
正如前面所说,模块化就是答案。 但这可能是一个很难在实践中使用的答案。
我建议重点关注:
首先编写接口是实现这两个目标的好方法(使用用于依赖关系的接口)。 接下来,在编写代码之前针对接口编写测试,通常会突出显示非模块化的设计选择。
我不知道你的应用程序是否是 UI 密集型的; 这会使模块化变得更加困难。 它通常仍然值得付出努力,但如果不是,那么假设它不久就会被丢弃并遵循冰山原则,即 90% 的工作不与 UI 绑定,因此更容易保持模块化。
最后,我推荐安德鲁·亨特和戴夫·托马斯写的《务实的程序员》,里面充满了技巧。 我个人最喜欢的是 DRY——“不要重复自己”——任何重复同一件事的代码都会有味道。
modularity is the answer, as has been said. but it can be a hard answer to use in practice.
i suggest focussing on:
writing interfaces first is a good way to achieve both of these (with interfaces used for the dependencies). writing tests next, against the interfaces, before the code is written, often highlights design choices which are un-modular.
i don't know whether your app is UI-intensive; that can make it more difficult to be modular. it's still usually worth the effort, but if not then assume that it will be thrown away before long and follow the iceberg principle, that 90% of the work is not tied to the UI and so easier to keep modular.
finally, i recommend "the pragmatic programmer" by andrew hunt and dave thomas as full of tips. my personal favourite is DRY -- "don't repeat yourself" -- any code which says the same thing twice smells.
小规模迭代
经常迭代
迭代之间进行测试
尽快得到一个简单的工作产品,以便客户可以给出输入。
基本上假设东西会被扔掉,所以要适当地编码,并且不要深入研究那些被扔掉会花费大量时间的东西。
iterate small
iterate often
test between iterations
get a simple working product out asap so the client can give input.
Basically assume stuff WILL get thrown out, so code appropriately, and don't get far enough into something that having it be thrown out costs a lot of time.
你好,
浏览这里的其他答案,我注意到每个人都在提到你的下一个项目要做什么。
但似乎缺少的一件事是进行彻底的清理以找出规范的原因。 不同步。 并结合客户实际需求。
我只是担心,如果你不这样做,无论你采取什么方法来实施你的下一个项目,如果你仍然存在实际需求和规范之间的不匹配。 对于您的下一个项目,您将再次处于相同的情况。
这可能是一些简单的事情,比如沟通不畅,或者客户需求的变化。
但至少如果您知道原因,并且可以尝试帮助最大程度地减少再次发生这种情况的可能性。
不要敲打其他答案所说的内容,那里有一些很棒的东西,但请从发生的事情中吸取教训,这样你就不会注定要重复它。
HTH
欢呼,
G'day,
Looking through the other answers here I notice that everyone is mentioning what to do for your next project.
One thing that seems to be missing though is having a washup to find out why the spec. was out of sync. with the actual requirements needed by the customer.
I'm just worried that if you don't do this, no matter what approach you are taking to implementing your next project, if you've still got that mismatch between actual requirements and the spec. for your next project then you'll once again be in the same situation.
It might be something as simple as bad communication or maybe customer requirement creep.
But at least if you know the cause and you can try and help minimise the chances of it happening again.
Not knocking what other answers are saying and there's some great stuff there, but please learn from what happened so that you're not condemned to repeat it.
HTH
cheers,
正如 csunwold 所说,模块化代码非常重要。 编写它时,如果其中一个部分容易出错,就不会弄乱系统的其余部分。 这样,您可以调试单个有问题的部分,同时能够安全地依赖其余部分。
除此之外,文档是关键。 如果你的代码有整齐、清晰的注释,那么对于你或任何正在调试的人来说,将来重新编写它将会变得更加容易。
使用源代码管理也很有帮助。 如果您发现一段代码无法正常工作,总是有机会恢复到过去的稳健迭代。
Like csunwold said, modularizing your code is very important. Write it so that if one piece falls prone to errors, it doesn't muck up the rest of the system. This way, you can debug a single buggy section while being able to safely rely on the rest.
Beyond this, documentation is key. If your code is neatly and clearly annotated, reworking it in the future will be infinitely easier for you or whoever happens to be debugging.
Using source control can be helpful too. If you find a piece of code doesn't work properly, there's always the opportunity to revert back to a past robust iteration.
有时重写是最好的解决方案!
如果您正在为相机编写软件,您可以假设下一个版本也将执行视频、立体视频或 3D 激光扫描,并包含所有这些功能的所有挂钩,或者您可以编写这样一个多功能可扩展的宇航员架构,它可以应对包括喷气发动机在内的下一代相机 - 但这将花费大量金钱、资源和性能,因此您最好不要这样做。
对新角色中的新功能进行完全重写并不总是一个坏主意。
Sometimes a rewrite is the best solution!
If you are writing software for a camera, you could assume that the next version will also do video, or stereo video or 3d laser scanning and include all hooks for all this functionality, or you could write such a versatile extensible astronaut architecture that it could cope with the next camera including jet engines - but it will cost so much in money, resources and performance that you might have been better off not doing it.
A complete rewrite for new functionality in a new role isn't always a bad idea.
尽管它并不直接适用于您的示例,但在编写代码时,我会尽力留意可以看到软件未来发展的方式。
基本上,我会尝试预测软件的走向,但更重要的是,我抵制住实现任何我能想象到的事情的诱惑。 我所追求的只是在不实现这些功能的情况下尝试让 API 和接口支持可能的未来,希望这些“可能的场景”帮助我想出一个更好、更面向未来的接口。
当然并不总是有效。
Although it doesn't directly apply to your example, when writing code I try to keep an eye out for ways in which I can see the software evolving in the future.
Basically I try to anticipate where the software will go, but critically, I resist the temptation to implement any of the things I can imagine happening. All I am after is trying to make the APIs and interfaces support possible futures without implementing those features yet, in the hope that these 'possible scenarios' help me come up with a better and more future-proof interface.
Doesn't always work ofcourse.