View: 3.. 2.. 1.. Ignition

Recently I do have many thoughts on where domain logic ends and where view starts. I know my position, but what is yours?

Here are few examples from 2 quite different (not) games: Shooting-Zombies, Typing-Letters-To-Kill-Approaching-Word-Represented-By-An-Alien-Ship

  • player guesses a word and gets points
  • player shoots an alien ship and gets points
  • player shoots a zombie and gets points
  • player does sth to a zombie and gets points
  • player does sth to a sth and gets sth
  • someone does sth to a sth and sth happens ;-)
  • user via a mouse clicks DOM element and another DOM element’s html changes
  • DOM element moves below X position and player looses points
  • zombie approaches player too close and player looses points
  • zombie position X is below scene lowest position Y and player looses points
  • shot is made
  • player tries to guess a word
  • DOM element X position += 1
  • bullet position X += 1

Questions..

  • What entities should a usecase have: generic or ones that actual game player uses?
  • Is a “zombie” or a “word”, or “alien ship” just a PNG, and usecase should only contain generic name.. let’s say a “target”. Does it matter in the game(s)?
  • Is X and Y position of an object important to a usecase, and should it be there; or only the view layer should know x,y and tell usecase: a.x is below b.x?
  • Should view have any logic at all, and be fully usecase driven?

I personally like to start writing code using terms from the domain. And only – only – when it occurs a name should represent something more generic, and is worth to share some code, then I make it more generic, and introduce some reuse patterns.

Also when X and Y position is important to a usecase logic then I keep it in the usecase.

We can say both: “zombie approaches to close”, “div.zombie.pos_x < div.scene.bottom.pos_x” and both mean the same, but different abstraction

.. and time.. well time is a matter for another blog post.
If timing is important in the game.. (“round takes 60 second”, “player has 5 seconds to make a move”, “game presents solution for 2 seconds”, etc..) then should be considered as part of a domain too.

P.S. I assume in above there are 3 layers:

  1. Usecase having domain logic.
  2. View having browser/screen related things.
  3. Glue that glues both of them and is simple stupid to only pass one Usecase API call to one/many View API calls and vice versa

 

Mixins in CoffeeScript

So, we’ve finally achieved a small utility function that implements mixins in Coffee. In Javascript too :-)

Implementation might not yet be super clean, but it allows us to:

  • mix all methods of mixin class into a base class
  • mix many classes into a base class
  • a mixin has a place for constructing its data if necessary
  • a mixin can read&modify “base” class’ data
  • a base class can read&modify mixin data (awkward, but works)

In short:

and implementation is bit hacky, but works. Uses underscore.js and modified hashmal’s Mixin.
One small requirement of this solution is all roles must extend Mixin class.

A longer example of what’s possible along with part of our Jasmine test:

class Nothing
constructor: (@name=”nothing”) ->

doSomething: =>
“I cannot do anything”

class Presenter extends Mixin
presentYourself: =>
“My name is #{@name}”

doIPlay: =>
“I play with many #{@players}”

class Game extends Mixin
setup: =>
@name = ‘Monopoly’
@players = []
@players.push “David”

sayHello: =>
@presentYourself()

something = new Nothing()
expect(something.name).toBe(‘nothing’)

ObjectHelper.addRole(something, Presenter)
expect(something.presentYourself()).toBe(‘My name is nothing’)
ObjectHelper.addRole(something, Game)
expect(something.sayHello()).toBe(‘My name is Monopoly’)
expect(something.doIPlay()).toBe(‘I play with many David’)

something.name = ‘something’
expect(something.presentYourself()).toBe(‘My name is something’)

something.players.push “John”
expect(something.doIPlay()).toBe(‘I play with many David,John’)

</pre>

And stripped down whole Mixin.coffee

 So, happy mixxxxing to you :-)