Hacker News new | past | comments | ask | show | jobs | submit login

Not just in game development. If you have a function that is only called once, it shouldn't be a function yet. Make it a function when you have a second or third use for it. Then, and only then, you will know what the parameters should be.



I disagree. Splitting a function up can help with readability and testability. The parent function becomes shorter and the child function can have a descriptive name. The parameters to a function are the fields that are needed for the function to perform its function.


Function calls have an overhead, and if the function is only used once it makes no sense to break it out.

It also makes no sense to have a rule on the maximum number of lines for a function. These rules are often created by people who don't write software that needs to have high performance.


The compiler does a lot of optimizing, including inlining function calls so that they do not have overhead. My opinion is to favour readable and maintainable code. If there is a performance issue, then profile it, measure and then optimize. No need to prematurely optimize at the cost of code quality.


A function that is called once will always be inlined. Trust the compiler.


> A function that is called once will always be inlined.

That is objectively false. Even though I agree with the spirit. For starters, unoptimized builds won't have that. Second, exceptions tend to inhibit inlining. Compare https://godbolt.org/z/c8Jayf with https://godbolt.org/z/Uoo2YA. Third, it's easy enough to push one of the heuristics used for inlining high enough in the wrong direction (e.g. function size). I recommend the clang optimizer view on godbolt.

Also note that it can be hard for a compiler to prove that a function is not used outside the current translation unit (although anonymous namespaces help with that). Number of calls is only one of the heuristics for inlining though anyway.


All languages? No.

Compilers are plenty stupid, and have not earned blind trust.


One of my professors used to encourage the heavy use of helper functions that just... well, like in A or B in carmacks article, break your code into chunks with clear names that can be unit tested.

How common is automated testing in AAA games?


Underlying helper libraries like math utilities are often extracted and put under independent test. A physics engine often has so much state (and isn't always guaranteed to be deterministic!) that doing any sort of unit testing at the functional level is not worth it. To those that reply with "use less state", I encourage you to show how. Often times the unit tests I've seen from junior game programmers are worse than useless and aren't testing anything of tremendous value.

Games that use automated tests often drive high level systems and test high level output. See for instance Riot Games's automated League of Legends test suite.


Game development problems are often large global state manipulation problems. If you don't write games you will never realize this.

Almost everything taught in academia and in the enterprise about software development "best practices" are absolutely the wrong things for a game. (They're wrong for enterprise and academia, too, but I'm not willing to get into that fight on this site.)


Is there an industry-wide set of concepts and best practices that is applicable for large scale games? What sorts of things do hiring managers worry about at night?


Preface: I'm not a gameplay programmer. I'm not even a dynamics or physics specialist. And I don't hire for them. But as a core engine programmer:

The power of an engine is that it is a series of closely intertwined parts. Often times, the graphics code and collision code are linked; here's an example. Shoot a bullet in any FPS; the resulting decal is likely created from the collision data, since it's much faster to search than the highly tessellated graphics model.

Or, let's say, I have a melee attack. The specific frame that the attack occurs on is likely decided by the animation data. So that means that we need to run animations on the server, against an invisible skeleton.

Similarly, you might encounter a scenario where a bunch of stuff blows up, and you want 99% of that simulation to be baked offline and not simulated on the client, to ensure that the tower lands exactly where it needs to. So now you need to plug together your physics and animation systems, yadda yadda.

These are not bugs, or necessarily problems. People who suggest we turn all engines into tiny independent toolkits are missing the point. Of course everyone tries to make systems as independent as possible. But there's a bunch of power you can unlock if you have even a small bit of close integration between two systems.

How does one manage complexity? The first is to enable everyone, even artist and designers, to be technical. They're already managing complex topologies, doing sophisticated lighting and shading techniques, and often writing custom Python scripts to help them clean up the massive amount of data. A big thing I've seen from developers out of FAANGs is that they're shocked that "non-programmers" are writing custom scripts and doing programming. Your artists and designers are incredibly technical people who are good at solving problems. Trust them.

Invest in custom tools; any bit of custom tooling to make your life easier will pay off massively. Basically, give your whole staff the ability to debug and fix issues, with custom UIs and logs specifically built for your purpose.

QA staff are undervalued here in the US, but anybody who's worked in games for three months knows what a difference a senior QA makes. They know your game better than anybody else. Watching a good QA go from a blurry cameraphone pic on an angry reddit post somewhere to complete repro steps in less than an hour is nothing short of magic.


Just want to chime in to say I have learned a lot from your participation in this thread, thanks for being part of what makes HN great.


function calls push registers, allocate a stack frame, and push a return address. By breaking your inner loops into more functions you've now generated megabytes of pointless memory thrash... on a console. Additionally, at the time this stuff was written, compilers and toolchain weren't neccessarily standardized, or were customized to accomodate certain use cases, so they needed more hand-holding to generate performant code. This is just a fact.. I'm not saying you're wrong, but you're definitely viewing this with hindsight.


Function calls do none of those things if they’re inlined, and compilers have been able to inline functions for a long time. Perhaps this code is even older than that.


While this is often a good rule of thumb, occasionally it's useful to extract a function just to make the inputs clear for a complicated calculation. Particularly when it has few inputs and they are unlikely to change.


With modern C++ you could do this with a lambda


Which compiler that can compile modern C++ doesn't always inline a static single-caller function?


All of them? There's many cases where it doesn't make sense:

- The function is exported to a library

- The code generator emitted an indirect branch instruction

- The inlined code exceeds the size of a single page in memory

- The inlined code does not perform as well because it is not i-cacheable


There are other reasons for separating logic into functions besides just keeping it DRY. It's an opportunity to encapsulate concerns and then, in some other place, compose the story poetically and clearly.


...which is NOT high on the list of concerns for a game title, what you want instead is massive performance gains, so you can do more with less, and in the end produce a better experience than your competitor. -- function calls/indirection/making your code 'easy' to understand, all have a RUNTIME cost, and many small costs add up to a large cost, the reasoning is really that simple.


I struggle to see how composing into functions adds a runtime cost when using modern compilers; as others have pointed out the compiler will inline it if the function is only used once.

This rationalization doesn’t make sense to me, especially for game engines which I assume are not limited to a release or 2 but are used to power multiple titles. If the software artifact is going to live for a long time, it’s probably worth the effort to make it easier to understand and test.


This! I'm not sure why we are discussing the runtime cost of a function with modern compilers.

Could this pattern result in code so slow the game won't work in development w/o high optimization flags, thus increasing compile time?


> the compiler will inline it if the function is only used once.

There may be other criteria, eg is the function likely to be called.


Breaking routines into functions makes testing possible. If it's really only called once, the compiler can inline it for you.


That is a bold statement, but you are free to express yourself.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: