Skip to content

Coding Guidelines

This document outlines the coding standards and best practices for contributing to omegaUp. These guidelines are enforced by automated linters and integration tests.

General Principles

Type Safety

All code must declare data types in function parameters and return types:

  • TypeScript for frontend (frontend/www/)
  • Psalm for PHP (frontend/server/)
  • mypy for Python (stuff/)

Type Annotations

Prefer type annotations for arrays/maps inside functions to make code easier to understand.

Language

  • All code and comments are written in English

Testing

  • Changes in functionality must be accompanied by tests
  • All tests must pass 100% before committing
  • No exceptions

Code Quality

  • Avoid null and undefined wherever possible
  • Use Guard Clause Pattern
  • Remove unused code (don't comment it out - use git history)
  • Minimize distance between variable declaration and first use

Naming Conventions

  • camelCase for functions, variables, and classes
  • snake_case exceptions:
  • MySQL column names
  • Python variables and parameters
  • API parameters

Abbreviations

Avoid abbreviations in code and comments. They're not obvious to everyone.

Code Formatting

We delegate formatting to automated tools:

Validate style with:

./stuff/lint.sh validate

Style Guidelines

  • Use 2/4 spaces (depends on file type), not tabs
  • Unix-style line endings (\n), not Windows (\r\n)
  • Opening brackets on same line as statement
  • Space between keywords and parentheses: if, else, while, switch, catch, function
  • No space before function call parentheses
  • No spaces inside parentheses
  • Space after comma, not before
  • Binary operators: space before and after
  • Maximum one blank line in a row
  • No empty comments
  • Only // line comments, no /* */ block comments

PHP Guidelines

Testing

// Tests must pass 100% before committing
// All functionality changes need tests

Database Queries

Avoid O(n) queries. Create manual queries for single round trips:

// ❌ Bad: Multiple queries
foreach ($users as $user) {
    $runs = RunsDAO::searchByUserId($user->userId);
}

// ✅ Good: Single query
$runs = RunsDAO::searchByUserIds(array_map(fn($u) => $u->userId, $users));

Function Parameters

API functions are the only ones that can receive \OmegaUp\Request. All other functions must:

  1. Validate parameters
  2. Extract to typed variables
  3. Call functions with these variables

Function Documentation

All functions must be documented:

/**
 * set
 *
 * If cache is on, save value in key with given timeout
 *
 * @param string $value
 * @param int $timeout
 * @return boolean
 */
public function set($value, $timeout) { ... }

Exceptions

Use exceptions to report errors. Functions returning true/false are allowed when they represent expected values.

API Responses

All APIs must return associative arrays.

Vue.js Guidelines

Component Behavior

Avoid components that change behavior significantly based on flags. Use slots instead:

<!-- ✅ Good: Using slots for customization -->
<template>
  <div>
    <slot name="header"></slot>
    <slot name="content"></slot>
  </div>
</template>

Internationalization

Never hardcode text. Always use translation strings:

// ❌ Bad: Hardcoded text
<div>Contest ranking: {% raw %}{{ user.rank }}{% endraw %}</div>

// ✅ Good: Translation string
<div>{% raw %}{{ T.contestRanking }}{% endraw %}</div>

String Formatting

Avoid concatenating translation strings. Use ui.formatString() with parameters instead.

Colors

Avoid hexadecimal or rgb() colors. Use CSS variables for dark mode support.

Lifecycle Hooks

Avoid lifecycle hooks unless directly interacting with DOM. Direct DOM interaction should also be avoided.

Computed Properties

Prefer computed properties and watchers over programmatic variable manipulation.

Storybook

Add Storybook stories for new components. Update stories when modifying existing components.

TypeScript Guidelines

Function Parameters

When a function has more than 2-3 parameters, especially of the same type, use an object:

// ❌ Bad: Too many parameters
function updateProblem(
  problem: Problem,
  previousVersion: string,
  currentVersion: string,
  points?: int
): void { ... }

// ✅ Good: Object parameter
function updateProblem({
  problem,
  previousVersion,
  currentVersion,
  points,
}: {
  problem: Problem;
  previousVersion: string;
  currentVersion: string;
  points?: int;
}): void { ... }

Type Assertions

Avoid type assertions except for: - DOM interactions (document.querySelector) - Empty literal type declarations: null as null | string - Testing: declaring params in Vue constructor

jQuery Deprecation

jQuery has been deprecated and cannot be used.

Python Guidelines

Function Parameters

For functions with many parameters, especially optional ones, use keyword-only parameters:

# ❌ Bad: Positional parameters
def updateProblem(
    problem: Problem,
    previous_version: str,
    current_version: str,
    points: Optional[int] = None
) -> None: ...

# ✅ Good: Keyword-only parameters
def updateProblem(
    *,
    problem: Problem,
    previous_version: str,
    current_version: str,
    points: Optional[int] = None,
) -> None: ...

Naming

  • snake_case for functions and variables
  • CamelCase for classes

Imports

Avoid from module import function. Import modules and use dot notation:

# ❌ Bad
from module import function
function()

# ✅ Good
import module
module.function()

Exception: typing module can use from typing import ...

Comments

Comments should explain why, not what:

// ❌ Bad: Explains what
// Increment counter
$counter++;

// ✅ Good: Explains why
// Increment counter to track retry attempts for rate limiting
$counter++;

Remember: These guidelines are enforced by automated tools. Run ./stuff/lint.sh before committing!