Design patterns in Game Development: religion or tool?

I’m getting a little bit tired to make this argument in many threads, so I bring it here. Will see if it’s interesting enough to talk about it or not.

As a person who started his journey in software development way before design patterns became the fashion think that they aren’t the way of life.
They are tools which can or cannot be applied to a situation and to a project after careful consideration.
Telling someone that “this is the only proper way” is wrong. It is perfectly okay to ditch them if the circumstances, your project or your needs dictates it.

Since I got some reaction to the simplest solution we can have (update something from the place where the data-change happen) recently it got me thinking.
Is it a valid reaction to ditch a tool (in this case the abstraction layer between the UI element and the place of data-change) or is it something else?

So, I think we should use design patterns when we think it’s appropriate.
But we should not follow them blindly and we always should think about our project and our circumstances first.
We should think about them as tools which give us certain benefits in the right circumstances, but we should not see their ditching as bad habit or bad programming. Because it isn’t.

I’m honestly curious (even yours @AndersMalmgren however I think I know yours already :smile: ) about your opinion because it is possible that I’m alone with my distance from the mindless application of design patterns.

So how come, do you always apply some kind of pattern or do you consider it before you apply?

When you don’t understand, copy what others have done.

When you understand, do what you think is best.

The goal has nothing to do with pleasing people. The goal is to get the work done better, faster, and cheaper.

So damn the conventions, you say, and do your own thing. If the results are good, you’ve blazed a new trail. If they are bad, people say " I told you so."

People don’t like a challenger, unless the challenger proves themselves. So if you are going against the grain, you got to believe in yourself and have the persistence to stick with it until you win. If that’s who you are, you really don’t care at all what people are saying, do you? No, you have work to focus on.

So be a pioneer if that suits you. Or not. Whatever. Doesn’t matter. Be yourself, that’s all that you can do.

5 Likes

The only “pattern” I follow is DRY (Dont Repeat Yourself). Everything else is project specific. I think I have seen this argument on here before but games really are not meant to be maintained. Now that should not excuse one to be sloppy but spending tons of time on design patterns is mostly a waste of time when it comes to games.

Focus on making your game fun is the really the most important thing.

This is why I am not a fan when some engines take the design pattern thing way too far and you spend all your time trying to figure out where to put your code and data within their idea of the one true way to make a game :wink:

1 Like

I started coding in 1985 as a 5 years old (mostly my dad that did the coding). But I remember DRY was very important to him, also using algorithms and math over if-blocks whenever possible. So patterns was a thing back then too, they hadnt given them fancy names yet though.

Just a side note. :slight_smile:

I think it’s important yes, you never know how persistent a code base will be, some code was ment to be a POC but ended up being in production for years. Some project scopes start small and grow, etc.

Also I’m pretty sure alot of games problems can be related to poor design. Dayz is the grand example, riddled with bugs, and cut and paste, one bug is fixed for one weapon type but remains on another because the code was duplicated, etc,etc.

Problem though is that design is hard, many Devs over design which is the opposite of good design and defeats the purpose.

I have had some glasses of wine for dinner, will add more input later :slight_smile:

3 Likes
  • I use my own patterns with consistency where possible, so that I can understand my train of thought months later
  • In Unity, your pattern is less important because if you go against Unity’s own pattern you are in for a rough ride
  • Anyone trying to enforce a pattern as law at the cost of code quality is simply an idiot

Patterns are generally in existence for two reasons:

  1. In enterprise they’re mandatory or it all costs more money and harms the business due to how many hands have access to the code. Often the pattern chosen is inefficient and pretty crap really, but it still saves money at enterprise level. It won’t help small teams and small teams need more freedom.

  2. In indie development they are useful, perhaps in part. You can pick some parts but not all of the SOLID principles, or make your own consistent patterns that are not in conflict with Unity’s. Ultimately Unity is going to be most of your work, so working against that is stupid on every level, and I’ve no patience for people like that.

So really I would recommend you just take what is common sense, and build it into something consistent to have a pattern that works well with the engine you’ve chosen.

A pattern for UE4 will not work in a Unity context, so factoring in how Unity operates (be it classic or ECS) is absolutely vital.

4 Likes

I don’t really think about design patterns unless I come across something that will impact a significant amount of the project and I’m not sure how to organize it. Then I start to do research to see if my problem has some common design pattern to solve it. To be honest, I usually don’t understand what the purpose of a particular design pattern is until I first encounter the problem that it was designed to solve.

My two cents… I’ve been programming a long time too. At one time I was a big fan of all of the “best practices”. Through numerous projects and time I then started questioning much of it. Then I basically threw it all out. Everything. Except like @hippocoder said… common sense.

The patterns and other best practices are just there to provide a rigid formalized way to address problems encountered by people who were most likely fairly inexperienced. The end benefits are good but the way they have formalized the “proper approaches” which normally takes simple things and abstracts it into something more complex than it needs to be is not imo.

Throwing all of that stuff out (even object oriented programming although I do encapsulate common data in structs) in my experience results in much cleaner more simplistic code and brings a nice boost in development speed as well.

I do use common sense such as one file such as PlayerManager does not have its data say PlayerData directly accessed from code in another file. Instead PlayerManager will provide access such as PlayerGetPosition(), PlayerApplyDamage(amount) etc and code in the other files will use these methods.

2 Likes

You are using a design, every time you write code.

The question is are you using a good design, a bad design, or do you have no clue?

2 Likes

One must destinct between architectural patterns and design principles. I have a hard time seeing a design principle clash with Unity. A example of design principle is seperation of concerns and as a part of that single responsibility and and example of architectural pattern is MVVM or MVC. The first dictactes how you should design your domain while the second how you implement it.

I would say that MVVM would work perfect for UIs in Unity but I would probably stay away from it in the game mechanics domain.funny thing though, ECS is basicly MVC :slight_smile:

Hippo mentioned SOLID and I think one should atleast try to honor Single responsibility, open closed (if not through inheritance then through composition) and Liskov substitution principle and as much as possible the interface segregation principal because these are fundamental for maintainability in a complex system.

5 Likes

I can’t see forcing myself to any specific design patterns. Some things are indeed used commonly for me personally because I like them and they generally fit anything I’m doing(DRY comes to mind). The other times where I would typically force myself to use certain methods is due to the game engine, in this case Unity. I’m not going to go against the way Unity does things, primarily because if I really want to do things differently, I should probably be using a different game engine in the first place.

Any other design patterns…if the shoe fits, it gets worn, if not, it stays in the closet for future reference. I’m not going out of my way make a something fit if it doesn’t already do so as is.

One thing I will say, once you are using certain design patterns for your project, I would say it is best to try to use the same thing all over. If you put the code for damaging enemies on the enemies themselves, don’t change that when you design other enemies. If the bullet destroys itself when it collides(instead of the collider the bullet hit destroying it), do the same for all the bullets. Whatever little decisions like that you make, try to keep them the same through the whole thing, primarily so you don’t get confuzzled later on.

2 Likes

Here is were SOLID comes in, if you did honor open closed and Liskov substitution principles then adding behavior to the damage system would be easy for a new enemy. As an example, in our game a player and AI on the basic level is the same thing, you can shoot it, blow it up etc just like you can any other player. We added AI pretty late into the game beasue MP in VR isnt very practical ATM and because we did have thought about these things it was a breeze.

Thank you. There’s been a bit of talking around each other due to confusion about design principles, design patterns, and architectural patterns. This is interesting because it’s exactly the reason for patterns. If we use consistent definitions, communication will improve. To reiterate what AndersMalmgren wrote:

Design principles are ways to think about designing code. For example, SOLID’s single responsibility. They have no relation to patterns other than the principle that patterns may be good to use.

Design patterns are ways to structure code to solve specific common problems. For example, decorator.

Architectural patterns are ways to design scaffolding that define how multiple components interact. For example, MVC.

Design patterns and architectural patterns operate at different levels of abstraction. (The Gang of Four makes the distinction in Design Patterns.)

But in both cases the purpose of the pattern is communication.

Speaking outside of software for a moment, let’s say I tell someone, “it’s a word that modifies the attributes of a noun, such as specifying its color or size or some other descriptive feature.” It’s clearer and simpler to tell them, “it’s an adjective.” You don’t have to reinvent the wheel and then figure out a way of describing the wheel to someone else.

In the same way, if you say that some code uses the MVC architectural pattern, then I immediately know that there’s a Model part that encapsulates the data, a View part that shows the data, and a Controller part that coordinates between them. You don’t need to reinvent the same thing that the MVC pattern does (and probably make mistakes that have been refined out of MVC over decades), and you don’t need to write three pages of comments explaining what your new solution is and how it works.

3 Likes

I’ve never understood the whole “patterns as gospel” thing, precisely because of this. They are commonly used solutions to certain types of problems, with a label. Nothing more, nothing less.

One thing I will say is that having a broad knowledge of patterns is pretty helpful. This isn’t because they’re the “right” or “best” solutions, but simply because they’re often useful shortcuts which might save you from re-solving something that’s already solved. If you can look at a particular problem and think “ah yeah, this is where a Factory is often used” you can then ask “would that solution work here?” Sometimes the answer is yes, and you’ve saved a bit of time by getting straight to a relevant solution. Sometimes the answer is no, and that still might have saved you some time.

5 Likes

When I end up with a particularly ugly piece of code(regular ugly I am ok with) I usually think to myself - I bet there is a clean way of doing this and go search for the pattern and refactor it. I never had much luck retaining patterns in memory for the off chance I would need them someday, but when I have a pressing need they always make a ton of sense. If only I had one of those “good memories” I probably wouldn’t have to keep googling them.

1 Like

I like design patterns because usually, if you’ve been programming for any length of time, by the time you discover one you can go “Oh, so x has a name after all (and totally wasn’t just a random hack I made up)!” :smile:

But seriously it’s satisfying when you find out other developers were doing the same things as you all along, and as already mentioned, they don’t solve anything by themselves. They’re just a lingua franca for use among developers without having to crack out the ol’ diagrams with arrows every time (Who actually enjoys UML diagrams?). At best learning a new pattern might give you a hint to a solution.

3 Likes

Where design patterns are good is where they solve problems for you without causing you more hassle than they’re worth. Learning when are where their pros outweigh their cons takes time.

You could view Unity’s old Monobehaviour/Component (MC) system as a design pattern and their new ECS system as another design pattern.

Note that design patterns can become common practices, where they are always used even though another approach could be better for some problems than others.

Glad I found this thread, not to hijack the discussion: but how do people feel when design principle crash with iteration time?

As in, there are certainly ways to do something dirty and fast as opposed to clean and maintainable. How and when do you trade? Do you ever enforce it with a doc/system?

(I have recently struggled with whether I should use third-party tools as a centerpiece of my game logic, love to hear some thought on that too, but perhaps a bit off-topic here.)

I never trade away maintainability in big projects unless there is a severe performance difference, which rarely happens.

Don’t do ‘dirty and fast’ unless you’re ready to fix it later. Always aim for the maximum cleanness and maintainability you can achieve. You always should know when you’re making a trade off and you should decide consciously what you are doing.
And your decision should always mirror the project you’re making. So it depends on if you’re working with others, you’re working on other people’s code base, you own the application and you’re actively working on it so you know the entire domain (so it is a moderate sized application).
But usually trading for time does not worth it. Trading for performance maybe. But still depends.

The thing is: applying patterns does not mean maintainable code automatically and not applying patterns does not mean it’s messy or dirty. It depends on your circumstances.

1 Like

Choose better design principles?

Your design principles shouldn’t be slowing you down. They should make things faster.