News for hackers. Stuff that matters.
Re:Thirteen Years of Bad Game Code by geokon on Friday March 31, 2017 @03:24AM (#14001787)
He basically admits that several of the "improvements" boils down to ripping out patterns that decouple code instead of finding alternate solutions. They're kinda quick and dirty, not agile, and could make refactoring a nightmare. I mean, he's not necessarily wrong, but hindsight is 20/20 and once you're done you can look back and cherry-pick and say "ahh, well obviously these things would always need to be coupled! I shouldn't have done the gymnastics to decouple them!" .. but that's a dangerous mindset to start solving the problem with.

The whole topic of global state is very interesting and one I approach cautiously. I'd love to hear what more experienced programmers have to saw. When I go with global state I usually rely on someone else's judgement and use a framework. Like OpenGL and the graphics pipeline has global state.. and I'm okay with that. I use Cinder/Arduino, those things have some global states and for good reasons as well.

But you really try your best to find a stateless solution - and here is feels like he isn't really trying

Re:Thirteen Years of Bad Game Code by sillysaurus3 on Friday March 31, 2017 @03:48AM (#14001866)
The whole topic of global state is very interesting and one I approach cautiously. I'd love to hear what more experienced programmers have to saw.

1. Quake 3 relied heavily on global state. It was good design, and the engine produced billions in revenue.

2. Emacs relies heavily on global state. A global variable is a first-class citizen. When a package declares a global variable, it's a contract between the package author and the user that "You may configure the behavior of this package by binding this variable to a new value, then invoking one of my functions." Emacs lisp has language constructs which makes this easier: `(let* ((foo-state 42)) (foo-bar))` will update the global variable `foo-state` to 42, call the global function `foo-bar`, and ensures that `foo-state` is returned to its previous value even if an error occurs and an exception is propagated. In other words, global variables are the interface to a module, just like a module's functions, and global variables are almost never left in an unexpected or invalid state due to errors.

This system works shockingly well in practice. Emacs is basically a gigantic state simulation, and it parallels a game engine quite strongly.

The Emacs Lisp language itself is cumbersome, which has led many to dismiss it as ancient. The true power of emacs has little to do with lisp and almost everything to do with excellent design decisions.

3. The history of programming informs us that those who hold to dogma are quickly made obsolete. Every tool and pattern has its place. A technique that simplifies X in a certain domain will make X far more complicated in a different domain. Context matters.

Re:Thirteen Years of Bad Game Code by TeMPOraL on Friday March 31, 2017 @05:22AM (#14002212)
> The true power of emacs has little to do with lisp and almost everything to do with excellent design decisions.

Those design decisions didn't come out of the vacuum. The ability to patch and modify almost everything at runtime is something that came out of Lisp and Smalltalk, and wasn't even on the map of the (currently) mainstream languages until very recently. Dynamic scoping is something that AFAIK has strong Lisp roots too.

Emacs Lisp is less of an accident and more of an old, old language. Even Lisp family moved on to default to lexical scoping, though it didn't remove dynamic scoping - as in many cases, it's still extremely convenient.

Re:Thirteen Years of Bad Game Code by smaddox on Friday March 31, 2017 @03:55PM (#14007539)
Dynamic scoping can easily be included when desired in the form of a key-value store. I can't think of any advantage to having it built into the language itself. I guess you could argue standardization, but most modern languages provide a standard kvstore.
Re:Thirteen Years of Bad Game Code by tcard on Friday March 31, 2017 @05:55AM (#14002360)
Now that you mention Quake 3, this article [1] by John Carmack himself on the subject is interesting, and then someone reviewed the source code from Doom 3 [2] where apparently they put some of that in practice.

[1] https://web.archive.org/web/20130819160454/http://www.altdev... [2] http://kotaku.com/5975610/the-exceptional-beauty-of-doom-3s-...

Re:Thirteen Years of Bad Game Code by saurik on Friday March 31, 2017 @06:26AM (#14002475)
The Emacs property you are demonstrating with let is "dynamic scoping" and not "global variables" (which is leading to a weird and essentially incorrect description, even if it is difficult to notice a behavior difference between that mental model and what really happens).
Re:Thirteen Years of Bad Game Code by sillysaurus3 on Friday March 31, 2017 @06:48AM (#14002557)
A global variable is a variable with global scope, meaning that it is visible and accessible throughout the program, unless shadowed.

Emacs added lexical scoping several years ago. When a global variable is declared in emacs using defvar, in addition to becoming globally accessible, the symbol is also flagged as special. This causes it to use dynamic binding whenever it is `let`-bound, even if lexical scoping is in effect.

I pointed out dynamic binding in order to call attention to a technique that allows global variables to be composed into large-scale systems without being hindered by the problems traditionally associated with global state. But if you'd like more precision, feel free to ask.

Re:Thirteen Years of Bad Game Code by bitexploder on Friday March 31, 2017 @06:45AM (#14002547)
Also, there is a kind "scoping" as well in Emacs. By way of convention. package-foo-var, etc. It reduces the odds of namespace conflicts by a lot.
Re:Thirteen Years of Bad Game Code by girvo on Friday March 31, 2017 @03:35AM (#14001824)
> stateless

Game development is kind of different, in that it's rendering the state of a simulation; so aiming for completely stateless solutions ends up making code quite convoluted -- you're hiding state rather than getting rid of it, in my experience.

Now, stateless functions are still well worth it, at least up until it's time to get it optimised for performance ;)

Game development is a fascinating world where a lot of the things I would normally reach for don't apply quite as well. It's quite likely you know all of this already, but I found learning this myself absolutely fascinating, and one of the reasons I still like to tinker with game development in my spare time :)

Re:Thirteen Years of Bad Game Code by taneq on Friday March 31, 2017 @09:26AM (#14003476)
Coming from a background mainly involving game development and control systems, this is one of the things that I find myself shaking my head at when reading HN. So many people here forget there's a software world outside web code, where memory and CPU time aren't effectively infinite, you're modeling processes and systems with continuously evolving state, and where trying to make everything immutable is just plain silly.
Re:Thirteen Years of Bad Game Code by geokon on Friday March 31, 2017 @12:05PM (#14005166)
Well my last job was working on simulations and I've only worked on performance sensitive system....

Making everything immutable maybe is silly, but it's still a very good goal to have in mind. A continuously evolving system can be designed in an mostly immutable manner as well without sacrificing performance.

In a big picture sense you are trying to have your system be a function of time. And while for efficiency you sometimes should preserve intermediate states, you can typically accomplish that with clever caching systems that are not exposed in the interface. So the design remains "immutable" in a sense

Re:Thirteen Years of Bad Game Code by smaddox on Friday March 31, 2017 @03:59PM (#14007576)
It's certainly not realistic to make everything immutable, but it's still worthwhile to move global state into some monadic encapsulation to make your code more testable and composable. This might not be an option on embedded systems, though, or for certain specialized hardware, e.g. GPU's.
Re:Thirteen Years of Bad Game Code by TeMPOraL on Friday March 31, 2017 @04:39AM (#14002042)
Since a lot of my programming experience is writing hobby engines and games (and reading up a lot of engine code and gamedev resources), I sometimes wonder how negatively does this impact my regular career (previously web, now desktop applications).

EDIT: to clarify, I mean the code I write, not my career prospects.

Re:Thirteen Years of Bad Game Code by cableshaft on Friday March 31, 2017 @10:33AM (#14004173)
I know several people who used to work in the video game industry, and I used to as well (I still may get back into it eventually). It's much harder to convince interviewers that you can handle the work than it is for you to be able to do that work.

Granted, there was a lot I've picked up over the past few years working for large corporations, but not all of it was good. And there's just as much awful code in business applications as there are in game applications, and it's even less fun to debug them.

Re:Thirteen Years of Bad Game Code by errozero on Friday March 31, 2017 @03:44PM (#14007428)
Bit of a tangent but how was the switch from web to desktop apps?
Re:Thirteen Years of Bad Game Code by TeMPOraL on Friday March 31, 2017 @05:33PM (#14008510)
Quite fine, actually. I like desktop apps better.

Architectural patterns are pretty similar in both; the primary difference is that in a desktop app, you deal with single user and a lot of impersistent state.

Re:Thirteen Years of Bad Game Code by errozero on Friday March 31, 2017 @05:42PM (#14008575)
I can imagine that would be a lot nicer, do you work for yourself? If not, how did you transition from a job in web dev to desktop?
Re:Thirteen Years of Bad Game Code by TeMPOraL on Friday March 31, 2017 @06:13PM (#14008804)
No, dayjob. I simply applied to a non-web company; turned out they make various software for use in factories.
Re:Thirteen Years of Bad Game Code by falsedan on Friday March 31, 2017 @05:19AM (#14002199)
> > stateless

I think they're going for 'immutable' instead of stateless.

Re:Thirteen Years of Bad Game Code by buzzybee on Friday March 31, 2017 @04:06AM (#14001933)
Decoupling isn't the same as statelessness. The state machine pattern used by OpenGL is a logical decoupling to the physical state of GPU hardware. State machines, buffers, protocols and the like - abstractions that we tend to think of as "low level" or "implementation detail" - are in fact the primary means of decoupling used when dealing with stateful systems. Computing hardware itself makes considerable use of these abstractions in providing modular interfaces.

Stateless abstractions are great when you can provide them. But the stuff you're building on isn't itself built out of statelessness.

Re:Thirteen Years of Bad Game Code by grey-area on Friday March 31, 2017 @06:25AM (#14002472)
but that's a dangerous mindset to start solving the problem with

A far more dangerous mindset is to think that when starting the problem you are capable of planning the perfect architecture up-front. Often you don't even know what the problem is. Far better to keep things coupled and simple till you know in retrospect that you need to split them out. Same goes for global state.

This is a hard lesson to learn. Abstraction is seductive.

Re:Thirteen Years of Bad Game Code by Nomentatus on Friday March 31, 2017 @01:21PM (#14005959)
I think about making an effort to loosely couple from the start as building in flexibility, which is useful precisely because "Often you don't even know what the problem is." Flexibility isn't a commitment to any particular abstraction of the solution, on the contrary it's the ability to dump any abstractions that you care to later on with less fuss. (Of course, you can still be unwise and decouple or create modules in ways that commit you to more than you realized.)

We agree that placeholder code shouldn't commit you to too much, but there are patterns that help you with that.

In the parent, the original decoupling turned out to be less performant (I take it) but wouldn't hinder completing the first draft or get in the way of a rewrite with closer coupling.

Re:Thirteen Years of Bad Game Code by buzzybee on Friday March 31, 2017 @07:04PM (#14009184)
The main challenge in abstracting for flexibility is that you are competing against your text editor. If copy-paste-modify introduces fewer new sources of error than any abstraction that is near-to-hand, then you end up in a scenario where it's actually the best option, because it is clearly reusable(in the sense of, hey, I can reuse it by copying it again) and it doesn't burden you with dependencies, so you can quickly try something and then delete it if it didn't work out. And for a lot of features, first-pass attempts, learning code - that's the space you want to be in. Cheap, dumb code.

This is what I started doing in the last year or two. Now my abstracted code tends to be directly motivated through refactoring the copy-paste stuff, with only a little bit of intentional architecture generated after learning that the abstraction addresses a common concern. It's a very cultivated way of developing the code - picking fruit as it turns ripe.

Re:Thirteen Years of Bad Game Code by Nomentatus on Friday March 31, 2017 @10:45PM (#14010111)
Abstraction isn't necessarily what loose coupling is about. It's worth some thought at the beginning to structure dumb code, to reduce waste and speeding up debugging. I agree the there's a useful element of Darwinism in coding, but Modules of cheap, dumb code are better than a big ball of mud made of cheap, dumb code. However it does depend a lot on how much you like rewriting and refactoring. Most people don't seem to. If you like it a lot, which I don't think is a bad thing AT ALL (it's just not common) I can see the attraction of starting with as much dumb code as possible and evolving from there. (But beware of local maximas.)

Even so, some decisions turn out to be extraordinarily hard to undo. One of my great blunders was a poor choice of data structure (too greedy with RAM it turned out.) The more experience you have, the more likely you are to sidestep those fatal early choices, of course.

Re:Thirteen Years of Bad Game Code by icebraining on Friday March 31, 2017 @10:14AM (#14003974)
A far more dangerous mindset is to think that when starting the problem you are capable of planning the perfect architecture up-front.

This sounds off to me; if you assume you'll need to change the architecture later on, aren't you better off starting with a decoupled system that can more easily be changed? Or are you essentially arguing for YAGNI, in the sense that decoupling upfront is potentially useless?

Re:Thirteen Years of Bad Game Code by wtetzner on Friday March 31, 2017 @02:57PM (#14006976)
> aren't you better off starting with a decoupled system that can more easily be changed?

I think the problem is that you don't know where the boundaries of your abstractions should be until you have a better understand of what it takes to solve the problem.

Re:Thirteen Years of Bad Game Code by grey-area on Friday March 31, 2017 @01:51PM (#14006234)
Yes, YANGNI. Not against all decoupling at all, but beginners tend to err on the side of too much structure.
Re:Thirteen Years of Bad Game Code by coldtea on Friday March 31, 2017 @06:18AM (#14002438)
>I shouldn't have done the gymnastics to decouple them!" .. but that's a dangerous mindset to start solving the problem with.

Is it, though? YAGNI comes to mind.

Re:Thirteen Years of Bad Game Code by TeMPOraL on Friday March 31, 2017 @07:52AM (#14002830)
My current rule of thumb is: if I know how to write it correctly, then I write it correctly. If I don't feel confident, I write the dumbest / most direct version that works to get the feel of the "lay of the land", and then refactor it later based on the new experience.
Re:Thirteen Years of Bad Game Code by coldtea on Friday March 31, 2017 @10:09AM (#14003903)
I like this rule (don't remember who said it): "Write code that is easy to remove, not easy to extend".