My Journey as Tech Lead : Designing a Self Assembling Module Integrator (Part 7)

Wafi Harowa
Kolektif Gamedev
Published in
7 min readMar 13, 2020

This article is part of my series “My Journey as Tech Lead” where I share my experience as Tech Lead on creating technical foundation for my team. What kind of challenge I have to solve and my thought process to solve them.

You can follow this series from the start by going into the link below.
My Journey as Tech Lead (Part 1)

Our goal is to create a Self Assembling Module Integrator with these criteria :

  • Modular : Each module is independent of each other
  • Customizable : Each module can be customized for different game needs
  • Flexible : Can choose and change third-party vendor easily

Architecture Layer

The first step we need to do is designing Architecture Layer for our Module Integrator. To do that, we have to understand the architecture layer of a common mobile game implementation.

A typical mobile game development use several third-party service vendor (SDK and plugin) in their game. A common implementation is by connecting the game directly into third-party vendor.

Mobile Game Architecture Layer

This architecture is straightforward, but have a Technical Flaw. It creates technical issue when we need to update the the third-party service or when we need to change it into a totally different technology. When that happen, we need to remove all integrated component from previous third-party vendor then integrate a new one. This process takes a lot of effort and time to do.

So, how do we solve that problem ?

The problem above is caused because the game is Coupled directly into the third-party vendor. The solution for solving coupling problem is by Decouple it. We can decouple it by creating an additional layer between the game and third-party vendor. This additional layer acts as Abstraction, and the actual third-party vendor acts as Implementation. By separating the abstraction from the implementation, we can change the implementation without modifying Game Integration.

Let say we need In Game Advertisement feature in our game. Initially we want to use Facebook Ad in our game, but then we want to change it using Admob. Using our new design approach, instead of connecting the game directly into Facebook Ad, we create an abstraction layer. Lets call it Advertisement module.

This Advertisement module is responsible to providing the game the API to show ads in game. This Advertisement module also connect into Facebook Ad to provide In-Game Advertisement capability. When we remove Facebook Ad and changes to Admob, the advertisement module redirect the connection into Admob.

This design approach solve the issue of coupled game code into third-party service. This design however, also have Technical Flaw. It causes technical issue when a same third-party vendor is used for multiple different abstraction. Let say we are using Facebook SDK not only for Advertisement (Facebook Ad), but also for Account (Facebook Login) and Analytic (Facebook Analytic).

With this design, we have 3 different connection to Facebook SDK that does not know each other. This can cause Racing or Multithreading issue when two process is executed at the same time. To solve this issue, we need to add another layer between abstraction and implementation layer.

We can call this layer as Coordination layer, which purpose is to coordinate access to SDK from different module. With this new approach, we allow multiple abstraction module to connect into the same third-party vendor safely.

To communicate the idea better, we identify modules as follow :

  • module in Abstraction Layer as Package
  • module in Coordination Layer as Integrator
  • module in Implementation Layer as Thirdparty
Our Module Integrator Architecture Layer

This way, the game never connect directly to third-party vendor. This architecture can only works if we also have a way to easily disconnect and redirect connection into different third-party vendor.

In order to achieve that, we need to define several Design Principle.

Design Principle

Design principle is a set of principles to follow in order to have a specific functionality. In our case, we define several Design Principle to allow us to fulfill the desired criteria and to make sure our architecture design is working as intended.

Modularity Principle

Modularity principle means Independent. Every module is independent with other module.

This principle can be achieved by following several rules :

  • Folder : Every module must be contained within a single folder.
  • Namespace : Every module must be contained in a unique namespace.
  • Safe Couple : Every connection to other module must not cause error when that module does not exist.

Integrated Principle

Integrated principle means Auto Integration. Every module is automatically integrated into the system and with other module.

This principle can be achieved by following several rules :

  • Auto Embed : Adding a module must automatically embed itself into the system.
  • Auto Detach : Removing a module must automatically remove it from the system.
  • Auto Detect : A module must be able to detect the existence of other module.
  • Auto Connect : A module must automatically connect with other module when it is added.
  • Auto Disconnect : A module must automatically disconnect with other module when it is removed.

Reusable Principle

Reusable principle means High Reusability. Every module can be used to multiple different game.

This principle can be achieved by following several rules :

  • Customizable : A module config must be customizable to fulfill game needs.
  • Ready to Use : Every module must be ready to use after adding it.
  • Auto Resolve Setup : Every required setup must be automatically resolved by the module itself.
  • Easy to Use : Every module must be easy to use, in the form of Single Gateway API class.

Technical Implementation

Now let’s go to technical side and see how we can actually implement this design principle into a working system.

Single Gateway

We define a single class as an entry point to our system. This allows the uniformity of the usage of our modules.

AGT class in Core System

Partial Class

Partial is a keyword to allow the same class to be implemented in multiple files. We can use this keyword to fulfill Auto Embed and Auto Detach principle.

Partial Class implementation in Advertisement Module

By creating a partial class implementation for each module, when Advertisement module exist, AGT class now have Advertisement object instance. When the module is removed, AGT class no longer have Advertisement object instance.

Define Symbol

Unity has a feature called Define Symbol which is basically a C Macro. Read more about it here. It basically allow us to have a compile time conditional logic. What it means is that we can enable specific part of code when a symbol is defined, and disable it when the symbol is not defined.

We can use this to fulfill Auto Connect and Auto Disconnect principle.

The code example above will enabled if ADMOB symbol is defined, and disabled if ADMOB is not defined.

Namespace

We can use namespace to fulfill Auto Detect principle. By making sure every module have unique namespace, we can use Reflection to check if a certain namespace exist.

If a module namespace exist, we add symbol for that module, and in turn enables the code inside that symbol.

If a module namespace does not exist, we remove symbol for that module, and in turn disabled the code inside that symbol.

Scriptable Object

We use Unity Scriptable Object to allow game to modify module config easier.

Example of Advertisement Config

Usage

Let say a game need to have In Game Advertisement using Admob. The game only need to add Advertisement module and Admob module.

Then add one line code in their game code. And voila, the game are now able to show advertisement in their game without any effort.

Game Implementation Code

Codename : Gauntlet

When presenting this idea to the CTO and CEO of Agate during a meeting, we held a brainstorm session to give this module integrator a codename. Agate love to use a gemstone to name their technology such as Topaz, Onyx, and Jasper (because Agate itself is the name of gemstone).

In that moment, I propose the name Gauntlet as a codename for this Module integrator. The name comes from Infinity Gauntlet used by Thanos in Marvel Cinematic Universe. And the name capture the essence of it perfectly.

Gauntlet is a container, which by itself have no power. But it allows the user to add module (Infinity Stone) to have a power. Adding more module will create more power, and synergize with other module.

And so we name this product with codename : Gauntlet.

In the next part, I will talk about the lessons I learned . Be sure to stay tuned!

--

--

Wafi Harowa
Kolektif Gamedev

Curious about a lot of things, and never shy away from asking question