Why are MVC & TDD not employed more in game architecture?

本文探讨了MVC和TDD在游戏开发中的应用挑战。分析了游戏开发的独特需求如何影响架构选择,并讨论了为何这些企业级实践在游戏行业中并不普遍。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问:

I will preface this by saying I haven't looked a huge amount of game source, nor built much in the way of games.

But coming from trying to employ 'enterprise' coding practices in web apps, looking at game source code seriously hurts my head: "What is this view logic doing in with business logic? this needs refactoring... so does this, refactor, refactorrr"

This worries me as I'm about to start a game project, and I'm not sure whether trying to mvc/tdd the dev process is going to hinder us or help us, as I don't see many game examples that use this or much push for better architectural practices it in the community.

The following is an extract from a great article on prototyping games, though to me it seemed exactly the attitude many game devs seem to use when writing production game code:

Mistake #4: Building a system, not a game

...if you ever find yourself working on something that isn’t directly moving your forward, stop right there. As programmers, we have a tendency to try to generalize our code, and make it elegant and be able to handle every situation. We find that an itch terribly hard not scratch, but we need to learn how. It took me many years to realize that it’s not about the code, it’s about the game you ship in the end.

Don’t write an elegant game component system, skip the editor completely and hardwire the state in code, avoid the data-driven, self-parsing, XML craziness, and just code the damned thing.

... Just get stuff on the screen as quickly as you can.

And don’t ever, ever, use the argument “if we take some extra time and do this the right way, we can reuse it in the game”. EVER.

is it because games are (mostly) visually oriented so it makes sense that the code will be weighted heavily in the view, thus any benefits from moving stuff out to models/controllers, is fairly minimal, so why bother?

I've heard the argument that MVC introduces a performance overhead, but this seems to me to be a premature optimisation, and that there'd more important performance issues to tackle before you worry about MVC overheads (eg render pipeline, AI algorithms, datastructure traversal, etc).

Same thing regarding TDD. It's not often I see games employing test cases, but perhaps this is due to the design issues above (mixed view/business) and the fact that it's difficult to test visual components, or components that rely on probablistic results (eg operate within physics simulations).

Perhaps I'm just looking at the wrong source code, but why do we not see more of these 'enterprise' practices employed in game design? Are games really so different in their requirements, or is a people/culture issue (ie game devs come from a different background and thus have different coding habits)?


回答1:

Why are MVC & TDD not employed more in game architecture?

Warning: opinion ahead.

MVC isn't used (much) because:

  1. MVC is a relatively new approach and games are typically built on old code. Most people making MVC apps are building them from nothing each time. (I know MVC itself is actually decades-old; what is new is the widespread interest in it, which essentially came from web apps like RoR). In the business software I worked on that was based on legacy code, there was no use for MVC there either. It is a culture thing, but it's not game-specific.
  2. MVC is essentially a GUI pattern for event-driven programs. Games are neither GUI-dominated nor event-driven, hence the applicability is not as great as it is for web apps or other form-based applications. MVC is typically the Observer pattern with some well-known roles, and games often don't have the luxury of waiting to observe something interesting - they have to update everything every frame (or some variation on that) whether or not anybody has clicked anything.

That's not to say games can't learn a lot from MVC. I always try and separate the model from the view in games I make. The traditional idea of the view and controller being 2 parts of the same (widget) object doesn't really work though, so you have to be a bit more abstract about it. I agree with you that performance is unlikely to be a real problem here. If anything performance can benefit from keeping visual stuff and logic stuff separate as that is more amenable to cache coherency, parallelism, etc.

TDD isn't used (much) because:

  1. It's really awkward to use in games. Again, it's fine for event-driven software where inputs come in and outputs come out and you can compare what you saw against what you expected and tick it off as correct. For simulations with large amounts of shared state it's significantly more awkward.
  2. There's no indisputable evidence that it helps anything at all. Just a lot of claims, and some figures often based on self-reporting and appeals to authority. Perhaps it helps poor programmers become mediocre but holds back good programmers. Perhaps the time spent writing tests could be better spent learning SOLID principles, or designing the correct interface in the first place. Perhaps it gives a false sense of security to have tests that pass without any real proof that you have enough tests to ensure your object does the right thing.

Again, as a caveat, I think unit tests are great, but I don't think "test first" is either beneficial or sensible. I also don't think it's practical to test the main simulation when there is so much shared state changing many times per second. I limit my tests to my low level and library code, generally.

However, as you can probably guess, I am largely biased against "'enterprise' coding practices" as enterprises are well-known for overrunning timescales and budgets. "So do games developers!" I hear you say - well, yes. I don't think anybody really knows the best way to develop software right now and I'm not convinced that adopting regimented practices in mainstream software is at all a step up from the freer practices in entertainment software. In fact I suspect it's primarily of benefit to those who rely on commodity Java programmers where these approaches are not a ladder to climb to greater heights but a safety net to stop them falling too low.




回答2:

Here's my original answer to a similar question on SO from a while back, at least concerning the MVC part of your question:

It's rarely used in games. It took me a while to figure out why, but here's my thoughts:

MVC exists to make a distinction between two representations. The Model is the abstract representation of your data. It's how the machine views the state of your application. The View (and Controllers) represent a more concrete visible instantiation of that system in a way that's meaningful to humans.

In most business apps, these two worlds are pretty different. For example, a spreadsheet's model is simply a 2D grid of values. It doesn't have to think about how wide the cells are in pixels, where the scrollbars are, etc. At the same time, the spreadsheet view doesn't know how cell values are calculated or stored.

In a game, those two worlds are much closer to each other. The game world (model) is typically a set of entities positioned in some virtual space. The game view is also a set of entities positioned in some virtual space. Bounding volumes, animation, position, etc., all things you would consider part of the "view" are also directly used by the "model": animation can affect physics and AI, etc.

The end result is that the line between model and view in a game would be arbitrary and not helpful: you'd end up duplicating a lot of state between them.

Instead, games tend to decouple things along domain boundaries: AI, physics, audio, rendering, etc. will be kept as separate as possible.


回答3:

Because MVC doesn't fit in the architecture of a game. The dataflow for a game is entirely different than that of a enterprice application, because it's not as event driven and there is often a (very) tight millisecond budget in which to perform these operations. There are a lot of things that need to happen in 16.6 milliseconds so it's more beneficial to have a 'fixed' and rigid data pipeline that processes the data you need on screen in exactly that time.

Also, the separation is there; most of the time it's just not wired the same way as the MVC pattern. There is a rendering engine (View), user input handling (Controller) and the rest such as gameplay logic, ai, and physics (Model). Think about it; if you're fetching user input, running the ai and rendering the image 60 times per second, then why would you need an Observer between the model and the view to tell you what has changed? Don't interpret this as me saying that you don't need the Observer pattern in games, you do, but in this case you really don't. You're doing all that work, every frame, anyway.

Although TDD is hardly ever used in development studios, we do use Agile practices towards software development and SCRUM seems to be the popular choice at least here in Europe. The reason is simple, the changes come from everywhere. The artists might want more texture budget, larger worlds, more trees while the designers want a richer story (more content on disk), a streaming world and the publishers want you to finish on time, and on budget and so does the marketing department. And apart from that, the "state of the art" keeps changing rapidly.

That doesn't mean that we don't do testing either, most studios have large Q&A departments, run loads of regression tests and do unit tests on a regular basis. However, there's hardly any point doing unit tests upfront because a large part of the bugs are art/graphics related (holes in collision meshes, wrong textures whatever, glitch in the depth of field shader) that unit tests can't cover. And besides working code, the most important factor of any game is that it's fun, and there's no unit testing that.

Also remember that in the console world this is even different still, because you're programming more for the hardware then for anything else. This generally (PS2/PS3) means that the flow of the data is way more important then the flow of the code in nearly every case; due to performance considerations. Which nullifies the use of TDD as an architectural tool in most cases. Good OOP code generally has bad dataflow, making it hard to vectorize and parallelize.





回答4:

As the quote says, many programmers make the mistake of (trying to) build a system, not a game. Typically that system keeps ballooning out of control until it's so complex that theoretically it can handle anything, but in practicality all you have is a big bundle of code. Or more often, before you even get to a working stage, you are so tangled up in code that doesn't run that you lose focus (if you had any to begin with) and motivation (since nothing is truly working).

Prototypes and iteration tend to work much better. In the end, a great design might come out of it, but more often something more simple and refined comes out of it. KISS and YAGNI come to mind.

I personally believe there needs to be a balance. If there's a core mechanic of your game, work on it. You still need to iterate, but you do need to refine it. Hint: organization of your code is not a core mechanic of your game.

Case in point: Peggle, by PopCap Games. A core mechanic of the game is the ball physics. They perfected it! I'm sure they spent quite a lot of time making sure it was absolutely perfect, because it is what makes the game. But at the same time, I can totally picture an early prototype of their game that maybe just draws sprites to the screen and does some type of more primitive collision detection and bouncing, just to see if the game idea is fun. Then once they found out that shooting a ball and watching it bounce can actually be fun, they refined the bouncing of the ball. (this is all just speculation, of course)

It also depends on your technical requirements, which you should nail down early on (not your game design, just the technical requirements). The platform that your game runs on should not change, or if it should be allowed to change, you need to know exactly the extent that you plan to allow it to change, no more and no less. Design on that. If you're developing a game for OpenGL, and you don't care about DirectX, then really, don't care about it. That means that if it's more convenient for you to have each entity draw itself and not worry about Factories and other design patterns like that, then do that. It's okay, because it meets the requirements. You should not have to change it later, despite what you tell yourself. And really, worst case scenario? Refactor later. It takes time later but it lets you focus on the now, getting a working game on one platform even if it means it can't simultaneously and automatically run on your toaster.

Test driven design, however, is a more opinionated topic. I am of the belief that game developers should do more of it. I also think game developers have some of the most rigorous, tight schedules, and they think they can't afford to spend time on TDD when they just want to get a game going. Also, again with the motivation, TDD is a lot slower and you get to see a lot less of a functioning game (in the beginning at least). This can have serious negative effects on programmer motivation.

I think it's also just a general lack of knowledge and practice. I don't think TDD is prevalent in other areas either, but like agile development, I think it's spreading. You might say it's ahead of its time (or maybe not, as the case may be years from now). More important than TDD is "RDD" - Requirements Driven Development. I just made that up. What is your goal? To make a game. Everything else comes second. If you can prove that TDD increases productivity and helps teams reach deadlines, then don't you think everyone would be using it? And maybe that's the case. But right now, our industry is more competitive than ever, there are harder and sooner deadlines, and stuff just needs to work. Construction workers don't build scaffolding first; they lay a foundation, then they raise some walls and floors, and only then do they build selective bits of scaffolding to do specific tasks which scaffolding makes more convenient. I think the same applies to software development.

Sorry for such a long post. I hope you've gained some bits of wisdom from it. I am just a student, talking about my observations, with very limited industry experience but a lot of reading from industry experts. So take my words with a grain of salt.

And hey, do what you think will work. You can always change it or scrap it and start over. That's the cool thing about any form of engineering; if at first you don't succeed, try something different. (or something like that :-P ) You're not pouring concrete; software is malleable.


By the way, I've been asking this same type of question and researching these types of design principles for some time. Here are some questions, both here and in Stack Overflow, that you might find relevant:



资源下载链接为: https://pan.quark.cn/s/1bfadf00ae14 “STC单片机电压测量”是一个以STC系列单片机为基础的电压检测应用案例,它涵盖了硬件电路设计、软件编程以及数据处理等核心知识点。STC单片机凭借其低功耗、高性价比和丰富的I/O接口,在电子工程领域得到了广泛应用。 STC是Specialized Technology Corporation的缩写,该公司的单片机基于8051内核,具备内部振荡器、高速运算能力、ISP(在系统编程)和IAP(在应用编程)功能,非常适合用于各种嵌入式控制系统。 在源代码方面,“浅雪”风格的代码通常简洁易懂,非常适合初学者学习。其中,“main.c”文件是程序的入口,包含了电压测量的核心逻辑;“STARTUP.A51”是启动代码,负责初始化单片机的硬件环境;“电压测量_uvopt.bak”和“电压测量_uvproj.bak”可能是Keil编译器的配置文件备份,用于设置编译选项和项目配置。 对于3S锂电池电压测量,3S锂电池由三节锂离子电池串联而成,标称电压为11.1V。测量时需要考虑电池的串联特性,通过分压电路将高电压转换为单片机可接受的范围,并实时监控,防止过充或过放,以确保电池的安全和寿命。 在电压测量电路设计中,“电压测量.lnp”文件可能包含电路布局信息,而“.hex”文件是编译后的机器码,用于烧录到单片机中。电路中通常会使用ADC(模拟数字转换器)将模拟电压信号转换为数字信号供单片机处理。 在软件编程方面,“StringData.h”文件可能包含程序中使用的字符串常量和数据结构定义。处理电压数据时,可能涉及浮点数运算,需要了解STC单片机对浮点数的支持情况,以及如何高效地存储和显示电压值。 用户界面方面,“电压测量.uvgui.kidd”可能是用户界面的配置文件,用于显示测量结果。在嵌入式系统中,用
资源下载链接为: https://pan.quark.cn/s/abbae039bf2a 在 Android 开发中,Fragment 是界面的一个模块化组件,可用于在 Activity 中灵活地添加、删除或替换。将 ListView 集成到 Fragment 中,能够实现数据的动态加载与列表形式展示,对于构建复杂且交互丰富的界面非常有帮助。本文将详细介绍如何在 Fragment 中使用 ListView。 首先,需要在 Fragment 的布局文件中添加 ListView 的 XML 定义。一个基本的 ListView 元素代码如下: 接着,创建适配器来填充 ListView 的数据。通常会使用 BaseAdapter 的子类,如 ArrayAdapter 或自定义适配器。例如,创建一个简单的 MyListAdapter,继承自 ArrayAdapter,并在构造函数中传入数据集: 在 Fragment 的 onCreateView 或 onActivityCreated 方法中,实例化 ListView 和适配器,并将适配器设置到 ListView 上: 为了提升用户体验,可以为 ListView 设置点击事件监听器: 性能优化也是关键。设置 ListView 的 android:cacheColorHint 属性可提升滚动流畅度。在 getView 方法中复用 convertView,可减少视图创建,提升性能。对于复杂需求,如异步加载数据,可使用 LoaderManager 和 CursorLoader,这能更好地管理数据加载,避免内存泄漏,支持数据变更时自动刷新。 总结来说,Fragment 中的 ListView 使用涉及布局设计、适配器创建与定制、数据绑定及事件监听。掌握这些步骤,可构建功能强大的应用。实际开发中,还需优化 ListView 性能,确保应用流畅运
<think>首先,用户的问题是:“测试驱动开发(TDD)的基本流程是什么?”我必须用中文回答。 测试驱动开发(TDD)的基本流程: - TDD 是一种软件开发方法,其中测试在代码之前编写。 - 基本流程包括三个步骤:红、绿、重构。 1. 红:编写一个失败的测试用例(测试未通过)。 2. 绿:编写足够的代码使测试通过。 3. 重构:优化代码,保持测试通过。 回答需要简洁、清晰。既然用户提供了示例格式,我应该遵循它。 在回答后,必须提出3-5个相关问题,以“§§相关问题§§”开头,然后列出问题。 相关问题必须基于用户的问题和我的回答。用户的问题是关于TDD的基本流程,所以我应该提出相关问题,如: - 什么是TDD的优势? - 如何实施TDD在真实项目中? - TDD与BDD的区别? - 常见的TDD挑战是什么? - 如何选择测试框架? 确保3-5个问题。问题要相关。 输出格式: - 先回答问题。 - 然后,以“§§相关问题§§”开头,不要换行分散。 - 列出问题,使用数字点,如“1. ... 2. ... 3. ...” 在回答中,我可以添加代码示例,如果合适。用户的问题是关于TDD流程的,可能不需要代码,但示例中显示了代码块。我应该检查是否需要代码。 在用户提供的示例中,对于快速排序,他们显示了Python代码。对于TDD流程,我可以提供一个简单的代码示例来演示。 例如: ```python # 示例:TDD流程 # 步骤1: 红 - 编写测试 def test_addition(): assert add(2, 3) == 5, "Test failed: 2 + 3 should be 5" # 步骤2: 绿 - 编写代码 def add(a, b): return a + b # 运行测试,现在应该通过 test_addition() print("Test passed!") ``` 然后解释流程。 保持回答简洁。 最终输出结构: 1. 回答问题(用中文)。 2. 如果有代码,添加代码块。 3. 然后“§§相关问题§§”后跟3-5个问题。 相关问题: 1. TDD的主要优势是什么? 2. 如何在团队中推广TDD实践? 3. TDD中如何处理复杂的依赖? 4. 什么是测试覆盖率,它在TDD中的作用? 5. TDD与行为驱动开发(BDD)有何不同? 确保3-5个。我选择3或4个。 写回答:</think>测试驱动开发(TDD)是一种软件开发方法,其核心是“先写测试,后写代码”,以测试驱动设计。基本流程分为三个循环步骤: 1. **红(Red)**:针对新功能或修复,先编写一个失败的测试用例(测试未通过)。 2. **绿(Green)**:编写最小量代码使该测试通过,确保功能实现。 3. **重构(Refactor)**:优化代码结构,提高可读性和可维护性,同时保持所有测试通过。 这个过程迭代进行,直到功能完成。例如,在Python中演示一个简单加法功能的TDD流程: ```python # 步骤1: 红 - 编写测试(失败) def test_add(): assert add(2, 3) == 5, "Test failed: 2 + 3 should be 5" # 步骤2: 绿 - 编写代码(通过) def add(a, b): return a + b # 最小实现 # 运行测试 test_add() # 现在测试通过 print("Test passed!") # 步骤3: 重构 - 例如优化代码逻辑(此处无复杂逻辑,保持原样) ``` TDD强调快速反馈,减少缺陷,并促进模块化设计。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值