I'm trying to reach good understanding of how to build scalable modular application structure. Recently I've been practicing with canvas and rewriting one of the popular snake game realizations. I've decided to try to split its code to modules. The codebase is not big and it seems to be a pretty nice exercise to me.The game is a classic snake game - user controls the snake with arrow keys, when snake collides with food it grows, when the snake collides with screen border or itself it dies and the game's over.The game involves a game object, snake object and food object. I've tried to split the code to store each of these objects in a separate module and import all of these in the main application file, so I have the main main.js file, snake.js file, game.js and food.js.snake.js represents the snake object and its behaviorimport game from './game';import food from './food';let canvas = document.getElementById(game_field);let context = canvas.getContext(2d);let snake = {    size: canvas.width / 40,    x: null,    y: null,    color: '#0F0',    direction: 'left',    sections: [],    init: function () {        snake.sections = [];        snake.direction = 'left';        snake.x = canvas.width / 2 + snake.size / 2;        snake.y = canvas.height / 2 + snake.size / 2;        for (let i = snake.x + (5 * snake.size) ; i >= snake.x; i -= snake.size) {            snake.sections.push(i + ',' + snake.y);        }    },    move: function () {        let directions = {            'up': function () {                snake.y -= snake.size;            },            'down': function () {                snake.y += snake.size;            },            'left': function () {                snake.x -= snake.size;            },            'right': function () {                snake.x += snake.size;            }        };        directions[snake.direction]();        snake.checkCollision();        snake.checkGrowth();        snake.sections.push(snake.x + ',' + snake.y);    },    draw: function () {        for (let i = 0; i < snake.sections.length; i++) {            snake.drawSection(snake.sections[i].split(','));        }    },    drawSection: function (section) {        game.drawBox(parseInt(section[0]), parseInt(section[1]), snake.size, snake.color);    },    checkCollision: function () {        if (snake.isCollision(snake.x, snake.y) === true) {            game.stop();        }    },    isCollision: function (x, y) {        if (x < snake.size / 2 ||            x > canvas.width ||            y < snake.size / 2 ||            y > canvas.height ||            snake.sections.indexOf(x + ',' + y) >= 0) {            return true;        }    },    checkGrowth: function () {        if (snake.x == food.x && snake.y == food.y) {            game.score++;            if (game.score % 5 == 0 && game.fps < 60) {                game.fps++;            }            food.set();        } else {            snake.sections.shift();        }    }};export default snake;food.js represents food for snake and its spawningimport game from './game';import snake from './snake';let food = {    size: null,    x: null,    y: null,    color: '#0FF',    set: function () {        food.size = snake.size;        food.x = (Math.ceil(Math.random() * 10) * snake.size * 4) - snake.size / 2;        food.y = (Math.ceil(Math.random() * 10) * snake.size * 3) - snake.size / 2;    },    draw: function () {        game.drawBox(food.x, food.y, food.size, food.color);    }};export default food;game.js is responsible for the game itself:import snake from './snake';import food from './food';let canvas = document.getElementById(game_field);let context = canvas.getContext(2d);let game = {    score: 0,    fps: 8,    over: false,    message: null,    start: function () {        game.over = false;        game.message = null;        game.score = 0;        game.fps = 8;        snake.init();        food.set();    },    stop: function () {        game.over = true;        game.message = 'GAME OVER';    },    // draws a square box with leg length of size around (x, y) point on canvas    drawBox: function (x, y, size, color) {        context.fillStyle = color;        context.beginPath();        context.moveTo(x - (size / 2), y - (size / 2));        context.lineTo(x + (size / 2), y - (size / 2));        context.lineTo(x + (size / 2), y + (size / 2));        context.lineTo(x - (size / 2), y + (size / 2));        context.closePath();        context.fill();    },    // places score to notification area    drawScore: function () {        message_area.innerHTML = game.score;    },    // places message to notification area    drawMessage: function () {        if (game.message !== null) {            message_area.innerHTML = game.message;        }    },    // clears the whole canvas region    resetCanvas: function () {        context.clearRect(0, 0, canvas.width, canvas.height);    }};export default game;main.js is an entry pointimport game from './game';import snake from './snake';import food from './food';window.onload = function () {    let inverseDirection = {        'up': 'down',        'left': 'right',        'right': 'left',        'down': 'up'    };    let keys = {        up: [38, 75, 87],        down: [40, 74, 83],        left: [37, 65, 72],        right: [39, 68, 76],        start_game: [13, 32],        getKey: function (value) {            for (let key in this) {                if (this[key] instanceof Array && this[key].indexOf(value) >= 0) {                    return key;                }            }            return null;        }    };    window.addEventListener(keydown, function (e) {        let lastKey = keys.getKey(e.keyCode);        if (['up', 'down', 'left', 'right'].indexOf(lastKey) >= 0            && lastKey != inverseDirection[snake.direction]) {            snake.direction = lastKey;        } else if (['start_game'].indexOf(lastKey) >= 0 && game.over) {            game.start();        }    }, false);    var requestAnimationFrame = window.requestAnimationFrame ||          window.webkitRequestAnimationFrame ||          window.mozRequestAnimationFrame;    function loop() {        if (game.over == false) {            game.resetCanvas();            game.drawScore();            snake.move();            food.draw();            snake.draw();            game.drawMessage();        }        setTimeout(function () {            requestAnimationFrame(loop);        }, 1000 / game.fps);    };    requestAnimationFrame(loop);};As you can see, the code is not split in fact. I currently need to import all the other modules to every module. I also need to get canvas context in almost all of them. This looks lame. What decisions, ideas and patterns could help me to make this truly split scalable and modular and to get better understanding of these things? What changes would you suggest?
Snake game using a canvas
javascript;object oriented;canvas;modules;snake game