Saturday, September 15, 2012

Quality vs. Velocity

In Software Engineering terms, quality reflects how well the software conforms to a given design, based on functional requirements and the degree to which the software is built correctly. Whereas velocity simply measures how fast the software is built.

Example
A piece of functionality needs to be added to the system; there are typically 2x options:
  1. Build a clean and solid design that is well tested but may take longer to integrate
  2. Apply a quick and dirty change that works but makes future coding more difficult
Cutting corners in terms of code quality may provide short term gains as features are implemented quicker, but this false economy leads to future costs: time spent refactoring, time spent fixing bugs; time spent re-understanding how the code works etc.

Technical Debt
Technical Debt refers to this false economy as the eventual consequence of poor software architecture and development within a code base.

In the example above, the quick and dirty change creates technical debt; similar to financial debt, technical debt incurs interest payments, which comes in the form of extra development which must be done in future because of the quick and dirty change.

In business, companies may be willing to incur financial debt to take advantage of market opportunities; they may also put pressure on developers to incur technical debt in order to hit important deadlines:

Here trading quality for development speed is really trading time now for time later; however, there is compound interest to putting off the work.

Therefore, there is constant challenge to minimize technical debt: work at high pace in order to meet aggressive deadlines while maintaining high levels of quality in the code.

Process
SCRUM process is being adopted more frequently to provide an iterative incremental framework for managing complex work, minimize rework and improve velocity.

However, it is still important to focus on agile software development techniques in order to improve quality and minimize technical debt.

Why? Because good code quality should help you move faster:
  • Consistent coding style / naming conventions makes code easier to maintain
  • Well-defined interfaces make self-documenting code easier to understand
  • High test coverage can uncover issues quicker and reduce potential bugs
  • High test coverage also allows teams to refactor code with confidence
Let’s revisit the example above:

Build a clean and solid design that is well tested but may take longer to integrate: the additional time spent during development should be supplemented by a reduced QA cycle as fewer bugs are reported.

In my experience, promoting quality over velocity, in the long-term: projects always take a lot less time.

Summary
In conclusion, agile software development techniques such as the following can help instil quality:
  • Unit testing, test-driven development, pair programming
  • Design patterns, domain-driven design, code refactoring
  • Stability through automated tests / continuous integration
Goal: drive quality through each software development project in order to eliminate technical debt!

Friday, September 7, 2012

XNA and Component Based Design

In the previous post, we discussed the topic of XNA and Level Validation.
Now, let's build on this information to discuss Component Based Design.

Note: this post includes complete code sample on CodePlex.
Download code sample here.

Component Based Design
Component Based Design is a common approach to build game objects that are flexible, maintainable and scalable: each component encapsulates a set of related functions, or data, so that additional game objects can be created without any extra code.

In game development, component based object data is typically stored in XML files. The logic used to parse XML and build game objects can be complex and error prone; consequently, system tests can
be used to validate all game objects before fully integrating into the game.

Example
As an example, let’s revise the Spacewar starter kit to demonstrate XNA and Component Based Design.
First, create a system that can parse XML files and build proxy objects for game consumption:
public class ProxyObjectBuilder
{  
 public void BuildProxyObjects(String folder, String txtFile); 
 public void BuildProxyObjects(String folder, IList<String> xmlFiles); 
 public ProxyObject GetProxyObject(String name); 
}
Next, create a component that can be used to build custom game objects at run-time:
public class GameObjectBuilder
{ 
 public T BuildGameObject<T>(String assetName) where T : GameObject;
 public GameObject BuildGameObject(String assetName);
 public GameObject BuildGameObject(ProxyObject proxyObject);   
}
Sample
The following code sample refactors the starter kit to integrate an unlimited number of spaceships using data driven design and validates each spaceship through system tests.
First, define an XML file that stores an unlimited number of spaceships available; each spaceship defines:
  • 3D model, ship class and ship skin
  • Position, rotation, flight boundary
  • Thrust power and bleed velocity
<Assets>
 <Asset name="PencilOneSkinOne" type="Spaceship">
  <ModelComponent id="100" shipClass="PencilOne" modelName="p1_pencil" textureName="pencil_p1_diff_v1" />
  <PhysicsComponent id="200" modelScale="0.02" rotateScale="0.02" position="0,0,0" rotation="90,0,0" boundLeft="-400" boundRight="400" boundTop="-250" boundBottom="250" />
  <ThrustComponent id="300" textureName="thrust_stripSmall" thrustFrame="12.0" thrustConstant="12" thrustMaximum="29" thrustFactor="1.0" thrustPower="100" bleedVelocity="0.3" />
</Asset>
Also, define an XML file that stores an unlimited number of weapons available to each spaceship:
<Assets>
 <Asset name="RocketTwo" type="Weapon">
  <ModelComponent id="100" modelName="p2_rocket" textureName="p2_rocket" />
  <PhysicsComponent id="200" modelScale="0.02" rotation="90,0,0" boundLeft="-400" boundRight="400" boundTop="-250" boundBottom="250" />
  <WeaponComponent id="400" cost="3000 " lifetime="1.5" maximum="1" burst="1" acceleration="300" damage="5" />
 </Asset>
</Assets>
Finally, write system tests to validate all data before fully integrating into the game.
Note: an IoC Container will be used to construct all components used throughout.

PROXY OBJECT BUILDER TESTS
[TestFixture]
public class ProxyObjectBuilderTests
{
 // System under test.
 private ProxyObjectBuilder proxyObjectBuilder;
 
 [SetUp]
 public void SetUp()
 {
  proxyObjectBuilder = IoCContainer.Resolve<ProxyObjectBuilder>();
 }

 [Test]
 public void BuildProxyObjectsSpaceshipsTest()
 {
  String path = GetPath();
  String[] xmlFiles = new[] { "Spaceships.xml" };

  proxyObjectBuilder.BuildProxyObjects(path, xmlFiles);

  Assert.AreEqual(18, proxyObjectBuilder.ProxyObjectManager.ProxyObjects.Count);
 }
}
GAME OBJECT BUILDER TESTS
[TestFixture]
public class GameObjectBuilderTests
{
 // System under test.
 private GameObjectBuilder gameObjectBuilder; 

 [SetUp]
 public void SetUp()
 {
  gameObjectBuilder = IoCContainer.Resolve<GameObjectBuilder>();
 }

 [Test]
 public void BuildGameObjectSpaceshipComponentTest()
 {
  String path = GetPath();
  String[] xmlFiles = new[] { "Spaceships.xml" };
  gameObjectBuilder.ProxyObjectBuilder.BuildProxyObjects(path, xmlFiles);

  String assetName = "WedgeTwoSkinOne";
  Spaceship spaceship = gameObjectBuilder.BuildGameObject<Spaceship>(assetName);

  var component = spaceship.GetComponent<ModelComponent>();
  Assert.AreEqual(ShipClass.WedgeTwo, component.ShipClass);
  Assert.AreEqual("p2_wedge", component.ModelName);
  Assert.AreEqual("wedge_p2_diff_v1", component.TextureName);
 }
}
Download code sample here.

Summary
The revised Spacewar starter kit demonstrates how to integrate an unlimited number of spaceships using data driven design: simply update the XML file to add more spaceships without constant need to recompile and validate all data quickly and efficiently through system tests.

In conclusion, data driven design does seem to have the potential to scale using XNA:
Consequently, there is an opportunity to integrate more complex game code and data using XNA and
data driven design techniques.