优秀的代码写两遍以上【Great code is written twice (or more)】

本文讨论了优秀的代码是如何通过不断的重写和迭代逐步完善的。作者强调了需求和代码都是逐步发展的,并分享了自己在项目实践中如何通过多次重写关键功能来提升代码质量的经验。

Great code is written twice (or more)
BY ROYVANRIJN ON OCTOBER 21, 2011 • 7 COMMENTS • IN AGILE, JAVA PROGRAMMING, SCRUM
优秀的代码写两遍以上

The last couple of years more and more people have been moving towards Agile development. These techniques aren’t new, most we’re devised in the 80s or 90s. But finally these days programmers and (more importantly) business consultants, architects and clients have learned to love and embrace Agile development.
最近这些年,越来越多的人开始转向敏捷开发。各种敏捷开发技术并不新鲜,大多是在80和90年代发展形成。但只是在最近这些年,程序员和(更重要的是)一些商业顾问、架构师和客户们开始变得喜欢和拥抱敏捷开发。
Evolving requirements
It has now become common knowledge that you can’t write down all the requirements before you start the project. These requirements have to be written down in an evolutionary matter. In short cycles/sprints we build pieces of the program and also iteratively extract the latest requirements from our clients. This is all based on the principle of evolution. Like everything in life, you get the best with incremental steps towards improvement.
进化中的需求
现在的一种普遍的认识是,在开始整个工程项目前,你不可能把所有的需求都写完备。需求的确定是一个逐渐进化的过程。使用短开发周期/sprints,我们一步步的开发程序,使用多次迭代的方式完成从客户方得到的最新需求。这些都基于进化原则。就像生活中,我们总是通过增量改进来达到最佳一样。
Evolving code!
But why stop there? Today most programmers have developed a mindset in which requirements have to be extracted evolutionary. But they seem to forget their own work!? They still think their frameworks and their architecture has to be solid at the start of their project. Also, once code is written, it is done.. right?
进化中的代码!
可是,这就完事了吗?如今大部分的程序员都认识到了需求必定是一步步的挖掘出来的。但他们却忘了自己的工作!?他们仍然认为他们的框架和架构在项目开始之初就定型了。同样,代码一旦写成,程序就完成了…不是吗?
Wrong. In my experience all great code is written at least twice. The first time you are too busy interpreting the requirements and figuring out what it should do. Sure, when you see certain patterns, we know that we need to extract methods and shift responsibilities around. The code you’ll end up can be pretty good, but it isn’t great.
In our current project, almost all important features have been rewritten from scratch multiple times. And slowly but surely the code is becoming better and better. Once you’ve made the 3rd or 4th addition to a certain piece of code, or you’ve fixed another bug, you’ll know where the code smells. You’ll feel like avoiding that piece of code, and you are glad when you are done fiddling with it. What do I do when I get this feeling? I delete the code.
错。以我的经验,所有优秀的代码都至少要写两遍。第一遍时你的时间主要用于匆忙理解和实现需求。不错,当看到了某种业务模式,我们知道要提炼出方法,围绕着它实现业务职责。你最终写成的代码是非常好的,但,它不是优秀的。
在我们目前的项目中,几乎所有的重要功能模块都从头重写过数次。慢慢的但明显的,代码变得越来越好。一旦你对某段程序做了第三或第四次增补,或又找到了一个bug,你能感觉到这程序什么地方有异味。你开始躲避触碰这段程序,你为不需要再处理这段程序而高兴。当有了这样的感觉后我会怎么做?我会删了这些代码。
But… but… then you have to start all over again!?
Wrong again! Sure, there is nothing left in the IDE, the code is gone, maybe some tests survived. You do have a solid understanding what the code should do. You also know what the code looked like before, so you know where it hurt/smelled in the past! With this knowledge you’ll write much better, maybe even great code! Sure, we could have kept the code and played with it some more, refactoring methods and responsibility… but there is nothing like grabbing the opportunity to start over again, and do it better.
Again, like all things in life: To make something great, it has to go through multiple evolutionary iterations. This is true for your requirements, your architecture and also your code.
可是…可是…这样你就要完全从头开始了!?
你又错了!当然,IDE里空空如也,代码全没了,也许一些测试程序会存留下来。但你却对你的代码应该做什么有了扎实的认识。你也知道以前这段代码是什么样的,你知道它以前的内伤和异味在哪里!有了这些认识,你能写出更好,甚至是非常优秀的代码!不错,我们也可以保留这些代码,使用一些重构措施…但你可能再也找不到这样好的从头开始、更好的编写它的机会了。
再次,就像生活中的所有事情:要让事情变的完美,你需要经过多次的进化迭代。对你的需求是这样,对你的架构和代码也是如此。
Doing it twice, twice as slow?
When I tell people that in my opinion all code needs to be written at least twice, they are afraid the project will take double the time. But this is far from true. Here is why:
1. The second time you write the code, it’ll only take a fraction of the time it took initially.
2. After rewriting the quality of the code is significantly higher, improving maintainability, extendability and also programming velocity.
Good luck, keep rewriting and evolve your code! And if you think rewriting doesn’t work… we have proof!
写两遍,就意味着两倍的时间吗?
当告诉人们我的观点是所有的程序都至少写两遍时,他们担心花费两倍的项目时间。但事实远非如此。下面是原因:
• 第二次写代码只是用去你初次写代码的很少一部分的时间。
• 重写之后,代码的质量会有明显的提高,可维护性,可扩展性都有改善,包括编程的速度。
祝你好运,坚持重新改进你的代码!

<think>好的,我需要解决用户在Cocos Creator 3.8中遇到的多次销毁对象的问题。首先,用户提到“试图销毁对象两次或更多次”,这通常是因为在代码中有多个地方调用了destroy()方法,或者对象已经被销毁但还被引用着,导致后续再次销毁时出错。 根据引用中的内容,特别是引用[4]提到了Cocos 3.x的API新法和避免重复实例化的方法,这里可能需要检查对象的生命周期管理。另外,引用[3]中提到的ECS框架中的Entity管理,可能涉及对象的创建和销毁逻辑,可以借鉴其通过id管理对象的方式,避免重复操作。 首先,我需要确认用户是否正确处理了对象的销毁。在Cocos Creator中,销毁节点应使用node.destroy(),但一旦销毁后,该节点的引用可能仍然存在,如果再次调用destroy()就会报错。解决方案可能包括: 1. 在销毁对象后立即将引用置为null,防止后续代码再次操作。例如,销毁后执行this.node = null;,这样后续的条件判断if(this.node)可以避免重复销毁。 2. 使用Cocos提供的isValid属性检查节点是否有效。在调用destroy()前检查if(node.isValid),确保节点未被销毁。 3. 检查代码逻辑,确保销毁操作只在一处执行,避免在多个地方(如不同的事件回调中)调用销毁方法。比如,可能是在触摸事件处理中多次触发销毁,需要确保事件回调被正确移除或只执行一次。 另外,引用[5]提到的事件处理顺序问题,比如began、move等事件的交替触发,可能导致在事件回调中重复销毁对象。需要检查触摸事件的处理逻辑,确保在对象销毁后移除事件监听,防止事件继续触发导致重复销毁。 还可能涉及到对象池的使用,如果用户使用了对象池来管理节点,那么销毁时应正确回收到对象池,而不是直接destroy(),这需要检查对象池的管理逻辑是否正确,避免重复销毁。 最后,建议用户使用调试工具,如断点或日志输出,跟踪对象的销毁过程,确认哪些代码路径导致多次销毁,从而有针对性地修复问题。</think>在Cocos Creator 3.8中,多次销毁对象会导致报错`Assertion failed: Cannot destroy a node twice!`。以下是解决方案和实现步骤: --- ### 一、问题原因分析 对象被多次销毁通常由以下场景引起: 1. 在代码逻辑中**重复调用`destroy()`方法** 2. 对象销毁后**未清空引用**,后续代码再次访问该对象 3. 事件监听未正确移除,触发回调时操作已销毁对象[^5] --- ### 二、解决方案 #### 1. 销毁前检查有效性 使用`isValid`属性判断对象是否已被销毁: ```typescript if (this.node.isValid) { this.node.destroy(); this.node = null; // 清空引用 } ``` #### 2. 统一销毁入口 将销毁逻辑封装为独立函数,避免多位置调用: ```typescript private destroyNode(target: Node) { if (target?.isValid) { target.destroy(); target = null; } } ``` #### 3. 事件监听管理 在销毁前移除所有事件监听(如触摸事件): ```typescript this.node.off(Node.EventType.TOUCH_START, this.onTouchStart, this); this.node.off(Node.EventType.TOUCH_MOVE, this.onTouchMove, this); ``` #### 4. 使用对象池优化 对频繁创建/销毁的对象使用`cc.NodePool`: ```typescript // 初始化对象池 const pool = new NodePool('Bullet'); // 取对象 const bullet = pool.get() || instantiate(prefab); // 还对象 pool.put(bullet); ``` --- ### 三、代码实现示例 ```typescript import { _decorator, Component, Node, NodePool } from 'cc'; @ccclass('ObjectManager') export class ObjectManager extends Component { private _pool: NodePool = new NodePool('DynamicObject'); // 安全销毁方法 public safeDestroy(node: Node) { if (node?.isValid) { node.offAll(); // 关闭所有事件监听 this._pool.put(node); // 回收到对象池[^3] // 如果不需要复用,则直接销毁 // node.destroy(); } } } ``` --- ### 四、性能优化建议 1. 优先使用`node.removeFromParent()`代替`destroy()`,若需要暂时隐藏对象 2. 通过`node.active = false`禁用节点而非立即销毁 3. 利用ECS框架管理对象生命周期(参考引用[3]的组件化思想) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值