Tuesday, 19 January 2010

Designing things very carefully.

The Complex System:

We all know that software architecture is important in large projects. We've all envisioned systems to help us maintain larger and larger complex problems with less user or developer input. Scripting systems, shader building tools, data-driven editors, and many other cool things that would take a long time to write properly, but when they're done they're a great benefit to everyone that uses them.

Except half finished, they're worse than useless.

I work in games, and games are highly complex systems of interactions. Games would take forever to write if they were written correctly with all the great and clever architecture they should have, so producers push for a minimum feature set, veto the clever architecture and demand a simpler approach to the solution.

Later on in the project, usually about half way through to maybe three quarters, the project starts to slow down due to growing complexity and difficulty separating sections of code from each other. When production asks why it is, often the coders will say that it's because the way it's written is wrong, it needed more abstraction or better architecture, or just more time spent on the design stage, and less time on just getting features in.

The bad programmers say "oh, noes, we should have designed it betterer from the beginning. We told you that we should have written all the code that was only marginally likely to be necessary, but would have been fun to write and figure out."

However, the good coders would note that only small proportion of the code that they would have written, is now necessary. They will be note the time saved by writing code that does the job rather than over-architected super-code that could do anything, and breath a sigh of relief that all they have to do is one month of overtime getting the final features in place, rather than a year of overtime getting the "correct way to do it" code working at all.

In fact, when I've been on over-engineered projects, the one thing that has come to bite us more than anything else has been the inability to refactor the code because it is too complex or too clever for a single human to understand.

Complexity When Necessary:

There's a big difference between sloppy coding and coding to requirements, but it seems that the longer I spend in software engineering, the more I find people thinking that they are the same thing. I realise that a lot of people architect away because they think reuse is good and encapsulation and data hiding this that and the other, but we don't actually reuse a lot of our code because it's usually game specific, genre specific, platform specific. The stuff that isn't, is usually our "we brewed our own because we didn't trust 3rd party software", or just generally us reinventing the wheel for small sections of module specific code. If you're lucky, you'll get a series of games that just need new art, that's real code reuse, never need to actually do more than change some constants and recompile for a new game. If you think you can write reusable code, they why haven't you released it as a library (whether for sale, or for free)?

Tell me that it's really important to write a fully data driven engine to power your next game, and I'll remind you that your consoles and PCs already have a powerful and fast, data-driven, flexible, ready-for-anything fully-supported easily-debuggable and profilable, and generally very well documented system. The system is C/C++. Why don't you write some game in it?

Monday, 11 January 2010

Deleting Code

I've learnt that keeping old stuff around is handy, but dangerous.

http://folklore.org/StoryView.py?project=Macintosh&story=Negative_2000_Lines_Of_Code.txt#

I've been a hoarder for years, but over the last few months I've come to appreciate reducing code even more than I'd thought possible. I've never been one for liking big bloaty code, but in the end, our company engine at Broadsword got a bit large. Working on a new engine has given me the freedom to destroy. It's been fun and educational. You spend less time maintaining and more time making only the right stuff work right. Join this with my new approach to problems (code it first and fast, then refactor optimise refactor), my game has come along at a startling pace.

Now, any time I want to do something I've done before I'll try to copy in from the old engine (code reuse), but if it's novel, it gets given a bit of time, not much though. Time is the only asset I have available to me, so I always take the very shortest route to the solution, and at the moment I haven't hit any horrible problems because of it. In fact, after only 58 hours of coding (and design and photoshoppery) I have a game demo up on my development blog. I'm both pleased and surprised at how quick I can code (and art and design) when I don't think about the bigger picture all the time. It might be that I've been doing games so long I don't do stupid things any more, but it also might be that "future thinking" is pace destroying. I'm not sure which, but I think that my experience has helped reduce the amount of time necessary to make things happen.

Does that mean we should all train up in large companies then go out and make small applications forever more?

Tuesday, 5 January 2010

Classes in H files

While working on my homebrew game, I noticed a thing I'd never really considered before. I've been thinking about compile times and link times recently and this one clicked as a fresh thought.

When you include your classes in header files, you automatically add complexity in the project through the header includes that are necessary to compile the class, and the link time complexity of the methods of that class being linked if used.

We know that the linker doesn't try to link methods that aren't called, as we've probably quite often seen classes written without their implementations as half done cases. So what's wrong with adding class methods? It's quite simple: all the methods that are implemented in a class are subject to being possibly linked at some point and therefore become one more item in the linkers list of suspects.

That's for every class you write.

There's no simple way of stopping the linker from giving access to class methods. There is a simple solution if you use global functions. You can use static global functions for your implementation details.

This thinking lead me to go half way on my game with my change from putting classes in headers to putting them as worker objects in the source files, and then operating them with global functions where possible. I think there might be a way to remove the class symbols from the objects, but until I find it, at least I'm ready, and thinking good for large-scale development. The class in question was a game level class that contains the stuff for managing the game level. The overall game needs to know very little about the class, just that it's running, and that it can be managed (transitioned) and saved (serialised). This simple interface is quite different from the internal workings and therefore the header would have had to include all sorts of unnecessary information. I think this is proper data-hiding and encapsulation rather than the C++ textbook version.

I'll keep tabs on this and see how it goes.