游戏编程模式:前言(架构,性能和游戏)(Part I)

        译者的序:《Game Programming Patterns》是一本不错的书,讲了设计模式在游戏编程领域中的灵活运用。由于写得实在是太好了,遂触发了本人翻译的热情。所以把本人的渣翻放在这里做成系列博客,希望大家多多提出宝贵意见呀!下面正式开始了!

        今天讲的是引言部分。引言部分有很多对此书进行说明的部分,就略过了,直接来说说Architecture, Performance and Games这一章。下面是本人的翻译。有一些本人的注解就放在括号里了,大家很容易找到的。

 

-----------------------------------------------------分割线---------------------------------------------------------------

 

        在我们一头扎进成堆的模式之前,我觉得先跟各位看官说说“我是怎么看待软件架构的以及它是如何运用于游戏中的”会比较有用。这也许会让你们能够更好地理解本书余下的部分。至少,当你参与到一个关于设计模式和软件架构多么糟糕(或者给力)的辩论中时,这会给你一些武器来使用。

    注意我并没有假设你会站在哪一边。就像武器供应商一样,我为交战双方都出售货物。

1、什么是软件架构?

        如果你完完整整地读完了此书,你并不会学会3D图形背后的线性代数或者是游戏物理学背后的微积分。它并不会告诉你如何修剪你的AI搜索树或者是在你的音频重放中模拟一个房间的回音。

    天哪!上面这一段话将会成为本书的一个糟糕的广告!

        实际上,此书是关于那些代码之间的那些事的。它更多地是关于组织代码的,而非写代码的。每个程序都有某种组织形式,即使它仅仅是“将所有的事情挤在main()函数中然后看看会发生什么”,所以我觉得谈谈什么可以造就好的组织形式会更加有意思。我们怎么区分架构是好是坏呢?

        我对这个问题琢磨了差不多五年。当然,像你一样,我对于好的设计有一种直觉。我们都承受过代码库的折磨,这折磨是如此之严重,以至于你可以希望做的最好的事情就是take them out back and put them out of their misery(译者注:这句话不知道怎么翻译啊,求助!)。

    让我们承认吧,我们大部分人对其中一些糟糕的代码库是负有责任的。

        一些幸运儿有相反的经历,有机会与设计得很漂亮的代码一起工作。这种代码库感觉就像是一个完美装饰的奢华旅馆,还有门房在热切地期待着你的每一个怪念头。这两种代码的区别是什么?

 

什么是好的软件架构?

        对于我来说,好的设计意味着当我做出一个改变的时候,看起来就像是整个程序就是为了变更而制造的。我可以用仅仅几个供选择的、可以完美嵌入的函数调用解决一个任务,不会在平静的代码表面上留下任何涟漪。

        这听上去不错,但是不太可行。“尽管去写你的代码,使得变更不会扰乱其平静的表面。”是的。

        让我把这件事稍微细分一下。第一个关键部分是“架构是关于变更的”。某人不得不修改代码库。如果没人去碰这代码——要么是因为它很完美,很完整,要么是因为它很烂,以至于没人会用它来弄脏自己的编辑器——那么其设计就无关紧要了。对于一个设计的好坏的量度是它应对变更的方便程度。如果没有变更的话,那么它就是一个从未离开起跑线的赛跑者。

   

你怎么做出一个变更?

        在你可以更改代码来增加一个新特性、修复一个bug或者是为了其他什么导致你打开你的编辑器的目的之前,你得要理解现有的代码正在做什么。当然,你不必了解整个程序,但是你需要将相关的部分载入到你的头脑中。

    想想有点奇怪,这是一个光学文字辨识(Optical CharacterRecognition, OCR)过程。

       我们倾向于对这一步骤避而不谈,但是这经常是编程过程中最耗时的部分。If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves.

        一旦你将所有的正确的相关文本放到你的大脑中,你会略微思索,并找出你的解决方案。这里可能会有很多的来回往复,但是这一般是比较直接的。一旦你理解了问题以及与之有接触的那部分代码,实际写代码的时候有时就不值得一提了。

        你用你肉乎乎的手指在键盘上敲打了一会儿,直到屏幕上闪烁着正确的颜色的光,然后你就完事了,对吧?还没呢!在你写测试代码并将代码发出去以供代码评审之前,你经常有一些清理工作要做。

    我是不是说了“测试”?哦,是的,我说了。对于某些游戏代码来说写单元测试很难,但是代码库的很大一部分完全是可以测试的。

    我不会在这里搞长篇大论(译者注:I won't get on a soapbox here),但是我会让你考虑做更多的自动化测试(automated testing),如果你还没有做的话。相比于一次又一次手动地确认事情,难道你没有更好的事情去做吗?

        你往你的游戏中又塞入了一些代码,但是你不希望下一个人被你在源代码中留下的褶皱所绊倒。除非变更很小,否则通常你需要对代码进行重新组织,以使你的新代码与程序的其他部分无缝地结合成整体。如果你做得对,下一个人将没法判断出哪一行代码是什么时候写的。

        简而言之,编程的流程图有点如下图所示:


    现在我想了想,这个循环没有跳出这一事实是令人担忧的。

 

解耦如何有帮助?

        虽然这不明显,但是我觉得软件架构的很大一部分是关于上面那个学习阶段的。将代码载入到神经元中的过程慢得令人痛苦,所以找到策略来减小代码的体积是值得的。本书有一整节是关于解耦模式的,并且《设计模式》(Design Patterns)的一大块跟这一概念有关。

        你可以用好几种方式来定义“解耦”,但是我觉得如果两块代码是耦合的,那么这意味着你要理解其中之一,就必得理解另一个。如果你解耦了它们,那么你可以独立地理解其中之一了。这很棒,因为如果只有一块代码与你的问题有关,那么你就只需要将这一块代码载入到你的头脑中,而非把另一半也载入进来。

        对我来说,这是软件架构的一个关键目标:减少你在能够有进展之前需要知道的知识的量。

        后面的阶段当然也有戏份了。解耦的另一个定义是对一块代码做出的变更未必要求另一块的变更。我们显然必须要变更某些东西,但是我们耦合的东西越少,该变更对游戏的其他部分产生的涟漪就越少。

 

2、以什么代价?

        这听上去很棒,对吧?对所有东西进行解耦,然后你就可以行云流水地写代码了。每一个变更意味着只要触碰一两个可供选择的函数,并且你可以在代码的表面跳舞,不留下一丝阴影。

        这种感觉正是为什么人们对抽象(abstraction)、模块化(modularity)、设计模式和软件架构感到兴奋的原因。与一个良好构架的程序一起工作是一个愉快的经历,并且每个人都喜欢变得更加多产。好的架构对于生产效率能够产生巨大影响。再怎么强调其效果的深远性都不为过。

        但是,就像人生中的所有事情一样,这并不是免费的。好的架构需要付出努力以及训练。每当你做出一个变更或者实现一个特性的时候,你必须努力工作以使得其余程序的其余部分优雅地结合成一个整体。你必须在两方面小心行事:一方面是好好地组织代码,另一方面是在经历过上千个构成开发周期的小小的变更后保持代码为有组织的状态。

    上述的第二部分——维护你的设计——需要引起特别的重视。我见过许多程序一开始是优美的,但是随着程序员们一遍又一遍地添加“仅仅一个小小的劈砍”而死于遍体鳞伤。

    就像园艺一样,仅仅放入新的植物是不够的。你必须除草、剪枝。

        你必须考虑程序的哪一部分应该被解耦出来,并且在这些地方做出抽象。同样地,你得确定什么地方需要加入扩展性(原文:you have to determine where extensibility should be enginnered in)以便可以更加容易地做出未来的变更。

        人们对此感到兴奋。他们设想未来的开发人员(或者就是未来的他们自己)涉足于代码库中,然后发现它是可修整的(open-ended)、强大的、希望被扩展的。他们想象着统治他们所有人的一个游戏引擎(The One Game Engine To Rule Them All)。

        但这就是事情开始变得棘手的地方。每当你增加一个抽象层级或者一个可以支持可扩展性的地方的时候,你推测你后来会需要这种灵活性。你正在往你的游戏中增加代码和复杂性,而这需要时间来开发、调试以及维护。

        如果你猜得对并在后来接触到那部分代码的话,那么这种努力会得到补偿。但是预测未来是困难的,而当该模块性最终证明无用的话,那么它就会很快地变得有害。毕竟,你需要处理更多的代码了。

    有些人发明了术语YAGNI(是You aren't gonna need it的缩写),作为用于对抗推测自己未来会需要什么的冲动的真言。

        当人们对此变得过于狂热的时候,你会得到一个代码库,其结构已经绕得脱离控制了(whose architecture has spiraled out of control)。你会在所有的地方遇到接口和抽象。插件系统(plug-in systems)、抽象基类、虚方法巨多无比,还有各种各样的可扩展点。

        这会让你花上一辈子在所有这样的脚手架间穿梭以追踪到一些真正做了实事的代码。当你需要做出一个变更的时候,当然,很可能有一个接口在那里可以相助,但是希望你运气好到能够找到它。理论上,所有的这种解耦意味着你在可以对代码进行扩展之前,只需要理解比较少的代码就行了,但是抽象层本身最终会装满你的心理暂存磁盘(mental scratch disk)的。

        像这样的代码库正是使得人们反对软件架构、尤其是设计模式的原因。很容易深陷进代码本身,以至于你忘却了你正在努力地发售一个游戏。可扩展性这首塞壬之歌吞没了无数的开发者,他们花了数年时间来做一个“引擎”,却并不知道这是一个用于什么的引擎。


  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值