{"id":21565246,"url":"https://github.com/mastercloudapps-projects/chess","last_synced_at":"2026-02-17T16:01:57.025Z","repository":{"id":45748808,"uuid":"514293236","full_name":"MasterCloudApps-Projects/chess","owner":"MasterCloudApps-Projects","description":"📔 Software Design Patterns using JavaScript, on a NodeJS chess engine","archived":false,"fork":false,"pushed_at":"2022-12-16T18:51:02.000Z","size":3846,"stargazers_count":2,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-30T14:29:50.642Z","etag":null,"topics":["chess","chess-game","design-patterns","javascript","javascript-design-patterns","nodejs"],"latest_commit_sha":null,"homepage":"https://mastercloudapps-projects.github.io/chess/coverage/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MasterCloudApps-Projects.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-07-15T14:11:00.000Z","updated_at":"2022-12-15T00:27:27.000Z","dependencies_parsed_at":"2023-01-29T15:45:40.345Z","dependency_job_id":null,"html_url":"https://github.com/MasterCloudApps-Projects/chess","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/MasterCloudApps-Projects/chess","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MasterCloudApps-Projects%2Fchess","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MasterCloudApps-Projects%2Fchess/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MasterCloudApps-Projects%2Fchess/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MasterCloudApps-Projects%2Fchess/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MasterCloudApps-Projects","download_url":"https://codeload.github.com/MasterCloudApps-Projects/chess/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MasterCloudApps-Projects%2Fchess/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29549212,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-17T14:33:00.708Z","status":"ssl_error","status_checked_at":"2026-02-17T14:32:58.657Z","response_time":100,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chess","chess-game","design-patterns","javascript","javascript-design-patterns","nodejs"],"created_at":"2024-11-24T10:18:59.948Z","updated_at":"2026-02-17T16:01:57.008Z","avatar_url":"https://github.com/MasterCloudApps-Projects.png","language":"JavaScript","readme":"# Patterned NodeJS\r\n\u003cp align=\"center\"\u003e\r\n\u003cimg src=\"https://github.com/MasterCloudApps-Projects/chess/actions/workflows/main.yml/badge.svg\"/\u003e\r\n\u003cimg src=\"https://img.shields.io/github/v/tag/MasterCloudApps-Projects/chess\"/\u003e\r\n\u003cimg src=\"https://img.shields.io/github/license/MasterCloudApps-Projects/chess\"/\u003e \u003cbr\u003e\r\n\u003cb\u003eSoftware Design Patterns using JavaScript, on a NodeJS chess engine.\u003c/b\u003e\r\n    \u003cimg src=\".readme/chessGUI.png\" /\u003e\r\n\u003c/p\u003e\r\n\r\n# Launching the chess engine\r\nIt is possible to execute the application for development purposes (with enabled auto-reload), or to just normally run it. As such, there are two scripts for these scenarios: *start* and *dev*.\r\n\r\nNormal execution\r\n```\r\nnpm start\r\n```\r\n\r\nNodemon execution\r\n```\r\nnpm run dev\r\n```\r\n\r\n# Building and launching docker image\r\nMoreover, it is possible to build a docker image of the app using the *Dockerfile*.\r\n\r\nBuilding image (named chess):\r\n```\r\ndocker build -t chess .\r\n```\r\nRun docker container based on the chess image:\r\n```\r\ndocker run -dp 3000:3000 chess\r\n```\r\n\r\n## Using GitHub Packages\r\nThere is also the possibility of using the image uploaded to github container repo. This option will be available only being a collaborator of the project.\r\n\r\nFirst of all, it is necessary to sign in to the [Container registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry).\r\n\r\nThen, it is possible to pull and run the version *1.0.1*:\r\n```\r\ndocker pull ghcr.io/mastercloudapps-projects/chess:1.0.1\r\ndocker run -dp 3000:3000 ghcr.io/mastercloudapps-projects/chess:1.0.1\r\n```\r\n\r\n# Technical Documentation\r\nThis work serves as a study of several well-known software design patterns implemented on the JavaScript language (by using the NodeJS platform), all applied in the context of a simple chess engine.\r\n\r\n## Table of Contents\r\n- [Introduction](#introduction)\r\n- [Style Guide](#style-guide)\r\n- [Project Structure](#project-structure)\r\n- [Design Pattern Implementation](#design-pattern-implementation)\r\n\r\n## Introduction\r\nGiven JavaScript's approach to OOP and the liberty it lends to the programmer, it's no surprise a plethora of different approaches exist when it comes to software design on said language.\r\n\r\nIn this work, comparative samples of different coding styles have been compiled (mainly **Classes**, **Closures**, **Factory functions** and **Constructor functions**) which can be found within the [*/codingStyles/*](https://github.com/MasterCloudApps-Projects/chess/tree/main/codingStyles) directory, together with alternatives to achieve inheritance without making use of JS' classes.\r\n\r\nThese served both as a small design study, and to decide on the coding approach to follow during development of the main software piece in this repository: A *REST API* **chess engine** running on Node.js, and implementing a number of **classic software design patterns**, which in themselves complement the coding style patterns previously mentioned as a general analysis of software design when using JavaScript.\r\n\r\nA frontend web graphic interface has also been developed and included in this project, being accesible upon launch on *localhost:3000*.\r\n\r\n## Style Guide\r\nDue to the inherent nature and versatility of implementation of design patterns, as well as the multitude of alternatives when using JavaScript, a decision was made to define a coding style guide to embrace consistency across the whole project.\r\n\r\nThe main architecture will be structured using **ES6 Modules**. To achieve this, the following style and code conventions are to be followed:\r\n\r\n### Creating a module:\r\nA single file will be created which will contain the new module. Filename must be written using **lowercaseCamelCase along with the .js extension** (ex: *exampleModule.js*). Module names must also be descriptive of their functionality or their relation to the domain model.\r\n\r\nWithin the file itself, methods and functions must be declared as:\r\n```\r\nfunction functionNameOnLowerCaseCamelCase (parameter1, parameter2) {\r\n    // Function code\r\n}\r\n```\r\nFunction names must be descriptive of their behavior and use **verbs** that make said behavior easily understandable.\r\n\r\nAll code indentation within JavaScript modules must be done **using spaces**.\r\n\r\n### Handling exports:\r\n**None of the functions or variables in a module must make use of the export keyword**. All exports for the module will be handled at the end of the file in the following fashion:\r\n```\r\nexport {\r\n    function1,\r\n    function2,\r\n    constant1,\r\n}\r\n```\r\nUsing the default export is to be avoided when possible, priorizing usage of named exports.\r\n\r\n### Importing modules:\r\nImports must be specified at the beggining of a file:\r\n```\r\nimport { function1, function2 } from ‘./ExampleModule.js’;\r\n```\r\nThe usage of **require() is to be avoided**.\r\n\r\n### Using classes, OOP, and other tools:\r\nES6 classes should be avoided in this project and JS modules are a natural alternative. [Stop using javascript classes](https://medium.com/giant-machines/stop-using-javascript-classes-d0b6890ef097) explains why classes are not necessary and how to implement said alternative.\r\n### Encapsulation:\r\nEncapsulation will be dealt with by making use of **closures**.\r\n```\r\nfunction createCounter () {\r\n  let counter;\r\n  function getCounter(){\r\n    return counter;\r\n  }\r\n  function incrementCounter(){\r\n    counter++;\r\n  }\r\n  return {\r\n    getCounter,\r\n    incrementCounter\r\n  };\r\n}\r\n```\r\n### Inheritance\r\nUsing the [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax), it is possible to return an object that augmentates (or extends) another object via composition. As a consequence, inheritance is approached this way in this project:\r\n\r\n```\r\nfunction createObjectA(parameter) {\r\n    let privateAttributeX = parameter;\r\n\r\n    function privateMethod() {\r\n        privateAttributeX++;\r\n    }\r\n\r\n    function publicMethod1() {\r\n        privateMethod();\r\n        console.log(`method1: privateAttributeX: ${privateAttributeX}`);\r\n    }\r\n\r\n    function publicMethod2() {\r\n        privateMethod();\r\n        console.log(`method2: privateAttributeX: ${privateAttributeX}`);\r\n    }\r\n\r\n    function parentExclusiveMethod() {\r\n        privateMethod();\r\n        console.log(`PARENT EXCLUSIVE: privateAttributeX: ${privateAttributeX}`);\r\n    }\r\n\r\n    return {\r\n        publicMethod1,\r\n        publicMethod2,\r\n        parentExclusiveMethod\r\n    }\r\n}\r\n\r\nfunction createObjectB(parameter1, parameter2) {\r\n    const returned = createObjectA(parameter1);\r\n\r\n    let privateAttributeY = parameter2;\r\n\r\n    function publicMethod1() {\r\n        console.log(`Overriden method: privateAttributeY: ${privateAttributeY}`);\r\n    }\r\n\r\n    function publicMethod2() {\r\n        console.log(`Augmentated method: privateAttributeY: ${privateAttributeY}`);\r\n        returned.publicMethod2();\r\n    }\r\n\r\n    function exclusiveMethod() {\r\n        console.log(`Exclusive method: ${privateAttributeY}`);\r\n    }\r\n\r\n    return {\r\n        ...returned,\r\n        ...{\r\n            publicMethod1,\r\n            exclusiveMethod,\r\n            publicMethod2,\r\n        }\r\n    }\r\n}\r\n```\r\n\r\nFull code can be consulted on [/codingStyles/styleProposal/](https://github.com/MasterCloudApps-Projects/chess/tree/main/codingStyles/styleProposal). In this way, an ObjectB instance will have the ObjectA extended funtionality:\r\n\r\n```\r\nlet test = createObjectB(5, 6);\r\ntest.publicMethod1(); // Overriden method: privateAttributeY: 6\r\ntest.publicMethod2();   // Augmentated method: privateAttributeY: 6\r\n                        // method2: privateAttributeX: 6\r\ntest.exclusiveMethod(); // Exclusive method: 6\r\ntest.parentExclusiveMethod(); // PARENT EXCLUSIVE: privateAttributeX: 7\r\n```\r\n\r\nThe drawback of this approach is that it is not possible to access to any parent's variable from the child class, since they all can be considered private. Nevertheless, getters and setters will be used to work around this limitation.\r\n\r\n### Enums\r\nEnums can also coded with closures and take advantage of [Object.freeze()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze), which makes impossible to extend or configure an object.\r\n\r\n```\r\nconst SeasonEnum = Object.freeze({\r\n    Winter: createSeason(\"Winter\"),\r\n    Summer: createSeason(\"Summer\"),\r\n    Autumn: createSeason(\"Autumn\"),\r\n    Spring: createSeason(\"Spring\"),\r\n});\r\n\r\nfunction createSeason(season){\r\n    let name = season;\r\n    function methodA(){\r\n        return \"Season: \" + name;\r\n    }\r\n    return{\r\n        methodA\r\n    }\r\n}\r\n```\r\n\r\n## Project Structure\r\nThe chess architecture follows the Model-View-Controller. On one hand is the backend, containing the domain model and the controllers ([*/Router/*](https://github.com/MasterCloudApps-Projects/chess/tree/main/src/backend/router)), and on the other is the frontend along with the views.\r\n\r\n### Backend\r\nThe backend is invoked from the view, using the exposed REST endpoints.\r\n\r\nThe *Game* module stands out in the model. *Game* directs the flow of the game by interacting with the rest of the modules. This component in addition to the *GameHistory* are the models called from the routers, thus the routers redirect the actions of the server to the model itself.\r\n\r\nA detailed diagram of the relationships between the modules that form the backend is shown.\r\n\r\n\u003cp align=\"center\"\u003e\r\n    \u003cimg src=\".readme/chessBackendDiagram.png\" /\u003e\r\n\u003c/p\u003e\r\n\r\n### Frontend\r\nThe frontend is formed by the views with which the user interacts (identified as Player).\r\n\r\nThe *main* module is in charge of relating the DOM classes, with which the player interacts during the game progress, with the corresponding view.\r\n\r\nThe REST client is used from *GameView* and *PlayerView*. This module invokes the chess backend through http requests.\r\n\r\nThe following diagram shows the relationship between the different view modules.\r\n\r\n\u003cp align=\"center\"\u003e\r\n    \u003cimg src=\".readme/chessFrontendDiagram.png\" /\u003e\r\n\u003c/p\u003e\r\n\r\nA priori, it is confusing that the interaction between the frontend and the backend is not done from one single main view (such as *GameView*), however this was done for a reason. The chess engine was initially developed for a single user, the other player being the *RandomPlayer*. The CPU player is used from the view as well as the user, which allows to easily separate this functionality for a second player in any future versions. As such, when generating the *RandomPlayer* interaction it was decided to do it from its own *PlayerView* view.\r\n\r\n## Design Pattern Implementation\r\nNext up is a list of all the design patterns applied on the chess engine, each one along with a short description of its role within the project and its participants, followed by small UML diagram of the achieved implementation.\r\n\r\n### Creational patterns\r\n- [Singleton](#singleton)\r\n- [Builder](#builder)\r\n### Behavioral patterns\r\n- [Strategy](#strategy-pattern)\r\n- [Template Method](#template-method)\r\n- [Memento](#memento)\r\n### Structural patterns\r\n- [Composite](#composite)\r\n- [Decorator](#decorator)\r\n\r\n#### Singleton\r\nThis pattern has been used at several points to build the following objects:\r\n- turn (frontend)\r\n- boardView (frontend)\r\n- restClient (frontend)\r\n- messageManager\r\n- randomPlayer\r\n\r\nIt has not been implemented in the classic way, as in other languages like Java. Commonly, a public static method will be defined and the constructor will be private. So, the static method will know if the instance has been created or not and return the instance of the type.\r\n\r\n```\r\npublic Class() {\r\n    private Class instance;\r\n\r\n    private Class() {\r\n        // Private constructor\r\n    }\r\n\r\n    public static Class getInstance() {\r\n        if(instance == null) {\r\n            instance = new Class();\r\n        }\r\n        return instance;\r\n    }\r\n}\r\n```\r\n\r\nNevertheless, in our case a constant variable has been assigned to the singleton instance, which is exported afterwards. As a consequence, no one can invoke the constructor from outside since only the object is exported, instead of the factory function.\r\n\r\n```\r\nconst singleInstance = constructor();\r\n\r\nfunction constructor() {\r\n    function publicMethod1(){\r\n        // method 1\r\n    }\r\n\r\n    function publicMethod2(errorMessage){\r\n        // method 2\r\n    }\r\n\r\n    return {\r\n        publicMethod1,\r\n        publicMethod2\r\n    }\r\n}\r\n\r\nexport {\r\n    singleInstance\r\n}\r\n```\r\n\r\n#### Builder\r\nBoard creation and initialization is done via a builder pattern, which accepts custom board layouts as strings and features default ones.\r\n\r\n\u003cp align=\"center\"\u003e\r\n    \u003cimg src=\".readme/boardBuilderPatternDiagram.png\" /\u003e\r\n\u003c/p\u003e\r\n\r\n#### Strategy pattern\r\nUsed to manage how pieces move across the board. As so, several movement strategies exist to implement each kind of piece, which can also be swapped during execution. This is the case of the pawn piece turning into a queen when reaching the end of the board, which was solved smoothly by using this pattern to switch its movement behaviour.\r\n\r\n\u003cp align=\"center\"\u003e\r\n    \u003cimg src=\".readme/movementStrategyPatternDiagram.png\" /\u003e\r\n\u003c/p\u003e\r\n\r\n#### Template Method\r\nWithin Movement Rule strategies, the main parent class pieceMoveRule.js implements the method isPossibleMove(), which retrieves a list of movements by calling getPossibleMovements(). The list of movements varies between pieces, so each child has its own implementation, showcasing the template method pattern.\r\n\r\n\u003cp align=\"center\"\u003e\r\n    \u003cimg src=\".readme/templateMethodPatternDiagram.png\" /\u003e\r\n\u003c/p\u003e\r\n\r\n#### Memento\r\nUndo/Redo functionality is implemented by a memento pattern, which is also used to simulate movements when calculating checkmate possibilities.\r\n\r\n\u003cp align=\"center\"\u003e\r\n    \u003cimg src=\".readme/boardMementoPatternDiagram.png\" /\u003e\r\n\u003c/p\u003e\r\n\r\n#### Composite\r\nThe Queen movement strategy is implemented via a composite movement of both Rook and Bishop movement strategies, while still operating the same as a normal piece movement rule.\r\n\r\n\u003cp align=\"center\"\u003e\r\n    \u003cimg src=\".readme/queenCompositePatternDiagram.png\" /\u003e\r\n\u003c/p\u003e\r\n\r\n#### Decorator\r\nThe decorator pattern was initially implemented to allow functionality for the pawn to transform into a queen upon making it to the end of the board. The decorator object inherits from a normal piece, implements new methods and overrides others to check and swap its piece name and movement strategy for those of a queen when conditions are met.\r\n\r\n\u003cp align=\"center\"\u003e\r\n    \u003cimg src=\".readme/pawnDecoratorPatternDiagram.png\" /\u003e\r\n\u003c/p\u003e\r\n\r\nHowever, this pattern is the only one not present in the final version: It was scrapped in favor of a simpler, non-overdesigned approach in the **getNextMoveRule** method present in all moveRule objects, which allows all of them to return a \"successor\" move rule after each movement. This way, the pawn can keep returning itself until queen transformation conditions are met.\r\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmastercloudapps-projects%2Fchess","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmastercloudapps-projects%2Fchess","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmastercloudapps-projects%2Fchess/lists"}