游戏邦在:
杂志专栏:
gamerboom.com订阅到鲜果订阅到抓虾google reader订阅到有道订阅到QQ邮箱订阅到帮看

分享程序员清理糟糕代码的8点建议

发布时间:2012-08-24 15:12:39 Tags:,,,,

作者:Niklas Frykholm

你猜怎么着?你刚接手一批糟糕的代码。恭喜你!现在这些活都是你的了。

糟糕的代码可能来源于任何地方。中介软件、网络、甚至在你自己的公司。

记着,那是某人几年前写的模块,现在人已离开公司。20个人经手那个模块,编辑、打补丁和修补漏洞,没有人真正理解他们在做什么。

你下载的开源代码怎么样呢?你知道那也是很可怕的,但它能解决燃眉之急,如果让你自己解决,可能要花好几年。

糟糕的代码不一定会成为难题,只要它没有产生太大的麻烦,也没有气得某人吐血。不幸的是,那种安乐状态极少能持续很久。你发现了一个新漏洞,你需要新的功能,你要进军新的平台。现在,你必须清理这团混乱。本文提供了一些实用的建议,帮助你摆脱不幸的处境。

bad code(from quickmeme.com)

bad code(from quickmeme.com)

这值得吗?

你要问你自己的第一个问题是,这段代码值不值得清理。我的观点是,你要在“是”和“否”之间权衡。如果你选择“是”的话,你要全权负责这段代码和重写编写,直到你完成某些让你感到高兴、乐意收进代码库的东西。

如果你选择“否”的话,你会认为即使那段代码看起来很糟,也不值得从你紧张的工作计划表中挤出时间修改它。所以你只是做了能解决当前问题的最小的调整。

换句话说,这取决于你把这段代码看成是你自己的还是别人的。

这两种选择各有优点。优秀程序员看到糟糕的代码会感到心里发痒。他们举着火把,拿着铁叉,高喊着:“这里没清理!那里没清理!”这是一个好习惯。

但清理代码也是一项浩大的工程。我们很容易低估这项工作所需的时间。你所耗费的时间可能像将这段代码重新写过一样,并且短期内看不到成效。花两周清理代码不会给游戏增加任何新功能,却可能给你带来新问题。

另一方面,从长远看来,不清理代码的影响可能是是灾难性的。信息熵是代码杀手。

所以,从来就没有容易的做法。你要考虑的事有:

*你希望对代码做多少调整?只是一个需要修复的小漏洞还是希望返回多次调整修改以增加新功能的代码。如果是前者,那么也许最好是睁一只眼闭一只眼。然而,如果是一整个需要你费大量时间处理的模块,那么你最好马上花时间清理它,以免日后头疼。

*你是否需要/想将修改任务交给前一级开发部门?这是一个正在开发的开源代码的项目?如果是,且你想将修改任务交给前一阶段,那么你不能对代码做出任何大改变,否则你的每一次调整都会把你推入地狱。所以,做个好队友,将漏洞的补丁发给维护人员吧。

*清理代码的工作量是多少?你一天可以实际可以清理多少行代码?根据数量级估算,不少于100不多于1000,所以我们假设是1000。所以如果这个模块有30000条代码,你需要花一个月的时间。你挤得出这些时间吗?值得花这些时间吗?

*这段代码是不是核心功能的一部分?如果这个模块的作用是次要的,比如渲染字体或载入图片,你可能不会关心它是否混乱。你之后可能会用其他东西将整个模块转换出来。但你应该让代码与核心功能相关。

*这段代码到底有多糟?如果只是有一点点乱,那么你也许可以无视它。如果确实乱得令人发指,那么你必须清理它。

1、测试用例

严格地清理一段代码意味着为它耗费大量时间。

如果你有一个体面的、覆盖性良好的测试用例,你可以马上知道什么地方错了,然后很快想出你犯了什么愚蠢的错误。如果没有测试用例,耗费时间和精力清理代码的过程是很可笑的。所以,要有一个测试用例,这是你首先要做的事。

单元测试最好,但并非所有代码都适合单元测试。如果单元测试太麻烦,可以改用综合测试。例如,开启游戏关卡,让角色执行与正在清理的代码有关的一套动作。

因为这种测试很费时间,所以不可能在每一次调整后都做一次。但如果你将每一次修改都置于源代码管理之下,就不算太坏。每过一段时间就测试一次(如,每做完5次调整)。当发现问题时,你可以对这些调整采用折半查找法,找出哪个修改引起问题。

如果你发现没有被测试检验出来的问题,那么你要确保你将问题添加到测试中,过后你才有可能改正它。

2、使用源代码控制

仍然必须有人告诉你要使用源代码控制吗?我希望不用。

对于清理工作,源代码控制是非常重要的。你会对一段代码做很多很多小调整。如果代码崩坏了,你肯定希望能在修改历史中查看,然后找出到底是哪里出错了。

另外,如果你也和我一样,那么有时候你会启动代码重构路径(如移除一个类),之后又意识到这不是一个好主意,或者这是一个好主意,但如果你先做点其他什么事,一切都会简单得多。所以你希望能够快速复原代码,先做其他什么事。

你的公司应该有一个源代码控制系统,允许你单独做修改,然后提交,而不必烦扰到其他人。

但即使没有,你也应该使用源代码控制。所以,下载Mercurial(或Git),创建一个新的资源库,将你用公司的系统查找出来的代码放进去。在那个资源库中做你的修改工作,然后交付。当你完成后,你可以将所有修改合并入那个系统。

将那个资源库复制到敏感的源代码控制系统中,只需要几分钟的时间。这样是绝对值得的。如果你不了解Mercurial,那就花一个小时学习吧。你会为自己的付出感到高兴的。或者如果你偏好Git,那就花30个小时学习吧。(我是开玩笑的,大家都不傻。)

3、一次只做一个(小)修改

处理烂代码的方法有两个:变革和改良。变革法就是将所有东西都删掉,从头再写一次。改良法就是在不破坏代码的情况下,每次做一个小的修改,最终重构代码。

本文要讲的是改良法。我不是说变革法永远不必要。有时候,代码实在太糟了,只能重新写过。但对改良的缓慢感到沮丧而主张变革的人往往没有意识到整个问题的复杂性,因此不够信任当前的代码。

改良代码的最好方法是一次只做最小的修改,然后测试,提交。当修改很小时,我们很容易知道它的修改效果,确保它不会影响当前功能。如果出错了,你只需要检查少量代码。

如果你开始做修改时发现不对劲,你还会以损失太多时间,只要返回上一次提交就可以了。如果过了一段时间你发现出现了微小的错误,使用折半查找法就可以发现导致错误的小修改。

我们常犯的错误是,同时做多件事。例如,在除去不必要的代码后,你可能会注意到API并不像你所希望的那样彼此正交,所以你开始重新安排。不要!首先除去继承的代码,提交,然后修改API。

聪明的程序员就是这么组织工作的,实际上他们不必太聪明。

要将现有的代码一点一点地往你所希望的样子调整。例如,在一个小步骤中,你可能会重新命名。在下一个小步骤中,你可能会将某些成员变量改成功能参数。然后你重新记录某些算法,好让它们更加清楚。等等。

如果你做修改时发现它是一个比你原来想象的还要庞大的调整,不要害怕复原代码,要将相同的过程分成更小、更简单的步骤。

4、不要同时清理和修改

这是第3条的推论,但因为比较重要,所以单独列成一个点。

这是一个普遍问题。因为你想增加某些新功能,你开始查看模块。然后你注意到这段代码组织得不好,所以你开始重新组织,同时,你还添加了新功能。

这个做法的问题是,清理和修改存在正好相反的目标。当你清理时,你想让代码看起来更好,同时不改变它的功能。当你修改时,你想把它的功能改成更好的那一种。如果你同时清理和修改,要保证你的清理不会改变功能是很困难的。

所以,先清理。等你有了一个漂亮的代码基础后再添加新功能。

5、移除所有当前不需要的功能

清理所需的时间与代码的数量、复杂度和混乱度成正比。

如果代码中存在当前不需要或在可预见的未来内不使用的功能,那就删除它。这么做,一方面减少了你要查看的代码数量,另一方面也让代码结构更清楚(通过删除不必要的概念和相关性)。这样就你可以更快地完成清理工作,最终结果也会更简单。

不要因为“可能哪天就用上了”就保留代码。代码是高投入的——需要移植、检验、读取和理解。代码越少越好。即使哪天你确实需要这些旧代码,你总是可以源代码库中找到它。

6、删除大部分注解

糟糕的代码几乎没有好注解。相反的,它们往往是:

// Pointless:

// Set x to 3

x = 3;

// Incomprehensible:

// Fix for CB (aug)

pos += vector3(0, -0.007, 0);

// Sowing fear and doubt:

// Really we shouldn’t be doing this

t = get_latest_time();

// Downright lying:

// p cannot be NULL here

p->set_speed(0.7);

阅读这段代码。如果注解对你来说没意义,或根本不能帮助你理解代码——那就果断删除。否则,在之后阅读代码时,你会浪费精力理解这些注解。

有注解的死代码也是一样的。果断删除。如果有需要,你也可以在源代码库中找。

甚至当注解正确和有用时,记着你要对代码所做的是大量重构的工作。当你完成修改后,那些注解可能就不再正确了。这个世界上不存在什么单元测试能告诉你“注解错误”。

好的代码需要的注解极少,因为代码本身就结构清楚、容易理解。命名恰当的变量不需要注解来解释它们的目的。输入和输出清楚、无特例的功能也不需要注解。简单、编写良好的算好不需要注解、声明文件、前提条件就可以理解。

在许多情况下,最好删除旧的注解,专心致志地将代码写清楚、然后返回添加必须的注解——现在反思新的API和你自己对代码的理解吧。

7、删除共享可变状态(游戏邦注:这是指在整个应用程序中共享且随时可变的变量)

说到理解代码,共享可变状态是一个大问题,因为它会产生可怕的“远距离活动”,即一段代码的修改,彻底改变了另一段代码的功能。我们经常说多线程是很复杂的。但事实上,共享可变状态的线程才是问题。如果你删除了共享可变状态,多线程也没那么复杂了。

因为你的目标是编写高性能的软件,你不可能删掉所有可变状态,但减少可变状态仍然可以大大优化代码。努力做“几乎功能性的”程序,确保你知道你在哪里、为什么、改变了什么状态。

共享可变状态可能在以下几个地方产生:

*全局变量。这是典型的例子。现在,所有人都肯定全局变量是不好的。但注意(这是有时候人们不能区别的地方),只有共享可变状态才是问题。全局变量没有那么糟。Pi不坏,Sprintf也不差。

*对象。对象是实现大量功能(方法)的方式,暗含了很多可变状态(类成员)。如果懒惰的程序员必须在不同方法之间通过某些信息,他会做一个自己可以随意读取和写入的新类成员。这几乎就像是全局变量。对象具有的成员越多,方法越多,问题越大。

*宏函数。你应该听说过吧。这些传说中的生物居住在最黑暗的代码库的最深处。郁闷的程序员在昏暗的酒吧里发泄他们的烦恼:“我翻了又翻,简直不敢相信自己的眼睛,整整12000条啊。”当功能足够大,他们的局部变量几乎就跟全局变量一样糟。改变局部变量会产生什么影响,不可能预测出来。

*引用和指示参数。没有常量的引用和指示参数可以用作介于调用函数和被调用函数之间的共享可变状态。

如何处理共享可变状态,以下有几条实用的建议:

*将大功能分解成几个小功能。

*将大对象分解成小对对象,然后分群组。

*不通用类成员。

*将方法改成常量,返回结果而不是改变状态。

*将方法改成静态的,将它们的参数作为参量,而不是从共享状态中读取。

*彻底删除对象,将功能作为纯功能来执行,不带附加作用。

*将局部变量设为常量。

*将指示变量和引用参数改成常量。

8、减少不必要的复杂性

不必要的复杂性往往是过分设计的结果——支持结构(游戏邦注:如序列化、引用计数、虚拟化界面、抽象因素等)掩盖了执行实际功能的代码。

有时候产生过度编程是因为软件项目的启动带有过多目标,超过了实际上能完成的程度。我认为,这反映了阅读关于设计模式和瀑布模型的程序员的野心,他们认为过度编程会让产品更“可靠”、品质更高。

通常,沉重、死板、太复杂的模型不能满足功能需求,这是设计师始料未及的。这些功能之后会被当作漏洞、附加功能和程序后门来执行,结果是绝对指令的混淆和彻底的混乱。

对抗过分编程的方法是,只编写你知道我需要的东西。当你需要时才添加新的东西,而不是在之前就添加。

减少不必要的复杂性的建议如下:

*移除你目前不需要的功能。

*简化必要的概念,删除不必要的概念。

*移除不必要的抽象函数,替换成更精确的执行。

*移除不必要的虚拟化,简化对象层次结构。

*如果只有一个设置是需要的,那就避免在其他设置中运行模块。(本文为游戏邦/gamerboom.com编译,拒绝任何不保留版权的转载,如需转载请联系:游戏邦

In-depth: Cleaning bad code

by Niklas Frykholm

Guess what! You’ve just inherited a stinking, steaming pile of messy old code. Congratulations! It’s all yours.

Bad code can come from all kinds of places. Middleware, the internet, perhaps even your own company.

You know that nice guy in the corner that nobody had time to check up on? Guess what he was doing all that time. Churning out bad code.

Or remember that module someone wrote years ago, just before she left the company. That module that 20 different people have then added hacks, patches and bug fixes to, without really understanding what they were doing. Yup, that one.

Or what about that open source thing you downloaded that you knew was horrible, but it solved a very specific and quite hairy problem that would have taken you ages to do by yourself.

Bad code doesn’t have to be a problem, as long as it’s not misbehaving, and nobody pokes their bloody nose in it. Unfortunately, that state of ignorant bliss rarely lasts. A bug will be discovered. A feature requested. A new platform released. Now you have to dig into that horrible mess and try to clean it up. This article offers some humble advice for that unfortunate situation.

0. Is it worth doing?

The first thing you need to ask yourself is whether the code is worth cleaning. I’m of the opinion that when it comes to code cleaning, you should either karate do “yes”, or karate do “no”. Either you assume full responsibility for the code and rework it until you end up with something that you are actually happy to maintain and proud to have in your codebase.

Or you decide that even though the code looks horrible, it isn’t cost-effective to take time out of your busy schedule to fix it. So instead you just do the smallest change possible that solves your current problem.

In other words, you either regard the code as yours or theirs.

There are merits to both alternatives. Good programmers get an itch when they see bad code. They bring out their torches and pitchforks and chant: “Unclean! Unclean!” And that is a good instinct.

But cleaning code is also a lot of work. It is easy to underestimate the time it takes. It can be nearly as time-consuming as rewriting the whole thing from scratch. And it doesn’t bring any short-term benefits. Two weeks cleaning code won’t add any new features to the game, but it might give you some new bugs.

On the other hand, the long-term effects of never cleaning your code can be devastating. Entropy is the code-killer.

So, never an easy choice. Some things to consider are:

How many changes do you expect to make to the code?Is it just this one small bug that you need to fix, or is this code that you expect to return to many times to tweak and tune and add new features. If it’s just this one bug, then perhaps it is best to let sleeping dogs lie. However, if this is a module that you will need to mess around with a lot, then spending some time to clean it up now, will save a lot of headache later.

Will you need/want to import upstream changes?Is this an open source project that is under active development? If so, and you want to pull the changes made upstream, you can’t make any big changes to the code or you will be in merge hell every time you pull. So just be a nice team player, accept its idiosyncrasies and send patches with your bug fixes to the maintainer.

How much work is it?How many lines of code can you realistically clean in a day? An order of magnitude estimate says more than 100 and less than 10,000, so let’s say 1,000. So if the module has 30,000 lines, you might be looking at a month of work. Can you spend that? Is it worth it?

Is it a part of your core functionality?If what the module does is something peripheral, like say font rendering or image loading, you might not care that it is messy. You might swap out the whole thing for something else in the future, who knows. But you should own the code that relates to your core competence.

How bad is it?If the code is just slightly bad, then perhaps you can live with it. If it is mind-numbingly, frustratingly incomprehensibly bad, then perhaps something needs to be done.

1. Get a test case

Seriously cleaning a piece of code means messing around with it a lot. You will break things.

If you have a decent test case with good coverage, you will immediately know what has broken and you can usually quite quickly figure out what stupid mistake you just made. The time and anxiety this saves over the course of the cleaning process is just ridiculous. Get a test case. It’s the first thing you should do.

Unit tests are best, but all code is not amenable to unit testing. (Test fanatics, send your hate mail now!) If unit tests are too cumbersome, use an integration test instead. For example, fire up a game level and run the character through a specific set of actions related to the code you are cleaning.

Since such tests are more time-consuming, it might not make sense to run it after every change you make, which would be ideal. But as you put every single change you make into source control, it’s not so bad. Run the test every once in a while (e.g., every five changes). When it discovers a problem, you can do a binary search of those last few commits to find out which one caused the problem.

If you discover an issue that wasn’t detected by your test, make sure that you add that to the test, so that you capture it in the future.

2. Use source control

Do people still have to be told to use source control? I sure hope not.

For cleaning work, it is absolutely crucial. You will be making lots and lots of small changes to the code. If something breaks you want to be able to look back in the revision history and find out where it broke.

Also, if you are anything like me, you will sometimes start down a refactoring path (like removing a stupid class) and realize after a while that it wasn’t such a good idea, or, that it was a good idea, but that everything would be a lot simpler if you did something else first. So you want to be able to quickly revert everything you just did and begin anew.

Your company should have a source control system in-place that allows you to do these changes in a separate branch and commit as much as you like without disturbing anybody else.

But even if it doesn’t, you should still use source control. In that case, download Mercurial (or Git), create a new repository and put the code that you checked out of your company’s stupid system there. Do your changes in that repository, committing as you go. When you are done you can merge everything back into the stupid system.

Cloning the repository into a sensible source control system only takes a few minutes. It is absolutely worth it. If you don’t know Mercurial, spend an hour to learn it. You will be happy you did. Or if you prefer, spend 30 hours to learn Git instead. (I kid! Not really. Nerd fight now!)

3. Make one (small) change at a time

There are two ways of improving bad code: revolution and reform. The revolution method is to burn everything with fire and rewrite it from scratch. The reform method is to refactor the code with one small change at a time without ever breaking it.

This article is about the reform method. I’m not saying that revolutions never are necessary. Sometimes things are so bad that they just need to go. But people who get frustrated with the slow pace of reform and advocate revolution often fail to realize the full complexity of the problem and thus don’t give the existing system enough credit for the things it does.

Joel Spolsky has written a classic article about this without falling into the trap of making strained political metaphors.

The best way of reforming code is to make one minimal change at a time, test it and commit it. When the change is small it is easier to understand its consequences and make sure that it doesn’t affect the existing functionality. If something goes wrong, you only have a small amount of code that you need to check.

If you start doing a change and realize that it is bad, you won’t lose much work by reverting to the last commit. If you notice after a while that something has gone subtly wrong, a binary search in the revision history will let you find the small change that introduced the problem.

A common mistake is to do more than one thing at the same time. For example, while getting rid of an unnecessary level of inheritance you might notice that the API methods are not as orthogonal as you would like them to be and start to rearrange them. Don’t! Get rid of the inheritance first, commit that and then fix the API.

Smart programmers organize the way they work so that they don’t have to be that smart.

Try to find a path that takes you from what the code is now to what you want it to be in a sequence of small steps. For example, in one step you might rename the methods to give them more sane names. In the next, you might change some member variables to function parameters. Then you reorder some algorithms so that they are clearer. And so on.

If you start doing a change and realize that it was a bigger change than you originally thought, don’t be afraid to revert and find a way of doing the same thing in smaller, simpler steps.

4. Don’t clean and fix at the same time

This is a corollary to (3), but important enough to get its own point.

It is a common problem. You start to look at a module because you want to add some new functionality. Then you notice that the code is really badly organized, so you start reorganizing it at the same time as you are adding the new functionality.

The problem with this is that cleaning and fixing has diametrically opposite goals. When you clean, you want to make the code look better without changing its functionality. When you fix, you want to change its functionality to something better. If you clean and fix at the same time, it becomes very hard to make sure that your cleaning didn’t inadvertently change something.

Do the cleaning first. Then, when you have a nice clean base to work with, add the new functionality.

5. Remove any functionality that you are not using

The time it takes to clean is proportional to the amount of code, its complexity and its messiness.

If there is any functionality in the code that you are currently not using and don’t plan to be using in the foreseeable future — get rid of it. That will both reduce the amount of code you will have to go through and its complexity (by getting rid of unnecessary concepts and dependencies). You will be able to clean faster and the end result will be simpler.

Don’t save code because “who knows, you might need it some day.” Code is costly — it needs to be ported, bug checked, read and understood. The less code you have, the better. In the unlikely event that you do need the old code, you can always find it in the source repository.

6. Delete most of the comments

Bad code rarely has good comments. Instead, they are often:
// Pointless:

// Set x to 3

x = 3;

// Incomprehensible:

// Fix for CB (aug)

pos += vector3(0, -0.007, 0);

// Sowing fear and doubt:

// Really we shouldn’t be doing this

t = get_latest_time();

// Downright lying:

// p cannot be NULL here

p->set_speed(0.7);

Read through the code. If a comment doesn’t make sense to you and doesn’t further your understanding of the code — get rid of it. Otherwise you will just waste mental energy on trying to understand that comment on each future reading of the code.

The same goes for dead code that has been commented or #ifdef’ed out. Get rid of it. It’s there in the source repository if you need it.

Even when comments are correct and useful, remember that you will be doing a lot of refactoring of the code. The comments may no longer be correct when you are done. And there is no unit test in world that can tell you if you have “broken the comments”.

Good code needs few comments because the code itself is clearly written and easy to understand. Variables with good names do not need comments explaining their purpose. Functions with clear inputs and outputs and no special cases or gotchas require little explanation. Simple, well written algorithms can be understood without comments. Asserts document expectations and preconditions.

In many cases, the best thing to do is just to get rid of all old comments, focus on making the code clear and readable, and then add back whatever comments are needed — now reflecting the new API and your own understanding of the code.

7. Get rid of shared mutable state

Shared mutable state is the single biggest problem when it comes to understanding code, because it allows for spooky “action at a distance”, where one piece of code changes how a completely different piece of code behaves. People often say that multithreading is difficult. But really, it is the fact that the threads share mutable state that is the problem. If you get rid of that, multithreading is not so complex.

Since your goal is to write high-performant software, you won’t be able to get rid of all mutable state, but your code can still benefit enormously from reducing it as much as possible. Strive for programs that are “almost functional” and make sure you know exactly what state you are mutating where and why.

Shared mutable state can come from several different places:

Global variables. The classic example. By now everybody surely knows that global variables are bad. But note (and this is a distinction that people sometimes fail to make), that it is only shared mutable state that is problematic. Global constants are not bad. Pi is not bad. Sprintf is not bad.

Objects — big bags of fun. Objects are a way for a large number of functions (the methods) to implicitly share a big bag of mutable state (the members). If a lazy programmer needs to pass some information around between methods, she can just make a new member that they can read and write as they please. It’s almost like a global variable. How fun! The more members and the more methods an object has, the bigger this problem is.

Megafunctions. You have heard about them. These mythic creatures that dwell in the deepest recesses of the darkest codebases. Broken programmers talk about them in dusky bars, their sanity shattered by their encounters: “I just kept scrolling and scrolling. I couldn’t believe my eyes. It was 12,000 lines long.”When functions are big enough, their local variables are almost as bad as global variables. It becomes impossible to tell what effect a change to a local variable might have 2,000 lines further down in the code.

Reference and pointer parameters. Reference and pointer parameters that are passed without const can be used to subtly share mutable state between the caller, the callee and anyone else who might be passed the same pointer.

Here are some practical ideas for getting rid of shared mutable state:

Split big functions into smaller ones.

Split big objects into smaller ones by grouping members that belong together.

Make members private.

Change methods to be const and return the result instead of mutating state.

Change methods to be static and take their arguments as parameters instead of reading them from shared state.

Get rid of objects entirely and implement the functionality as pure functions without side effects.

Make local variables const.

Change pointer and reference arguments to const.

8. Get rid of unnecessary complexity

Unnecessary complexity is often a result of over-engineering — where the support structures (for serialization, reference counting, virtualized interfaces, abstract factories, visitors, etc) dwarf the code that performs the actual functionality.

Sometimes over-engineering occurs because software projects start out with a lot more ambitious goals than what actually gets implemented. More often, I think, it reflects the ambitions/esthetics of a programmer who has read books on design patterns and the waterfall model and believes that over-engineering makes a product “solid” and “high-quality.”

Often, the heavy, rigid, overly complex model that results is unable to adapt to feature requests that were not anticipated by the designer. Those features are then implemented as hacks, bolt-ons and backdoors on top of the ivory tower resulting in a schizophrenic mix of absolute order and utter chaos.

The cure against over-engineering is YAGNI — you are not gonna need it! Only build the things that you know you need. Add more complicated stuff when you need it, not before.

Some practical ideas for cleaning out of unnecessary complexity:

Remove the functionality you are not using (as suggested above).

Simplify necessary concepts, and get rid of unneeded ones.

Remove unnecessary abstractions, replace with concrete implementations.

Remove unnecessary virtualization and simplify object hierarchies.

If only one setting is ever used, get rid of the possibility of running the module in other configurations.

9. That is all

Now go clean your room!(source:gamasutra)


上一篇:

下一篇: