Improve the structure of my codebase (JS)

I’m currently building a game (an RPG) in javascript, and the codebase has grown rather big and currently feels like a bit of a spider’s nest. I’ve never built anything of this size before so I’ve never had to deal with this type of problem, and I have a constant feeling that I should do some re-arranging but I feel that my knowledge around OOP is lacking and I need help figuring out if there’s a better way to do things. I’m not even sure I can call it OOP, but it sure isn’t purely functional either.

The codebase is currently based around a single object, with lots of child objects as properties. I keep passing the parent down the chain because I need to call methods from it. A lot of child objects need to be able to access methods and values from siblings as well.

Here’s a mock example of what the structure looks like. I’ve simplified it a lot for the example’s sake:

class Game {
  constructor (content) {
    this.content = content
    this.movement = new Movement(this)
    this.character = new Character(this)
  }

  //... + A lot of helper methods on the game object
}

class Movement {
  constructor (game) {
    this._game = game
  }

  openChest = (chest) => {
    chest.content.forEach(itemId => this._game.character.pickupItem(itemId))
  }

  // ... + Bunch of methods and values here, a lot of them use this._game to call methods
}

class Character {
  constructor (game) {
    this._game = game
    this.inventory = []
  }

  pickupItem = (id) => {
    const props = _game.getEntity('items', id)
    this.inventory.push(new Item(props))
  }

  // ... + Bunch of methods and values here, a lot of them use this._game to call methods
}

class Item {
  constructor (props) {
    Object.assign(this, props)

    this.equipped = false
  }

  // ... + Bunch of methods and values here
}

As you can see, the game object is like an umbrella, and the children reference it and other siblings constantly. But it all feels messy, because it feels dirty to pass down the game object to every new object that is created that need it.

  • Is there a better way to do this?
  • How can I re-organize my code in a better way?
  • Should I be doing it like this, or should I separate concerns more and import already instantiated objects instead?

For example:

  • What if I have a use case where I need to use a method from the top level of the game object, but I need it in an item that is in the array in game.character.inventory. Is it “OK” to pass the game object to every item? Does it have performance implications?

PS. Not sure if it matters, but the game is built in React Native and I’m using MobX quite heavily and game is a MobX store, which is how I got started on this path.

You kind of answered your own question on a better way to structure your code. re: import already instantiated objects.
You could try emulating denormalization techniques used in no-sql databases like Mongodb. And you didn’t indicate if you’ve mapped any sort of IA schema. If you haven’t, now would be ideal.

1 Like

Thanks for your feedback!

While I may have answered some of it myself, I still needed validation that I was on the right track, so thank you for that. I have made an ER diagram (early on though, not up to date now), which did help a lot at that stage.

What denormalization techniques are you referring to? I’m not familiar with the concept.