Meet the Crew: Tau Station’s Engineering and Vessel Mainframe

Meet the Crew: The Technical Team of Tau Station

Welcome to the second episode of our “Meet the Crew” series, introducing you to the teams behind our beloved scifi indie game Tau Station. Today, you’ll meet our technical team, responsible for Engineering (back-end) and Vessel Mainfraime (front-end).

While the Tales of Tau Station may be core to our experience, let’s be honest, you can’t keep anything flying without an engineer! A certain Firefly class ship would have been a-grounded long past, as would have the Enterprise, Death Star, and countless other space-faring vessels without a hearty crew of engineers and mainframe experts!

So too, does Tau Station stay in orbit by the loving care of our engineers and vessel mainframe crew!

Meet Emma – Chief Mainframe Technician

Tau Station ID of Emma

Tau Station ID card with a photo of Emma in front of the exhibited sheep "Dolly", the first animal cloned

Emma’s nick is bdhokey, she’s our Chief Mainframe Technician (front-end),  living in Scotland. Her weapons are JS and A11y, her strength is “always learning” while her weakness is chocolate stout. Her first game was Lemmings and her favorite things are tea, singing, music, stout.

Make time for your life Emma

My Web Accessibility Testing Tips

I want to share two sources that I think are helpful for people starting out in development and testing for web accessibility.

  • WebAIM has lots of easily understood resources. In particular I recommend their quick reference – for a clear guide to the process with equally clear explanations of technology and techniques, and tools that can be used straight away.
  • The A11y Project – is ‘a community-driven effort to make accessibility easier’ offering detailed information on development and testing and a comprehensive compilation of resources

Meet Pete – Chief Engineer

Tau Station ID of Pete

Tau Station ID card of Pete, team lead of the technical team for back-end

Peter Mottram’s nick is SysPete, he’s our Chief Engineer (back-end) from Malta. His weapon is Perl, his strength is “solving problems” while his weakness is Belgian beer. His first game was The Valley (Computing Today April 1982) and his favorite beer is Westmalle Dubbel.

“I love deadlines. I love the whooshing noise they make as they go by.” Douglas Adams, The Salmon of Doubt

My favorite code

This is not really what I wanted to show as an example, but the things I’m most happy with are just way too big to show any code snippets.

Our players are clever, and like to find ways to get more than we expected when they perform an action. They find interesting ways to multiclick, or do fast page refreshes, instead of waiting for the page to complete loading and then clicking the next action. We can use JavaScript to try to paper over issues like this, but such mitigations are easily circumvented client-side, so we created our one-time URL “nonce” system.

When a nonce is attached to a URL then any second, or subsequent click, is simply ignored by the game. We use a Catalyst ActionRole along with a simple helper to add the nonce and verify it. So, instead of a URL like:


https://taustation.space/career/attempt/opportunist-practice-hacking-locks

we now have a URL with the nonce appended:

https://taustation.space/career/attempt/opportunist-practice-hacking-locks/be73f4fb3c1326a898220b16ce9a876ee046c9ed

Nonce checking is handled by the ActionRole, so inside a controller we simply add attributes to the action sub:


package Veure::Controller::Career;

sub attempt Local Args(1) Does(Nonce) Nonce(career_task) 
    NonceDetachTo(denied_attempt)
    : ( $self, $c, $career_task_slug ) {
        # attempt is allowed, do something...
}

sub denied_attempt Private : ( $self, $c, $career_task_slug ) {
        # not allowed, do something else...
}

A simpler controller action might not need an action-specific nonce, or a custom action on fail, making the action really simple:


sub thing Local Args(0) Does(Nonce) : ( $self, $c ) {
    # thing is allowed...
}

Meet Noel – Engineer

Tau Station ID of Noel

Tau Station ID card of Noel

Noel’s nick is Zhtwn, he’s one of our Engineers (back-end) from USA (Earth). His weapon is Socratic Rubber-Ducking, his strength is “obsessive analysis” while his weakness is “obsessive analysis”. His first distro was SLS Linux and his favorite activity is Exploring the tangible and intangible.

“Deep in the fundamental heart and mind of the universe, there is a reason.” Slartibartfast

My favorite code

One of the bits of Tau Station code that I’m most proud of is actually the YAML that we use to configure our shared DBIC Row cache (and of course, the actual code that implements this cache). The Station cache is configured
like this:


Station:
    enabled: 1
    lifecycle: permanent
    index_fields : [ 'slug' ]
    order_fields: [ 'level', 'name' ]
    prefetch: [ 'affiliation' ]
    subcaches:
        all_active:
            predicates: ['active']
        all_for_star_id:
            partition_fields: ['star_id']
        all_active_for_star_id:
            partition_fields: ['star_id']
            predicates     : ['active']
        all_for_star_id_affiliation_slug:
            partition_fields: [ 'star_id', 'affiliation.slug' ]

which allows us to use any of the following accessors, doing no more
than one database query per accessor, and never retrieving a given
Station from the database more than once:


# get Station by station_id
$station = $cache->station->for_id($station_id);

# get station by station_slug
$station = $cache->station->for_slug($station_slug);

# get all stations, ordered by level and name:
@stations = $cache->station->all;

# get all active stations, ordered by level and name:
@stations = $cache->station->all_active;

# get all active stations around the given star
@stations = $cache->station->all_active_for_star_id($star_id);

# get all stations around the given star with the given affiliation
@stations = $cache->station->all_for_star_id_affiliation_slug( $star_id, $affiliation_slug);

Meet Florin – Engineer

Tau Station ID of Florin

Tau Station ID card of Florin

Florin’s nick is MeSe, he’s one of our Engineers (back-end) from Romania. His weapon are Jokes, his strength is “making people laugh” while his weakness is “any food”. His first game was Super Mario Bros and his favorite activity is playing guitar.

“Trying is the first step toward failure.” Homer Simpson, The Simpsons

My favorite code

One part of the code that I like is the query that decides which of a character’s bodyguards steps in a fight next.

We have four types of bodyguards:

  • warden – tied to the station on which the bodyguard was hired
  • escort – travels with character but only in the star system where the bodyguard was hired
  • guardian – travels with character in the whole Tau Station universe
  • sentinel – accompanies character everywhere and provides character extraction to a safe area if a conflict occurs

First we see which of the character’s bodyguards are available (not already involved in a fight or currently recovering in Sickbay due to a fight) on the current station. We sub-query then by bodyguard qualities.
We consider the sentinels the most useful in a fight, due to their capability to extract the character from a conflict area. Then we also need to consider bodyguard rank, so that we provide the most powerful ones with priority.


sub get_bodyguards_sorted_most_qualified_first ($self) {

  my $order_by = [
    \"CASE WHEN type=‘sentinel’ THEN 1 ELSE 2 END",
    {
      '-desc' => [
        'tier', 'bodyguard_company.bodyguard_company_id',
        'start_date'
      ]
    }
  ];

  return $self->available->search(
    {},
    { prefetch => 'bodyguard_company', order_by => $order_by }
  );
}

Meet Curtis – Captain

Tau Station ID of Curtis

Tau Station ID card of Curtis Poe, project founder, and also member of the technical team

Curtis Poe’s nick is ovid, he’s the Captain of Tau Station in France while being an Engineer (back-end). His weapon is Perl, his strength is creativity while his weakness is “Single Malts”. His first text-based game was Zork and his favorite author is Charles Stross.

Do not follow where the path may lead. Go instead where there is no path and leave a trail.” Ralph Waldo Emerson

My favorite Code

My favorite piece of code is our partial classes. This was a technique we adopted early on when it became clear that your character could do many, many things and the “single-responsibility” guideline for class design actually turned out to be a hindrance. But packing too much responsibility into a class can result in “god objects” which do too much and are hard to maintain.

Instead, we compose some classes out of multiple “partial classes”, each of which has a single responsibility. It’s made our code both easier to read and easier to maintain.

Rationale

I was trying to do the right thing and follow the “single responsibility” principle so that each class had one and only one responsibility. Thus, my Mission class might handle all mission-related behavior and I had code like this:

if ( $missions->has_missions_for($alice, $bob) ) {
    ...
}

But even though I wrote that code, I could never remember if Alice had a mission for Bob or vice versa. I had to look it up every time and that’s a hallmark of fragile code.

The reason it was fragile is because in linguistics, that’s a verb-subject-object (VSO) structure. However, in English, we almost always use subject-verb-object (SVO), and the VSO structure is very confusing to us.

What I wanted to write was:

if ( $alice->has_missions_for($bob) ) {
    ...
}

That’s SVO and it’s no longer ambiguous. Thus, our code becomes easier to
read. I decided I wanted to use SVO everywhere in the code base to avoid these problems.

Except that our character class potentially has knowledge of missions. And there are plenty of other examples of where I could push knowledge of other parts of the system into the Character class and turn the Character class into an unmaintainable God Object. The surface code would be easier to read, but the underlying code could be a nightmare.

I thought about this for while and considered partial classes. There are several ways of implementing them, though today, the C# implementation is probably the best-known. With partial classes, you create several classes which can be composed into a single class, but each partial class has a single responsibility. In Tau Station, we use Moose for our object-oriented code and Moose provides roles, which gives us the ability to separate class responsibility and class behavior. Thus, our Character class could be implemented with the following pseudo-code:

package TauStation::Character;

use TauStation::Moose;
with qw(
  TauStation::PartialClass::Character::Career
  TauStation::PartialClass::Character::Inventory
  TauStation::PartialClass::Character::Mission
  TauStation::PartialClass::Character::Movement
  ...
);

While some might argue that TauStation::Character is still a “god object”, we’ve been using this approach for years and it’s turned out to be very maintainable and allows us to use the intuitive SVO structure for our method calls.

Keep Flying…