Customer Science Coding Standard

Customer Science Coding Standard

Customer Science Coding Standard

Article Type: Engineering Standard

Audience: Customer Science software engineers, architects, automation developers, data engineers, support engineers, delivery engineers, and technical reviewers

Applies To: Application code, scripts, automations, integrations, APIs, frontend applications, backend services, data pipelines, CI/CD, testing, security, logging, and documentation


1. Purpose

This Customer Science coding standard defines the expected quality, structure, readability, security, and maintainability practices for software and automation work. It is intended to make systems easier to build, review, operate, troubleshoot, extend, and hand over between teams.

The standard is deliberately technology-neutral. Individual projects may add more specific implementation rules, but project-specific rules should not weaken the principles in this document.

The purpose of this standard is to ensure that solutions are:

  • Readable: Code communicates intent clearly to future maintainers.
  • Maintainable: Changes can be made safely without unnecessary rework.
  • Secure: Secrets, credentials, tokens, and sensitive data are protected.
  • Reliable: Systems handle validation, errors, retries, timeouts, and dependency failures deliberately.
  • Observable: Logs and telemetry provide enough context to investigate production behavior.
  • Consistent: Similar problems are solved in similar ways across projects.
  • Testable: Business logic can be verified without requiring live external systems.

Use this document as a baseline for new development and as a review checklist when changing existing systems. When editing mature code, prefer consistency with the surrounding file unless the existing style creates a clear defect, security issue, or operational risk.


2. Engineering Principles

2.1 Clarity Over Cleverness

Code should be written for people first and machines second. Avoid clever shortcuts, dense expressions, hidden side effects, and overly abstract designs where a direct approach would be easier to understand. A reviewer should be able to identify what the code does, why it exists, and what could fail without mentally unpacking unnecessary complexity.

Prefer explicit control flow for validation, branching, error handling, retries, and resource cleanup. Compact syntax is acceptable only when it improves readability without hiding behavior.

2.2 Separation of Responsibilities

Each layer, module, class, function, workflow, or script should have a clear responsibility. Do not mix request handling, business rules, persistence, external service calls, presentation logic, and infrastructure concerns in the same unit unless the unit is intentionally small and has no meaningful reuse or risk.

The boundary between layers should make testing and replacement easier. Business logic should not depend on transport-specific objects, user interface state, database connection objects, or cloud SDK details unless the component's purpose is specifically to adapt to that dependency.

2.3 Secure by Default

Security must be considered at design time, not added only during release. Secrets must not be committed to source control. Sensitive values must be held in approved secret stores or secure runtime configuration. Access should be least-privilege, and every privileged operation must have an explicit authorization decision.

Inputs from users, files, queues, APIs, databases, and external services must be treated as untrusted until validated. Do not rely on frontend validation, naming conventions, or assumed upstream correctness as the only control.

2.4 Observable by Default

Production systems must emit enough information to understand what happened, when it happened, what component was involved, which operation was attempted, and whether it succeeded. Logging should support investigation without exposing secrets or unnecessary sensitive data.

Long-running jobs, bulk operations, and integrations should log progress at useful intervals. Logs should include stable identifiers, operation names, counts, durations, and error categories where appropriate.

2.5 Fail Safely

When an error occurs, the system should fail in a controlled manner. User-facing and caller-facing messages should be safe, concise, and actionable. Internal logs may contain diagnostic detail, but must not expose secrets, tokens, full connection strings, private keys, or sensitive payloads.

Retries should be used only for failures that are likely to be transient. Permanent validation failures, authorization failures, and malformed requests should fail quickly with clear handling.


3. Project Organisation

3.1 Organisation Principles

Projects should be organised so that a new maintainer can quickly find source code, tests, configuration templates, deployment instructions, operational documentation, and build scripts. The exact folder names may vary by framework, but the purpose of each area should be obvious.

Avoid scattering related behavior across unrelated locations. Keep implementation code, generated output, local tooling, runtime artifacts, and documentation separated. Do not rely on personal IDE settings or local machine state for normal build and test workflows.

3.2 Required Documentation

DocumentPurposeExpectation
OverviewExplain what the system does and who owns itInclude purpose, high-level behavior, support ownership, and operational context.
Setup guideEnable local or deployment setupInclude prerequisites, configuration, build commands, test commands, and common issues.
Configuration referenceDefine runtime settingsDocument setting names, purpose, default behavior, allowed values, and security notes.
Operational notesSupport production useInclude logging locations, troubleshooting steps, scheduling, monitoring, and rollback considerations.
Change historyTrack meaningful changesSummarise user-visible, operational, security, and compatibility-impacting changes.

3.3 Configuration and Sample Files

Configuration files committed to source control must contain safe defaults only. Sample files should be runnable in a development environment without exposing actual credentials. Do not commit secrets, production endpoints, organisation-specific credentials, private keys, or temporary access tokens.

Any new configuration setting should be documented at the same time it is introduced. If the setting affects performance, security, scheduling, data retention, or external connectivity, include operational guidance.


4. Naming Standards

4.1 Naming Principles

Names should describe intent, domain meaning, and responsibility. A good name reduces the need for comments because it tells the reader what the value or behavior represents. Avoid names that describe only implementation mechanics unless the implementation detail is the important concept.

  • Use consistent terminology across code, tests, logs, documentation, and database objects.
  • Avoid placeholder names such as temporary, data, value, item, object, manager, helper, or processor unless the surrounding context makes the meaning precise.
  • Use abbreviations only when they are widely understood by the target engineering audience.
  • Prefer nouns for data structures and verbs for actions.
  • Prefer names that make ownership, lifecycle, and side effects clear.

4.2 Naming by Element

ElementPreferred StyleGuidance
Types and classesPascalCaseName by responsibility or domain concept. Avoid vague suffixes unless they describe a recognised pattern.
Methods and functionsPascalCase or language-standard function styleUse a verb phrase that describes the action and result. Async methods should follow the language or framework convention.
Variables and parametersLanguage-standard local variable styleName by meaning, not by type. Avoid single-letter names except for narrow, conventional loops or mathematical code.
ConstantsLanguage-standard constant styleName by the business or technical rule represented, not by the literal value.
Configuration keysHierarchical and descriptiveGroup related settings and use names that make operational purpose clear.
Log propertiesStable and descriptiveUse consistent names for identifiers, operation names, durations, counts, and statuses.

4.3 Avoid Ambiguous Names

Avoid names that force readers to inspect implementation details to understand meaning. Generic names may be acceptable in very small scopes, but they should not cross method, module, component, service, or persistence boundaries.


5. Architecture Standard

5.1 Layering

Systems should separate transport concerns, validation, authorization, business rules, persistence, external service integration, and presentation. The exact layers may vary by technology, but dependencies should flow in one direction and business logic should remain testable without requiring live infrastructure.

Controllers, routes, handlers, pages, workflow triggers, and automation entry points should be thin. They should validate input shape, establish context, call the appropriate service or workflow, and translate the result into the correct response format.

5.2 Business Logic

Business logic should live in components that can be exercised directly by tests. It should not depend on HTTP request objects, UI state, database sessions, cloud SDK clients, file paths, or environment variables unless the component is specifically an adapter for that boundary.

When business rules become complex, make them explicit. Prefer named methods, domain models, validators, and policy objects over deeply nested conditionals or duplicated checks.

5.3 Data Access and External Services

Persistence and external integrations should be isolated behind clear interfaces or modules. Query construction, API request formatting, retry handling, pagination, rate limiting, and response mapping should not leak into unrelated business logic.

Use structured APIs, parameterised queries, SDK models, serializers, and schema validation where available. Avoid ad hoc string manipulation for SQL, JSON, XML, URLs, paths, or protocol messages when safer library support exists.

5.4 Architecture Rules

  • Do not bypass authorization checks for convenience.
  • Do not return raw dependency errors to callers.
  • Do not couple business logic directly to infrastructure unless the component is an infrastructure adapter.
  • Keep identifiers in their native type internally where practical, and convert only at external boundaries.
  • Use dependency injection or explicit constructor parameters for replaceable dependencies.
  • Keep long-running orchestration separate from individual units of work.
  • Document intentional deviations from the standard architecture.

6. C# Coding Standard

6.1 Formatting and Layout

C# code should follow the conventions used by the .NET ecosystem and by the file being edited. The default position is to use project formatter and editor configuration rules, four-space indentation, Allman braces, explicit visibility, and readable member ordering.

Formatting should make control flow obvious. Avoid compressed one-line logic, hidden side effects, and spacing that makes conditions or method chains hard to scan.

  • Use four spaces for indentation.
  • Do not use tabs.
  • Use Allman braces for blocks.
  • Use one statement per line.
  • Specify visibility modifiers explicitly.
  • Keep using statements at the top of the file and sort them consistently.
  • Remove unused using statements and trailing whitespace.
  • Keep methods focused and reasonably small.

6.2 Naming

Use standard C# naming conventions. Types and public members use PascalCase. Local variables and parameters use camelCase. Private fields use a consistent private-field convention within the project. Constants should follow the existing project convention.

Names should communicate purpose and domain meaning. Avoid unnecessary abbreviations and avoid names that only repeat the type.

6.3 Type Usage and Language Features

Use language features when they improve clarity. Do not use newer syntax only because it is shorter. A reviewer should be able to understand the important type, ownership, lifetime, and side-effect information without following several layers of inference.

  • Use C# language keywords for built-in types.
  • Use nameof(...) instead of string literals for member and parameter names.
  • Use var only when the type is obvious from the right-hand side.
  • Use target-typed construction only when the declared type remains obvious.
  • Avoid this. unless needed to resolve ambiguity.
  • Prefer explicit models over loosely typed dictionaries in business logic.

6.4 Class Shape

Classes should be organised so dependencies, public surface area, and implementation details are easy to find. Put fields near the top, followed by constructors, public members, and private helpers. Keep database access, API calls, transformation logic, and orchestration in separate components where possible.

Use immutable or readonly dependencies where practical. Avoid public mutable fields. Keep constructors simple and avoid doing expensive work before the object is used.

6.5 Async Rules

Most integration and application work is I/O-bound. Async code should remain async through the call path. Blocking on async work can exhaust thread pools, deadlock callers, and cause slow behavior under load.

  • Use async and await consistently.
  • Do not block async code with synchronous waiting.
  • Pass cancellation tokens through long-running operations and external calls where supported.
  • Name asynchronous methods according to project convention.
  • Use bounded concurrency for large fan-out work.
  • Log progress for long-running jobs at useful intervals.

6.6 Error Handling

Catch exceptions only when the method can add context, translate the error into a safe contract, retry a transient dependency failure, or perform cleanup. Do not catch and silently continue unless skipping the work item is deliberate and logged.

When logging exceptions, include stable operational identifiers, operation names, table or resource names, counts, durations, and date ranges where appropriate. Do not log secrets, tokens, full connection strings, private keys, raw customer payloads, or unnecessary sensitive content.

6.7 Configuration

Configuration belongs at the application boundary and should be passed into services as typed options or explicit dependencies. This keeps business logic testable and prevents hidden production differences between environments.

Do not hardcode values that can change between environments, organisations, regions, deployments, credentials, endpoints, feature flags, retry settings, timeouts, schedule intervals, or retention policies.


7. Python Coding Standard

7.1 Formatting and Tooling

Python code should be formatted and linted by project-standard tools. Formatting should be automated so code reviews focus on design and behavior rather than whitespace.

  • Use four spaces for indentation.
  • Use snake_case for variables and functions.
  • Use PascalCase for classes.
  • Use uppercase naming for constants where that is the project convention.
  • Use type hints for production code.
  • Use a formatter, linter, type checker, and test runner consistently.

7.2 Imports

Imports should be grouped and sorted consistently. Keep standard library imports, third-party imports, and local imports clearly separated. Avoid wildcard imports. Avoid importing heavy dependencies at module import time if doing so slows startup or complicates testing.

7.3 Controllers and Entry Points

Entry points should validate request shape, establish execution context, call a service, and return a safe response. They should not contain business rules, persistence logic, or complex orchestration.

Caller-facing errors should use a stable response contract. Raw exceptions, stack traces, internal paths, dependency messages, and sensitive details must not be returned to external callers.

7.4 Services

Services should contain business logic and orchestration decisions. They should receive dependencies through constructors or explicit parameters so tests can replace external systems with deterministic fakes.

Services should validate important assumptions and raise meaningful domain or application errors. They should avoid reading environment variables directly unless their purpose is configuration loading.

7.5 Persistence and External Access

Repository, client, gateway, or adapter components should isolate database and external service details. They should own query construction, pagination, request formatting, response parsing, and dependency-specific retry behavior.

Use parameterised queries, SDK models, serializers, and schema validation. Avoid dynamic strings for queries, paths, and protocol payloads unless all inputs are safely encoded.

7.6 Error Response Contract

ConditionResponse CategoryGuidance
Invalid inputClient errorReturn a clear validation message that does not expose internals.
Unauthorized or forbidden actionAuthorization errorReturn a safe access message and log the decision context internally.
Dependency failureService errorReturn a generic dependency failure message and log diagnostic details internally.
Unexpected exceptionServer errorReturn a generic fallback message and log the exception server-side.

8. JavaScript and Frontend Standard

8.1 Architecture

Frontend code should separate rendering, state management, routing, API access, validation, and reusable UI behavior. Pages and components should not directly duplicate authentication, authorization, telemetry, or API response parsing logic.

8.2 Frontend Rules

  • Keep network calls in dedicated API or client modules.
  • Do not rely on frontend checks as the only authorization control.
  • Handle loading, empty, error, and success states deliberately.
  • Clean up timers, event listeners, subscriptions, and in-flight work when views are destroyed or hidden.
  • Use shared helpers for authentication, API calls, telemetry, and error display where the project provides them.
  • Do not expose tokens, secrets, or privileged configuration in browser-accessible code.

8.3 API Wrappers

API wrapper modules should own URL construction, headers, request methods, response parsing, error translation, and telemetry around calls. Components should call wrapper methods rather than assembling authenticated requests directly.

8.4 Route and Action Guards

Privileged routes and actions should be guarded in the frontend for user experience and in the backend for security. Frontend guards should fail closed, show clear feedback, and avoid rendering privileged controls when the user lacks access.

8.5 Frontend Security

  • Escape or safely render untrusted content.
  • Avoid injecting unsanitised HTML.
  • Keep dependency versions maintained.
  • Protect state that affects permissions or privileged operations.
  • Do not store long-lived secrets in local browser storage.

9. Workflow and Automation Standard

9.1 Design Principles

Workflows and automations should be modular, readable, recoverable, and observable. They should validate inputs early, handle expected business conditions explicitly, and separate business exceptions from system failures.

Avoid hardcoded paths, credentials, endpoints, environment values, email addresses, queue names, and approval rules. Use secure configuration and document operational dependencies.

9.2 Structure

Workflows should have a clear beginning, validation phase, processing phase, error path, notification or response path, and termination behavior. Long workflows should be decomposed into reusable subflows, activities, or modules.

9.3 Naming

Workflow, automation, variable, and action names should describe purpose and scope. Avoid names that depend on a specific customer, temporary project, or individual developer unless the system is intentionally customer-specific.

9.4 Error Handling

  • Business exceptions should identify expected conditions that prevent processing.
  • System exceptions should identify unexpected dependency, runtime, or infrastructure failures.
  • Retries should be bounded and visible in logs or run history.
  • Failed transactions should preserve enough context for safe reprocessing.
  • Screenshots, payloads, and attachments must not capture sensitive data unless explicitly approved.

10. Security Standard

10.1 Never Commit or Expose

  • Passwords
  • API keys
  • Client secrets
  • Refresh tokens
  • Private keys
  • Production connection strings
  • Raw identity tokens
  • Certificates or certificate passwords
  • Sensitive customer or user data that is not required for source control

10.2 Preferred Security Patterns

  • Use approved secret stores for credentials and sensitive settings.
  • Use least privilege access for users, applications, service accounts, and automation identities.
  • Use secure transport for all external communication.
  • Validate all external input.
  • Use parameterised database operations.
  • Record security-relevant decisions in logs without exposing sensitive values.
  • Review dependency and container vulnerabilities where applicable.

11. Logging and Observability

11.1 Required Context

Logs should help operators understand behavior without needing to reproduce the issue immediately. Include enough stable context to correlate events across components while avoiding sensitive content.

  • Operation name
  • Correlation or request identifier where available
  • Relevant resource or entity identifiers
  • Environment or deployment context where appropriate
  • Start and end timestamps for long operations
  • Counts, durations, and page or batch numbers for bulk work
  • Outcome, status, or error category

11.2 Do Not Log

  • Passwords
  • Secrets
  • Tokens
  • Full connection strings
  • Private keys
  • Unapproved sensitive payloads
  • Data that is not required for support or audit purposes

11.3 Metrics and Telemetry

Systems should expose meaningful operational signals such as success counts, failure counts, retry counts, processing duration, queue depth, dependency latency, and throughput. Metrics should be stable enough for alerting and dashboards.


12. Testing Standard

12.1 Testing Principles

Testing should focus on behavior, boundaries, and risk. Tests should give maintainers confidence that important workflows still behave correctly after change. Avoid tests that only repeat implementation details.

  • Unit tests should be deterministic and should not call live external systems.
  • Integration tests should clearly identify external dependencies and setup requirements.
  • Regression tests should be added when fixing defects that could recur.
  • High-risk changes should include broader verification than low-risk formatting or documentation changes.
  • Test data must not contain actual secrets or unnecessary sensitive data.

12.2 Test Coverage Expectations

Coverage should scale with risk. Core business rules, authorization decisions, data transformations, retries, error handling, and integration boundaries should receive stronger coverage than trivial pass-through code.

12.3 Manual Verification

Manual testing is acceptable for areas that cannot be automated immediately, but the steps and results should be recorded in the pull request or deployment notes. Repeated manual checks should be considered candidates for automation.


13. CI/CD Standard

13.1 Pipeline Expectations

  • Install dependencies from declared manifests.
  • Build the application or package.
  • Run formatting and lint checks where available.
  • Run automated tests.
  • Publish test and coverage results where supported.
  • Package artifacts reproducibly.
  • Keep deployment configuration separate from source code secrets.
  • Version releases using the approved release process.

13.2 Pipeline Design

Pipelines should be understandable, repeatable, and auditable. Avoid hidden manual steps, undocumented environment assumptions, and machine-specific dependencies. Deployment jobs should make rollback and operational impact clear.


14. Pull Request Standard

Every pull request should include enough information for a reviewer to understand the change without reconstructing intent from the diff alone.

  • Summary of the change.
  • Reason for the change.
  • Risk and impact notes.
  • Testing performed.
  • Configuration or deployment notes.
  • Rollback notes where relevant.
  • Linked work item or approval reference where applicable.
  • Screenshots, diagrams, exports, or logs where useful.

14.1 Reviewer Checklist

  • Is the code readable and consistent with the surrounding project?
  • Is the architecture appropriate for the problem?
  • Are responsibilities separated clearly?
  • Are security and authorization handled correctly?
  • Are errors handled safely?
  • Is logging sufficient and safe?
  • Is configuration externalised and documented?
  • Are tests or verification steps appropriate for the risk?
  • Are deployment and rollback notes clear?
  • Is documentation updated where behavior or operation changed?

15. Definition of Done

A change is complete only when it is implemented, reviewed, verified, and ready to operate.

  • Code, workflow, automation, or configuration change is complete.
  • Naming and formatting standards are followed.
  • Secrets and sensitive data are not exposed.
  • Configuration is externalised where appropriate.
  • Error handling is included.
  • Logging and telemetry are sufficient.
  • Security and authorization have been considered.
  • Testing or verification is completed.
  • Pull request is reviewed.
  • Deployment steps are documented.
  • Rollback approach is understood where relevant.
  • Operational documentation is updated where behavior, configuration, or support procedures changed.

Document Version: 3.0

Last Updated: June 2026

Owner: Customer Science


    • Related Articles

    • CSI - Customer Hosted Deployment Requirements

      Overview Document Purpose: This document outlines the infrastructure and configuration requirements for deploying the CSI (Genesys Cloud Data Adapter) platform in a customer-hosted environment. The platform synchronises Genesys Cloud operational and ...
    • public.partsumm_customer

      Columns Name Type Default Nullable Children Parents Comment keyid varchar(100) false conversationid varchar(50) true conversationstartdate timestamp without time zone false conversationstartdateltc timestamp without time zone true conversationenddate ...
    • Service Commitments

      Customer Science Group works to respond to and restore incidents within the timeframes set out in the table below. These times are not guaranteed and there are situations (see examples in Appendix 1) where longer timeframes are reasonably required. ...
    • Genesys Cloud OAuth for Genesys Adapter

      Introduction These instructions are to be used to complete the necessary configuration of the Genesys Cloud instance required to allow the Customer Science Group Genesys Adapter to extract the required analytical data from your dedicated Genesys ...
    • CSI Platform Release Notes

      CSI Platform Release Notes This article provides a summary of significant platform updates, enhancements, bug fixes, security improvements, and infrastructure changes made to the Customer Science Intelligence (CSI) Platform. Release notes are updated ...