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

 

BackFactor..

Just a reminder on refactoring: it means finding parts of the code where it can be improved in quality.
Also, as style of code must be consistent across whole code base, I should also apply the refactoring in all similar places that need to be refactored the same way.

Refactor the system back.. backfactor.

I see 2 reasons “why not to”:

  • one can’t
  • one has no time

I will try to argue both.

1. Sure you can. Maybe you have no way to know if code after modification works the same way as before. Well, you probably have no tests, or your code was already way too complicated. Either way – you need to find a solution, and find it quick

2. No time. This is tricky. As I believe leaving such code creates legacy code. Creates inconsistency among code base. And in the end more time is wasted than spent on backfactoring.

Any new (or you) developer reading system code in future, will find the same problems solved in different ways, or expressed in different ways. They will need to spend more time than you would backfactoring earlier..

Hope it makes you thinking when you refactor next time :-)

 

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 :-)