The first concept in SOLID principles is the single responsibility principle. According to Robert Martin's Agile Software Development: Principles, Patterns and Practices, it is defined as:
A class should have only one reason to change
The definition is simple enough, but let's look at an example to really solidify its meaning.
Despite the class looking relatively simple, there is actually a lot going on.
Game controls how the board is rendered, how the player's turn is carried out, if a winner is found and the main game loop. If the way the board is rendered changes,
#renderBoard() will have to change. If the rules of the game changes how a player should conduct their turn,
#playerTurn() and possibly
#detectWinner() will have to change. If we decided to create a more complicated game, where an Ai or some other high level action has to happen,
#start() would have to change.
The easiest way to separate responsibility is to separate the functions into classes depending how on they change in respect to one another.
#renderBoard() can be separated into its own class, because changing how the board is rendered doesn't necessitate changing the game's loop or the game's rules. It only cares about the medium the board is rendered on; for example, a phone app or command line.
#detectWinner() can be separated from
Game, but kept together. The rules of the game dictates how the player conducts their turn and how a player wins. If the rules of the game changes, both
With these changes, the only behavior left in
Game is the main game loop.
When determining how to separate responsibility, look for what Robert Martin calls, "an axis of change". For example, if
#startPlayerTurn() behavior weren't related, we could segregate
#detectWinner() into its own class. However, for our example, this is unnecessary. Be sure not to introduce needless complexity.