GCS Professional Programmers Panel is Back

Last year and the year before, we did a panel at GDC's Game Career Seminar for students (and others) to ask questions of professional programmers. We're doing it again this year, and we want your questions!

If you have questions, you please tweet them with the hash tag #gcsppp and we'll select the best to be part of the panel. In addition, I'll be watching that hash tag during the panel and pulling our favorite questions from the audience to ask the panelists.

Our panelists this year are:

  • Mike Acton - Engine Director at Insomniac Games
  • Brett Douville - Formerly Lead Programmer at Bethesda Game Studios, now independent
  • Anna Kipnis - Senior Gameplay Programmer at DoubleFine
  • Sven Bergström - Developer for Celsius game studios and underscorediscovery

If you have questions for them, be sure to get them in early, and we hope to see you at the panel!

The Importance of Genre

Over GDC, I talked to a lot of people about genre, being generic, and how important that actually is.

Being a part of a genre (and being generic) is sometimes looked at as a bad thing, especially in many indie developer circles. But, understanding genre, and what genre you'll fit into is extremely important.

Genre is one of the major ways people connect to something new. By comparing their experience to things they've seen in the past, audiences can quickly form a basis for any deviations from generic form. If you present something entirely new, or something that deviates so far from genre that it gives no tangible attachment points, anyone can get easily confused and frustrated. This is consistent in all mediums, including writing, music, movies, and games. Whenever you hear about a work or medium that is "ahead of its time" this is usually because it gave audiences nothing to latch onto from a generic perspective. It takes time for people to be eased into new conventions. Genre is one of the major things that helps them do that.

I came to this realization during GDC, and it explained one of the reasons why I felt Fire Hose's first game, Slam Bolt Scrappers, did not do well. Among other problems, it didn't give players any generic hooks. And in places where a generic hook might have been made ("Ah this is like tetris!") it turned too far away from the convention ("but you make squares, not lines, and of matching colors."). In its attempt to mash up two genres, it missed the boat on creating the generic hooks for either one. When you approach SBS, it's confusing, not necessarily because the game itself is confusing (though it is), but because it doesn't offer a single place were a player can say "AH! This is like Game X." This is something that's worn as a point of pride by many indies, but really shouldn't be.

This is not to say games need to be completely generic, in fact just the opposite. AAA has found itself relying too much on generic convention to hold the weight of gameplay, and it is starting to backfire, if only slightly. When you rely too much on genre, the medium starts to stagnate. People know they've seen it all before, and feel no need to engage with new products. It's only when creators twist generic conventions in interesting ways that the medium can evolve, and even create new genres.

More recently, I've been thinking about the future of the living room, and how the various media companies are vying for dominance. I think that the future of media in general is going to rely on a company taking advantage of their individual genres of consumer fulfillment, and expanding to service new needs and new opportunities. The company that does that well can "win the living room," but all three top contenders are still far from giving us the "genre" that we can attach to, and a few have even taken a step backwards in the process. But, I think I'll leave that to another post.

GDC 2013 – Programmers Panel

GDC is over, and it was fairly awesome. I'll have a quick "thoughts on GDC" post later, but I wanted to get the information for the GCS panel I participated in up as soon as possible.

GDC did not record this panel this year, but thankfully, we have a fairly good unofficial recording of the panel thanks to Jeremiah Ingham. (sssshhh, don't tell GDC)

You can also just download the file, if you'd like.

The only real resources we recommended this year were at the end, where I asked each of the panelists recommended a book, and here they are:

If you have other questions of the panelists, please feel free to ping us on twitter. We're all pretty approachable (especially if we can respond in 140 characters or less).

Using Waf to build an iOS Universal Framework

I've used a lot of build systems, and so far my favorite (when I'm "forced" to use something outside of Visual Studio) is probably waf.  Besides being based on a proper scripting language, waf doesn't feel like it's doing a whole lot of "wicked voodoo magic" behind the scenes (like scons sometimes does).  It's also fairly easy to extend, and we used it to make and deploy all of our Nacl executables.

Today, I figured out a way to make waf do some interesting things concerning iOS and creating libraries / frameworks.

iOS Universal Frameworks require that you create libraries for 2 versions of the simulator (i386 and x86_64) as well as 2 versions of ARM (armv6 and armv7) if you want to run on all of those platforms.  Each of these libraries is then linked together using a tool called lipo.  Waf can easily build one library, but building multiple, especially as part of one build step, can be tricky.  What you do is create a separate environment for each target, then link them together in a single build step. Here's how it goes.

First, waf doesn't understand how to handle .m / .mm files and pass them on to clang properly, so we want to teach it how to do that. The simplest way to do that is like so:

@TaskGen.extension('.mm')
def mm_hook(self, node):
    "Bind the c++ file extensions to the creation of a :py:class:`waflib.Tools.cxx.cxx` instance"
    return self.create_compiled_task('mm', node)

class mm(Task.Task):
    "Compile MM files into object files"
    run_str = '${CXX} ${ARCH_ST:ARCH} ${MMFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CXX_SRC_F}${SRC} ${CXX_TGT_F}${TGT}'
    vars    = ['CXXDEPS'] # unused variable to depend on, just in case
    ext_in  = ['.h'] # set the build order easily by using ext_out=['.h']

This will use whatever the CXX compiler is set to (which we'll set to clang) using MMFLAGS over CXXFLAGS or CCFLAGS. Everything else will stay the same. This can be added anywhere in the file, but I tend to add it under configure, before build.

Next, we set up configure to create an ios base environment, off of which we're going to base other targets.  Because I use this script to build for multiple environments on multiple operating systems, I check to make sure that this is being performed on Mac OS before creating the environment.

IOS_MIN_VER = '6.0'
IOS_SDK_LOC = '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneSimulator6.0.sdk'
IOS_SDK_SIM_LOC = '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator6.0.sdk'

def configure(conf):
    # ... Any other configure steps
    
    # Make sure we're running on a Mac
    if sys.platform.startswith('darwin'):
        conf.setenv('ios')
        # Set the C++ plugin here to use clang over gcc  g++
        conf.env.CXX = 'clang'
        conf.env.CC = 'clang'
        conf.env.LIPO = 'lipo'
        conf.load('gxx')
        conf.load('gcc')
        # set any CFLAGS, CXXFLAGS, MMFLAGS and DEFINES for ios in general

Next, we create an environment for each target (debug or release) and each platform (i386, x86_64, armv6 and armv7). If you're not targeting an x86_64 simulator or an armv6 device, you don't need to build these, but since post first build this is fairly quick, I just build all of them.

        for arch, tgt in itertools.product(['i386', 'x86_64', 'armv6', 'armv7'], ['dbg','rel']):
            conf.setenv('ios')
            newEnv = conf.env.derive()
            newEnv.detach()
            conf.setenv('ios_' + arch + '_' + tgt, newEnv)
            #... set any target specific flags 
            # These flags set up the sysroot for ios based on simulator or device
            if arch.startswith('arm'):
                addflags = [ '-mios-version-min=' + IOS_MIN_VER, '-isysroot' + IOS_SDK_LOC ]
            else:
                addflags = [ '-mios-version-min=' + IOS_MIN_VER, '-isysroot' + IOS_SDK_LOC ]
            conf.env.CCFLAGS += addflags
            conf.env.CXXFLAGS += addflags
            conf.env.MMFLAGS += addflags    
            conf.env.ARCH = arch

Now we have to create commands that use each of these environments. This is exactly the same as using multiple variants / platforms, if you've seen that example. The other thing we're going to do is make a LIPO command for each target, so we don't have to re-specify how to LIPO our libs together (this is useful if you've got multiple like I do).

def init(ctx):
    # any other architectures / platforms

    for arch in ['i386', 'x86_64', 'armv6', 'armv7']:
        for tgt in ['dbg', 'rel', 'retail']:
            for inheritingClass in (BuildContext, CleanContext, InstallContext, UninstallContext):
                name = inheritingClass.__name__.replace('Context','').lower()
                class tempClass(inheritingClass):
                    # this is used in the next step to actually call the step
                    cmd = name + '_ios_' + arch + '_' + tgt
                    # This must match your environment name, and sets the output directory
                    variant = 'ios_' + arch + '_' + tgt  
                    # These are for testing in your build script, if you need them
                    architecture = arch
                    target = tgt
                    platform = 'ios'

      for tgt in ['dbg', 'rel', 'retail']:
          class tempClass(BuildContext):
              cmd = 'lipo_ios_' + tgt
              fun = 'lipo_ios'
              variant = 'ios'
              target = tgt
              platform = 'ios'

Last, we create a build_ios command to build all the variants for a target (I default to release), and a command called lipo_ios to LIPO each one together. Here's how it goes.

def _lipo_lib(ctx, lib_name):
    ctx(rule='lipo -create ${SRC} -output ${TGT}',
        shell = True,
        target = 'lib%s-%s.a' % (lib_name, ctx.target),
        source = ['build/ios_%s_%s/lib%s.a' % (x, ctx.target, lib_name) for x in IOS_ARCHS]
    )

def build_ios(ctx):
    for x in ['i386', 'x86_64', 'armv6', 'armv7']:
        waflib.Options.commands.append('build_ios_' + x + '_rel')

    waflib.Options.commands.append('lipo_ios_rel')

def lipo_ios(ctx):
    """ This creates universal libraries in ios_target made from the architecture 
        builds of each lib. """
    _lipo_lib(ctx, 'A')
    _lipo_lib(ctx, 'B')
    _lipo_lib(ctx, 'C')

So this is not at all straight forward, and took a lot of trial and error, so hopefully this helps some people.

The upshot here is that waf's dependency detection in terms of libraries is way better than XCode's, so you can use multiple dependent libraries together and it will only ever rebuild exactly what's necessary. However, the preprocessor that determines include dependency only supports C / C++, not Objective-C's #import directive. So I would avoid doing this if you're working a lot with Objective-C dependencies, at least until waf gets real objective-C support.

Also, you could use these same principles to create build_ios_simulator and build_ios_device targets instead, without too much effort, but I like having all targets build into the universal libs, and going from there.

More Speaking Engagements: UVA, VCU and AltDev

I've got a bunch more speaking engagements lined up!

First up, the weekend of November 10th I'll be speaking at the Alt Dev Student Summit, with a talk titled OOP Is the Root of All Evil, of course riffing a bit off of the phrase "pre-mature optimization is the root of all evil." The idea behind this talk is that pure OOP, especially OOP that doesn't think about how data is going to be used or the performance tradeoffs incurred, is pre-mature pessimization, and that frequently the argument that OOP makes more understandable, more reusable, or more maintainable code is frequently an illusion. I'll also be looking at how certain OOP patterns actually promote bad coding practices, but are used because they're considered OK from a pattern perspective.

Earlier, on October 30th, I'll be speaking at UVA to the Student Game Developers club, doing a dry run of my talk to the AltDev Student Summit.

Lastly, on November 6th, I'll be speaking at VCU to their chapter of SIGGRAPH. This will be the same talk I gave at JMU earlier this year called Getting Started Making Games. I am still planning on recording a shortened version of this talk for posting online, and I still need to post the slides. This will hopefully happen shortly.

More on Open Offices

After my talk with Mike on Leadership, we got into a discussion about open vs. closed office spaces. Mike is in favor of the open office while I (obviously) am not. Mike's assertion (which I actually agree with) is that you can create an interuptionless culture in an open office space, and still get the benefits of an open space that removes the psychological barriers to communication. In addition, Mike asserts that, if a person knows they're going to have to have lots of uninterrupted time, they can always work from home (not necessarily true, but I'll give him the benefit here).

These are two just fundamentally different approaches: one that favors open communication, and creative collaboration, versus one that favors individual productivity, potentially at the expense of team productivity. However I believe that closed offices are better for two reasons.

First, I believe flow and interruptionless work are important to personal productivity and job satisfaction. This doesn't mean that I believe that everyone should always go uninterrupted all the time, but that a culture that minimizes these by default is important.

Second, because I believe it is easier to foster an open culture in a closed office than to foster a closed culture in an open office. What this means is that I think that you can work very hard to foster a culture of few interruptions and respecting people's time and space in an open office, but that when it comes down to it, the open office itself works against this. In contrast, while a closed office makes open culture harder, but does not necessarily work against an open culture, especially if said office provides open spaces as well.

With all of this said, Mike also pointed out one very key point:

Most likely, neither Mike nor I are ever going to be in a position to actually be able to plan out an office.

Speaking at JMU: Getting Started Making Games

Next Wednesday (October 3rd) I'm giving a talk at James Madison University to their ACM. Although they've labeled it a "Tech Talk," my actual talk is going to be much more general, titled Getting Started Making Games. It's inspired by this talk and website, but moves beyond what tools you can use and resources are available to give some real practical advice on how to make your first games, and what constitutes a reasonable first game. Then I'll tackle where you can go from there, and discuss techniques for failing early, and avoiding productivity black holes.

According to the ACM people, the talk is open to non-students so if you're in the area, drop by HHS 1302 at about 7:30 and say hi!

Open Environments in a Closed Office

I've been railing against open offices and office meetings (especially micro meetings) on my blog for the last few weeks, and I have one more thing to add to this series. I'd like to talk about creativity in a "meetingless" / "interruptionless" office. Generally, people that believe in open offices believe in the creativity of the micro-meeting, and they believe in the collaborative power of spontaneous large group meetings (hence the open office). There is some truth to the fact that a spontaneous large group meeting, or hallway discussions, can lead to some very interesting and creative decisions. But why? And how can you create a creative environment within a constraint of few to no meetings?

First, let me say that an interruptionless office does not mean that there will be no hallway discussions, discussions over coffee, lunch, donuts, etc. In fact, I've found that even in semi-closed offices, these happen more often, because people feel more at liberty to just walk around. There's no chance of them disturbing anyone directly, so when they feel the need to be creative, they'll wander the halls, go to the cafeteria, or sit in a lounge, and just talk.

Second, as I talked about in the "Meetingless" post, a Meetingless office doesn't have no meetings, it just creates a culture of most group meetings being optional, minimizes interruptions caused by meetings, creates times that are guaranteed to have no meetings, and creates alternatives to split-second, micro meetings and micro decisions that I feel are an overall team detriment.

In general, there are three things that I feel open offices achieve automatically, that a closed office needs to work on:

  1. Removing psychological barriers to communication. As I've stated before, I admit that walls create psychological barriers to communication. To remove these you need to create an atmosphere that people are approachable in and outside of their office. Team building (the next point) helps with this, but managers, and leaders have to take extra steps to make sure that they are approachable. A few suggestions are to implement skip levels, hold frequent one-on-ones (which you should be doing anyway) and to meet outside your office. Coffee shops and established open areas in the office are great for this.
  2. Foster team building.  This doesn't mean everyone has to do trust falls, but it does mean you need to make efforts to bring the team together. This can be anything from catering lunch (which is what Fog Creek does), hosting in office Happy Hours, office Board Game Night (a personal favorite), or other office parties. Just make sure people mingle.
  3. Create open spaces for work and discussion.  This may sound like it goes against everything I've said, but I do still believe in having portions of the office be open spaces. Sometimes, you want to get out of your office, sit on a couch, and relax. Maybe go with a few other team mates to look over a problem. Maybe discuss something in a smaller open environment. Make these comfortable spaces and give employees the means to work in them (laptops or otherwise portable workstations, whiteboards, lots of power and wireless) and people will.  Even more so if they know they won't disturb others by doing so.

Generally, I feel like, cost aside, closed offices create happier, more productive employees, and that the benefits of an open office can be simulated more readily than those of a closed office.

The Interruption-less Office

In a previous post, I talked a bit about why I'm not a fan of open offices, and one of the main reasons is because they are too prone to various types of interruptions that actually keep creative people from being "in the zone." In addition, the types of "meetings" that happen in open offices can actually create a culture where split second decisions and decisions between small groups are the "norm." While this is fine in smaller studios, it can become an issue as teams get larger.

First, let's look at the common types of meetings that are encouraged in an open office, or one that encourages meetings, and see how we can remove most of them.

  • Quick Questions – You know these meetings because they're always prefaced with the person interrupting you saying, "Hey, quick question…" Frequently these are anything but quick, and almost always it is not imperative that they be answered immediately. However, in an open office, the person will frequently ask you directly, which means you need to give an immediate response. These meeting can be handled in private chat rooms where the question can be either answered by someone else or answered at a more opportune moment.
  • Class A Bugs – These are bugs are actively blocking, and need to be fixed ASAP (and I'm talking actually ASAP, in that people are actively losing work). These things happen. My recommendations for this are, first, make sure that all bugs are documented and tracked. Frequently with class A bugs like this, people just report it to the person they "think" is responsible verbally. If they're wrong, you can get two people working on the same bug at the same time, which can be hugely problematic. Once the bug is documented and tracked then you can interrupt the responsible coder (or producer responsible for assigning it).
  • Micro Meetings – Micro meetings are when (usually) two people decide to discuss an issue quickly to try to come up with a solution. These actually have two forms:
    • Idea bouncing – One person has an idea they want to flesh out, or run past someone, and just wants to talk it out. Frequently, this doesn't actually require the other person, just something to talk to. (I know a designer that keeps a stuffed monkey on his desk for exactly this purpose). I'm actually okay with these types of meetings provided they do not actually interrupt someone's work
    • This Isn't Working – These meetings come about because someone feels something "isn't working" and needs to be reworked. In my experience, these meetings have several drawbacks, besides the interruptions they frequently cause. First is that they rarely involve all of the people that need to be part of the decision making process, which means that  certain people are left out of the loop and surprised by changes they didn't know were going to happen. Second, these meetings frequently cause or require snap decisions without a real good amount of thought, which can be problematic. Lastly, decisions made at these meetings can contradict other decisions that were already made and documented. Now not only do you have a change that isn't documented based on a decision process that isn't documented, but it contradicts documentation that does exist. Again, these are probably better handled in group chat rooms, so that all people invested can see the discussion, the decision, and update the documentation accordingly.
  • Micro Meeting Turned Team Creative Session – This is really what people that want open offices cite as a benefit of open offices. Start with a "This Isn't Working" micro-meeting which becomes a full fledge, whole room creative discussion about how various systems and designs should work, interrupting everyone. The results of these meetings can be great creatively, but because they're always impromptu and records are scant, decisions made can affect entire teams without their knowledge or input. These meetings have the same all the same drawbacks as micro meetings, except with the added benefit of you keep several members of your team from working (including those that aren't in the micro meeting) for several hours. These should be avoided at all costs
  • Actual Meetings – Then there are actual meetings, which I'm not against, but only in certain forms, which I'll talk about in a bit.

In general, you should be always be striving to move to an "interruption-less" and "meeting-less" office. But, there are a few types of meetings that I'm okay with, with one caveat: you should strive to have days with no meetings at all, and as many of them in a row as possible. In addition, if you can schedule meetings to overlap with other times that people are taking breaks (lunch, for example) this means you're not interrupting actual work flow. This gives people lots of time to get into the groove not only on a single day, but multiple consecutive days.

The type of meetings I'm generally okay with:

  • Review Meetings – We have to review our work. Artists need art review, coders need code review, designers need design review and the whole game needs to be reviewed as a whole. It's important, and frequently it's important to do this with groups rather than one on one (depending on the type of review). If you can get these to be outside of meetings with tools (like Review Board) that's great.
  • Creative Meetings – Large group creative meetings can be great, but they have their own place and time, and their own rules. This is the subject of another post.
  • Planning Meetings – Generally I'm okay with planning meetings, provided they're shorter. This is for sure a good candidate for a lunch meeting.

Any other types of meetings I'm missing? Do any of these meetings work better in an open office? Am I right about most of these meetings being avoidable?

On Air Hangout with Mike Acton

In case you haven't heard, this coming Monday, September 10th, I'm doing an On Air Hangout with Mike Acton, talking to him about his thoughts on leadership. If you can't tell from my recent blog posts, leadership, and how to be a good leader, are new interests of mine. So, I'm super excited to talk to Mike about his role not only as a lead at Insomniac, but also about his role as an industry leader, and get his thoughts on how to create better leaders in the game industry.

On Air Hangouts are cool because they are recorded and posted to You Tube immediately after they're done, and as soon as that happens, I'll post the link to the recorded hangout here.

Update: If you missed it, check out the results of the hangout on You Tube, and let me know what you think!