coding-standards

% MUGS Coding Standards

Reviewed 2021-03-03 by japhb

The MUGS codebase is large, interconnected, and complex. In order to -Ofun, make our code easy to learn and work with, and keep the community inclusive and safe, there are some common standards, guidelines, and recommendations that all contributors should follow.

Do Not Provoke the Lawyers

In order to keep MUGS free and available to everyone, it is critical that it not become a target for legal action. Game companies are (in)famous for having active and zealous legal teams, which means we have to be extra careful operating in this space. Seriously, I cannot stress this enough:

DO NOT include any protected intellectual property of any game company, including but not limited to: trademarks, trade dress, trade secrets, patented techniques, or copyrighted material including game data, game art, or game audio, in the core MUGS repositories.

There are a zillion games in the public domain, under the creative commons, or that have otherwise been released free-as-in-speech for public use. Be aware that some companies have released their game code as open source, without freeing the game data; be careful. Some of these have community-provided free data sets, which can be used on their own terms, but DO NOT import the original unfree data, in whole or in part, into the core MUGS repositories.

There are also games for which the basic ruleset, mechanics, and play sequence have been open sourced, but the "flavor" (special descriptions, art, trademarks, etc.) remain proprietary. For example, the share-alike Open Game License (OGL) has been used for a number of games, and distinguishes Open Game Content (OGC) from Product Identity (PI). PI belonging to others must not be used in MUGS. Often OGL publishers provide acceptable terms for community users to use in place of their PI trademarks; please use the community terms where appropriate.

If all of the above make you nervous to contribute, don't worry -- there are MANY ways to contribute without copying proprietary games, everything from improving documentation, to adding to the pool of core shared functionality, to better supporting entire game genres. If you want more ideas, don't hesitate to ask; we're a friendly bunch. If you are still most interested in implementing an individual game, please put your energies toward support for more freely available games, or create and share a new game of your own design!

In the rare situation that you have a valid license to redistribute a non-free game -- such as if you had secured a contract to port the game to the MUGS ecosystem -- you must distribute it outside the core MUGS repositories, and of course within the terms of your license. This protects MUGS and its community if the license or contract is ever revoked or invalidated, if you accidentally violate a license term, or if case law shifts unfavorably.

Avoid Hurtful Language

Over the years a number of terms have become commonly used in the technical and gaming worlds while nevertheless remaining insensitive to groups for whom those terms have been used hurtfully over the years. The MUGS community should be an inviting, supportive place for everyone, and a simple step in that direction is to stop using those hurtful terms and phrases, and instead use the (usually more accurate anyway) replacements. Examples include the following groups of terms:

Mental health: (in)sane/(in)sanity, crazy, normal : Disassociate correctness from mental health. Generally these can be replaced with '(in)correct', '(in)valid', '(un)expected' and so forth.

Disability: crippled : Historically this has been used to describe an API or module whose key functionality is broken or unusable for some reason, is in a prototype or proof-of-concept state, or is not being used to full capacity. In any case, say what you mean instead.

LGBTQIA+: queer/gay : These terms can be used to describe queer-positive game content, but do not use them when you mean 'strange', 'unusual', 'eccentric', or 'happy'.

Sexism and gender bias: for girls/boys : There should be nothing intrinsic about a particular game or design that makes it "only for" girls or boys; certainly color scheme and genre do not. Games that assume a particular gender for the player don't belong in MUGS. (Games that even have the concept of gender for characters should allow the player to choose whatever gender they would prefer, and not limit the character's in-world choices pointlessly because of it.)

Slave history: master/slave : It does not matter that these terms have been used in other engineering disciplines beyond computer science, they still do not belong in MUGS. Many replacements are possible here, such as 'primary/secondary', 'primary/replica', 'leader/follower', 'source/sink', and 'server/client'.

Institutional racism: redline/blacklist/whitelist : Depending on intent, these can be replaced with 'priority list', 'capacity limit', 'performance threshold', 'ACL', 'ban list', 'deny list', 'access list', or 'allow list'.

Violence: rape/pillage/assault/murder/kill/death/hostage/prisoner : Use only in the context of a game in which this is legitimate subject matter, and even then be very certain to clearly warn players of the content well before they stumble over it. In MUGS code, these terms should not be used at all other than for certain (rather macabre) system process management APIs.

Sexual language: many, MANY terms : As with violence, use only in the context of a game in which this is legitimate subject matter, and even then be very certain to clearly warn players of the content well before they stumble over it. Sexual terms have even less use in the codebase itself than violent terms, since there is not even the system API exception in this case.

The above is merely a starting point. A great many words are born of a history of oppression, hatred, and othering. The above list will likely be updated and expanded over time, but it is unlikely any existing items will be removed.

Special Cases

A few special cases surrounding hurtful language will likely come to mind, so let's get those out of the way:

A game is commonly known by a hurtful name : Historically many games have been so named, such as Hangman or Crazy Eights. For some there is already a (more or less well-known) replacement name and theme; Hangman can be played as Snowman with identical mechanics but minus the lynching overtones. Others do not have a recognized replacement name yet, but closely related or derivative games in the same subgenre exist. For example, in the subgenre of shedding-type card games, several other games could be implemented instead of Crazy Eights (though note that at least one of them is a non-free variant; see "Do Not Provoke the Lawyers" above).

A game specifically explores triggering topics : Some games (often those with a mature narrative or realistic historical setting) intentionally explore topics that can be triggering for many players. Players (and server admins for that matter) will have very different tolerances for such topics. Games with mature, triggering, or hurtful subject matter should be developed and distributed separately from the MUGS core game set, and should be clearly tagged so that servers that wish to serve them, and players that wish to play them, are fairly informed. To be very clear, the goal here is not censorship but rather ensuring informed consent (to borrow the medical terminology).

Hurtful language is discovered in already-committed files : This can easily come up in several ways: The author and/or reviewer may not have known about the historical or cultural context, the hurt may be closely tied to a culture that the author and reviewer are not part of, prevailing usage may change, scholars may rediscover previously hidden history, etc. In many cases this will be a case of ignorance rather than malice, but that does not obviate the problem. It is action and effect that matter, not intent -- especially since intent becomes ever more difficult to judge with the passage of time -- though of course repeated ill intent makes the problem much worse. The offensive language should be treated as a standards violation, and at the very least replaced in the repo. (More detail on handling this situation is left to the code of conduct.)

Code Style

In general, contributions should match the formatting and style of surrounding code or documentation, but there are some simple rules that the existing code base tries to stick to:

Documentation Formats

  • Write text documentation in Markdown (generally in the intersection of Pandoc Markdown and GitHub-Flavored Markdown so that both will handle it correctly).

  • Create explanatory diagrams in Graphviz DOT, ready for conversion to SVG using dot -Tsvg.

Formatting

  • Default indent to 4 spaces for Raku code, 2 spaces for HTML templates.

  • Avoid code constructions that cause very deep indentation ladders.

  • Never use tabs.

  • Remove trailing whitespace.

  • If you can keep within 80 characters, do so ... but don't contort the code into an unreadable mess to get there. I'd rather an extra couple characters in the line than a word-wrapped abomination.

  • Keep else and elsif uncuddled (a preceding } should be on a separate line).

  • Vertical alignment of matching constructs helps readability, and makes some bugs very obvious; don't be afraid to align on '=' or similar.

Naming

  • Naming matters; take extra time (especially with routine and parameter names) to choose good, clear names.

    • One positive indicator is if API callers will likely name their variables to match parameter names so they can use the :$variable shorthand for named arguments, and this will improve the clarity of the caller's code.

  • Avoid confusion by naming different things differently; in particular, be careful to clearly differentiate an object from the name used to refer to it.

    • For example, a user is a persistent identity object carrying security information, while a username is the text moniker used to log in as a user or look up a user in the database.

Repo Layout

Follow the Repo Layout document. If you want to add a new file or directory that doesn't clearly fit that layout, open a GitHub issue asking for guidance.

Tests

  • Try to keep the test suite monotonically improving; include tests for all new or changed functionality, even if the original code didn't have enough.

  • Make sure test files can be run in parallel safely.

  • Do not depend on the order in which test files run; each should be fully independent of all others.

  • Test both features by themselves (unit tests) and combinations of features (integration or combinatoric tests).

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.