Aller au contenu

Règles de code

Conventions réellement appliquées et pratiquées dans ce codebase. La philosophie (Clean Code, Object Calisthenics, patterns) vit dans CLAUDE.md ; cette page est le « comment on écrit concrètement le code Feelbat ».

Règles d'or

  1. Utiliser les tokens de couleur du thème — ne jamais coder une couleur en dur. (AGENTS.md)
  2. Utiliser le hook useTranslation pour l'i18n — ne pas importer t directement depuis i18next.
  3. Préférer les alias de modules (components/…, store/…) aux chemins relatifs profonds.
  4. import plutôt que require.
  5. Toute nouvelle fonctionnalité non triviale → un module de feature (src/features/), pas un nouveau sous-arbre de screens/.

Fichiers & nommage

Élément Convention Exemple
Vues React .tsx UnitSelector.tsx
Utilitaires purs / domaine .ts validators.ts
Composants PascalCase ChangeMode, CategoryItem
Valeurs / hooks / fonctions camelCase updatePreference, useChangeModeForm
Constantes d'action Redux SCREAM_CASE ADD_MEASURE, SET_LANGUAGE
Constantes d'opération GraphQL SCREAM_CASE CHANGE_DELTA_V_MODE, GET_UNIT_PREFERENCE

Gardez un nom cohérent partout — si c'est sensorId à un endroit, c'est sensorId partout.

Structure d'un fichier de composant

Un composant par fichier, un StyleSheet par fichier (en bas). Aucune logique dans le JSX — extrayez-la en variables/fonctions au-dessus du return. Aucune fonction anonyme dans le rendu — utilisez useCallback. Enveloppez les lignes de liste dans React.memo.

// 1. imports : externes → internes aliasés → relatifs
import { useMemo } from 'react';
import { StyleSheet, View } from 'react-native';
import { useAppTheme, AppTheme } from 'components/Navigation/types/theme';

// 2. type des props
interface UnitSelectorProps {
  units: Unit[];
  value: UnitId;
  onChange: (id: UnitId) => void;
}

// 3. composant : hooks d'abord, early returns, puis JSX avec attributs testID
export const UnitSelector: React.FC<UnitSelectorProps> = ({ units, value, onChange }) => {
  const theme = useAppTheme();
  const styles = useMemo(() => unitSelectorStyles(theme), [theme]);
  // …
};

// 4. factory de StyleSheet en bas
const unitSelectorStyles = (theme: AppTheme) =>
  StyleSheet.create({
    btnActive: {
      backgroundColor: theme.colors.activeColor,
      borderRadius: theme.roundness * 2, // les rayons sont toujours roundness * n, jamais des nombres bruts
    },
  });

Thème

Les tokens vivent dans src/theme/lightColors.ts et darkColors.ts ; on y accède via useAppTheme() (depuis components/Navigation/types/theme), qui expose colors et roundness. Les factories de styles prennent theme et sont mémoïsées (useMemo(() => styles(theme), [theme])).

 backgroundColor: theme.colors.activeColor
 backgroundColor: '#2468C1'
 borderRadius: theme.roundness * 2
 borderRadius: 8

Les tokens sémantiques incluent activeColor (bleu primaire), black, orange, green, grayLight, white, plus les groupés thresholds.*, acceleration{X,Y,Z}.

i18n

 const { t } = useTranslation('changeMode');   // dans un composant
 getWhatChangeItems(t)                          // les helpers prennent t en paramètre
 import { t } from 'i18next';

6 langues (en, fr, de, it, pt, es), fallbackLng: 'en', config dans src/i18n/i18n.ts. Les clés sont regroupées en namespaces par domaine (fichiers JSON) sous src/i18n/<lang>/ — passez le namespace à useTranslation('<ns>'). Les namespaces de feature vivent sous src/i18n/<lang>/features/<feature>.json.

État

  • Global / persistéduck Redux (src/store/ducks/) : constante d'action + action creator + reducer switch + selectors dans un seul fichier. Pas createSlice.
  • Local à une feature → store zustand dans la feature (hooks/*.store.ts) ou React Context.
  • N'ajoutez pas de duck Redux pour un état qui appartient à une seule feature.

Voir architecture.md.

GraphQL

  • Les opérations sont co-localisées avec leur consommateur : *.mutation.ts, *.fragment.ts, ou api/queries/* dans une feature.
  • Les noms d'opérations doivent être globalement uniques — le preset client de codegen échoue si deux documents partagent un nom (ex. query getSensor défini deux fois). Gardez une seule définition canonique par opération ; ne copiez pas une opération dans un second fichier.
  • Seuls les .ts imbriqués sont scannés (documents: "src/**/*/*.ts"). Une opération dans un .tsx ou un fichier de premier niveau ne sera pas générée.
  • Les types proviennent du dossier généré src/gql/ — ne jamais éditer ce dossier ; lancez yarn generate-interfaces:<env> après avoir modifié des opérations, et rafraîchissez graphql.schema.json.

Principes de conception (issus de CLAUDE.md — appliqués, pas aspirationnels)

  • Les fonctions font une seule chose ; des verbes pour les noms ; ≤ 3 arguments (sinon un objet d'options).
  • Early returns plutôt que conditions imbriquées ; pas de else ; un niveau d'indentation par fonction.
  • Pas de nombres magiques — des constantes nommées.
  • Pas de paramètres booléens qui masquent l'intention — préférez deux fonctions.
  • Les fonctions longues (> 20 lignes) sont un avertissement, > 40 un problème.
  • Appliquez les patterns GoF seulement s'ils simplifient : Strategy pour les switches par type (voir useChangeModeColors indexé sur le mode), Observer/Context pour la communication inter-composants, Factory pour la création complexe.

Application

Prettier + ESLint via lint-staged au commit ; Conventional Commits via commitlint ; architecture via dependency-cruiser ; contrôles de PR via DangerJS. Détails dans ci-cd.md.

Fichiers clés

  • CLAUDE.md, AGENTS.md — les règles sources
  • .eslintrc, .prettierrc.js
  • src/theme/, src/i18n/i18n.ts
  • feature de référence : src/features/unitPreference/