Awesome Reviewers

Language Runtimes & Compilers

Interpreters, compilers, async runtimes, parsers and low-level systems code.

406 instructions from 17 repositories. Last updated 2025-10-23.


Use semantically accurate names

Variable, method, and type names should accurately reflect their actual purpose, content, and behavior. Avoid generic or misleading names that don’t match the underlying functionality.

Key principles:

Example:

// Bad - misleading name
let cached_hit_test_result = match event.event { ... }

// Good - accurate name  
let hit_test_result = match event.event { ... }

// Bad - singular for collection
visible_input_method: Vec<EmbedderControlId>,

// Good - plural for collection
visible_input_methods: Vec<EmbedderControlId>,

Names should immediately communicate what the code actually does, not what it might do or what it was originally intended to do.


avoid unnecessary work

Identify and eliminate computational work that serves no purpose, particularly for inactive, hidden, or irrelevant elements. This includes early returns for non-visible components, lazy initialization of expensive resources, and preventing work during inappropriate timing.

Key strategies:

Example from display list processing:

// Before: Always process display lists
fn handle_display_list(&mut self, webview_id: WebViewId, display_list: DisplayList) {
    self.process_display_list(webview_id, display_list);
}

// After: Skip processing for hidden webviews
fn handle_display_list(&mut self, webview_id: WebViewId, display_list: DisplayList) {
    if !self.webview_renderers.is_shown(webview_id) {
        return debug!("Ignoring display list for hidden webview {:?}", webview_id);
    }
    self.process_display_list(webview_id, display_list);
}

Example from variable initialization:

// Before: Create display immediately
let display = path.display();
if some_condition {
    println!("Error with {}", display);
}

// After: Create display only when needed
if some_condition {
    let display = path.display();
    println!("Error with {}", display);
}

This optimization prevents wasted CPU cycles, reduces memory pressure, and improves overall application responsiveness by ensuring computational resources are only used when they contribute to meaningful work.


avoid unsafe unwrapping

Replace .unwrap() calls and sentinel values with safe null handling patterns to prevent runtime panics and improve code robustness.

Key Issues:

  1. Unsafe unwrapping: Using .unwrap() on operations that could fail, especially downcasts and IPC operations
  2. Sentinel values: Using invalid constants like Invalid or None = -1 instead of proper Option types
  3. Missing graceful degradation: Not handling None cases appropriately

Safe Patterns:

Example:

// ❌ Unsafe - could panic
let video_elem = self.downcast::<HTMLVideoElement>().unwrap();
video_elem.resize(width, height);

// ✅ Safe pattern
if let Some(video_elem) = self.downcast::<HTMLVideoElement>() {
    video_elem.resize(width, height);
}

// ❌ Sentinel value antipattern  
pub enum LargestContentfulPaintType {
    None = -1,
    // ...
}

// ✅ Proper Option usage
pub fn get_lcp_candidate() -> Option<LCPCandidate> {
    // ...
}

This prevents runtime crashes and makes null states explicit in the type system, improving both safety and code clarity.


optimize algorithmic complexity

Prioritize algorithmic efficiency by choosing operations and data structures that minimize computational complexity. Look for opportunities to replace O(n) operations with O(1) alternatives, select appropriate data structures for the use case, and avoid unnecessary algorithmic overhead.

Key optimization strategies:

Example of complexity optimization:

// Instead of O(n) traversal:
fn get_root_slow(&self) -> Self {
    let mut current = self.clone();
    while let Some(parent) = current.parent() {
        current = parent;
    }
    current
}

// Provide O(1) direct access:
fn get_root_node(&self) -> Self {
    // Often possible to get root in O(1) if in shadow/document tree
    self.document().root_element()
}

This approach reduces computational overhead and improves performance, especially in frequently called code paths involving DOM traversal, data structure operations, and rendering algorithms.


avoid unwrap and panic

Replace .unwrap() and panic!() calls with proper error handling to prevent crashes and improve robustness. When encountering potential failures, choose one of three approaches:

  1. Propagate the error to the caller using Result types
  2. Log and continue with graceful degradation
  3. Use .expect() with clear, actionable messages if crashing is truly intended

Examples:

Instead of:

let result = receiver.recv().unwrap().unwrap();

Use propagation:

fn get_result(&self) -> Result<SomeType, Error> {
    let result = receiver.recv().map_err(|e| Error::IpcFailure)?
        .map_err(|e| Error::OperationFailed)?;
    Ok(result)
}

Instead of:

devtools_chan.send(msg).unwrap();

Use logging:

if let Err(e) = devtools_chan.send(msg) {
    log::error!("DevTools send failed: {e}");
}

Instead of:

let components = string.split('x').collect::<Vec<_>>();
Ok(Some(Size2D::new(components[0], components[1])))

Use graceful handling:

let (width, height) = string.split_once('x')
    .ok_or(ParseResolutionError::InvalidFormat)?;

This approach prevents unexpected crashes, especially in content processes, and provides better debugging information when failures occur.


reduce complexity for readability

Prioritize code readability by reducing complexity through better organization and clearer patterns. Use early returns to avoid deep nesting, extract methods to break down large functions, and choose appropriate data structures over generic ones.

Key practices:

Example of improving nested code:

// Instead of deep nesting:
if ancestor.is::<Document>() {
    true
} else if ancestor.is::<Element>() {
    let ancestor = ancestor.downcast::<Element>().unwrap();
    // ... complex logic
} else {
    false
}

// Use early returns:
if ancestor.is::<Document>() {
    return true;
}
let Some(ancestor) = ancestor.downcast::<Element>() else {
    return false;
};
// ... simplified logic

This approach makes code easier to follow, test, and maintain by reducing cognitive load and making the control flow more explicit.


Algorithm edge case validation

Ensure algorithmic implementations properly handle edge cases and boundary conditions before considering them complete. Many algorithm failures stem from insufficient consideration of special inputs, parameter combinations, or state transitions that occur at the boundaries of normal operation.

Key areas to validate:

Example from encoding algorithms:

// Problem: encoding_rs::Decoder fails with single invalid byte when last=false
// The algorithm includes malformed bytes in bytes_read count, causing issues
// when transitioning to flushing state (last=true) with empty remaining slice
let result = decoder.decode_to_string_without_replacement(input, last=false);
// Edge case: single invalid byte [0xFF] doesn't return DecoderResult::Malformed

Before marking algorithmic work as complete, systematically test edge cases that could cause unexpected behavior in production. Document known limitations and file follow-up issues for incomplete algorithm implementations.


comprehensive API documentation

All public items, struct fields, and methods must have comprehensive documentation. When implementing web specifications, include the actual specification text in comments rather than just links, as specifications can change over time.

Required Documentation:

Specification References: Include actual specification text in comments, not just links:

// ❌ Avoid link-only references
// Step 3 - 5.
// <https://w3c.github.io/webdriver/#dfn-deserialize-a-web-window>

// ✅ Include specification text
// Step 3: Let browsing context be the browsing context whose window handle is
// reference, or null if no such browsing context exists.
// Step 4: If browsing context is null or not a top-level browsing context,
// return error with error code no such window.
// Step 5: Return success with data browsing context's associated window.

Comprehensive Field Documentation:

// ✅ Document all fields with purpose and context
pub struct TextDecoderStream {
    reflector_: Reflector,
    /// Document-specific data required to fetch a web font.
    #[ignore_malloc_size_of = "Rc is hard"]
    decoder: Rc<TextDecoderCommon>,
    /// The associated transform, as per
    /// <https://streams.spec.whatwg.org/#generictransformstream>
    transform: Dom<TransformStream>,
}

This ensures code is self-documenting, maintainable, and provides clear context for future developers and specification compliance.


conditional CI execution

Use appropriate conditional statements in CI workflows to ensure steps execute under the right circumstances and handle different environments gracefully.

Key practices:

Example from the discussions:

- name: Publish artifact marking this job as done
  uses: actions/upload-artifact@v4
  if: ${{ always() }}  # Ensures cleanup runs even if job fails
  with:
    # artifact configuration

- name: Setup Python
  if: ${{ runner.environment != 'self-hosted' }}  # Only on GitHub-hosted
  uses: ./.github/actions/setup-python

- name: Change Mirror Priorities  
  if: ${{ runner.environment != 'self-hosted' }}  # Skip on self-hosted
  uses: ./.github/actions/apt-mirrors

This approach prevents workflow failures due to missing infrastructure, ensures proper cleanup, and optimizes resource usage by skipping unnecessary steps on different runner types.


configuration parameter handling

When working with configuration parameters and values, follow these best practices to ensure maintainable and correct configuration handling:

  1. Use collections for multiple related values: When checking against multiple related configuration values, use the in operator with a list or set rather than chaining multiple OR conditions. This makes the code more readable and easier to maintain when adding new values.

  2. Use tool-specific parameter names: Different tools may use different parameter names for similar concepts. Always verify and use the correct parameter names for the specific tool being invoked to avoid configuration errors.

Example from the codebase:

# Good: Use 'in' operator for multiple related values
return self.is_custom() and (self.profile in ["production", "production-stripped"])

# Good: Use tool-specific parameter names
# For nextest, use --cargo-profile instead of --profile
args += ["--cargo-profile", build_type.profile]

This approach reduces maintenance overhead when adding new configuration values and prevents configuration mismatches when working with different tools that have similar but distinct parameter naming conventions.


implement security validation

Ensure all security-related functionality includes complete validation checks and proper testing. This applies to both cryptographic operations and security policy configurations.

For cryptographic operations, implement all required validation steps as specified in standards. For example, in EdDSA signature verification:

// Step 2: Validate key data
if (key.representsInvalidPoint() || key.isSmallOrderElement()) {
    return false;
}

// Step 3: Validate signature point R  
if (signatureR.representsInvalidPoint() || signatureR.isSmallOrderElement()) {
    return false;
}

For security policies like Content Security Policy, ensure all required directives are properly configured and tested:

<!-- Ensure all necessary permissions are included -->
Content-Security-Policy: sandbox allow-forms allow-scripts

Always verify that security validation logic is complete by checking against specifications and testing edge cases. Missing validation steps can create security vulnerabilities, whether in cryptographic implementations or policy configurations.


Network request configuration

When creating network requests, ensure all security-sensitive parameters are properly configured including origin, referrer, CORS mode, and destination. Incomplete request configuration can lead to test failures, security vulnerabilities, and incorrect cross-origin behavior.

Always specify:

Example of proper request configuration:

let request = RequestBuilder::new(
    state.webview_id,
    url.clone().into(),
    Referrer::ReferrerUrl(document_context.document_url.clone()),
)
.destination(Destination::Font)
.mode(RequestMode::CorsMode)
.origin(ImmutableOrigin::new(url.origin()));

Be particularly careful with CORS mode settings as they can cause failures when loading cross-origin resources. Test thoroughly when modifying request builder parameters, as incomplete configuration often manifests as test failures that may not be immediately obvious.


validate external system inputs

When integrating with external systems that receive repository or organizational information, always implement server-side validation to ensure the provided data belongs to authorized organizations or repositories. This prevents potential abuse where attackers could exploit organizational resources by spoofing repository information.

The receiving system should validate that repository names, organization identifiers, or similar contextual data are constrained to expected values before processing requests or allocating resources.

Example from CI runner integration:

# Action passes repository info to external monitor
echo "qualified_repo=${{ github.repository }}" | tee -a "$artifact_path"

The external monitor should validate that github.repository belongs to the authorized organization (e.g., “servo/*”) before proceeding with runner allocation or resource provisioning. Without this validation, malicious actors could potentially abuse organizational infrastructure by providing crafted repository information.


enhance testing interfaces

Design testing tool interfaces to be both flexible and discoverable. Support multiple keyword variations for test-related functionality and provide pass-through parameter options to enable advanced debugging scenarios.

When implementing testing commands or parsers, consider:

Example implementation:

# Support multiple keywords for discoverability
elif any(word in s for word in ["cov", "coverage", "test-coverage"]):
    return JobConfig("Coverage", Workflow.COVERAGE)

# Allow pass-through parameters for flexibility
@CommandArgument("params", nargs="...", help="Command-line arguments to be passed through to test runner")

This approach improves developer experience by making testing tools more accessible and providing the flexibility needed for complex debugging scenarios.


avoid borrow hazards

Prevent borrow conflicts by collecting or cloning data before operations that may trigger garbage collection, call into JavaScript, or create additional borrows. This is especially critical when holding mutable borrows (borrow_mut()) that could conflict with operations that need to access the same data.

The pattern involves identifying operations that might cause borrow conflicts and restructuring code to release borrows before those operations execute.

Example of the problem:

// BAD: borrow_mut is still active when calling jsval_to_webdriver (which can trigger GC)
fn WebdriverCallback(&self, cx: JSContext, val: HandleValue, realm: InRealm, can_gc: CanGc) {
    let rv = jsval_to_webdriver(cx, &self.globalscope, val, realm, can_gc);
    let opt_chan = self.webdriver_script_chan.borrow_mut().take();
    if let Some(chan) = opt_chan {
        let _ = chan.send(rv);
    }
}

Corrected approach:

// GOOD: Take the channel first, then call the potentially conflicting operation
fn WebdriverCallback(&self, cx: JSContext, value: HandleValue, realm: InRealm, can_gc: CanGc) {
    if let Some(chan) = self.webdriver_script_chan.borrow_mut().take() {
        let result = jsval_to_webdriver(cx, &self.globalscope, value, realm, can_gc);
        let _ = chan.send(result);
    }
}

Another pattern - collecting before iteration:

// GOOD: Collect vector before starting loop to avoid borrow hazards
pub(crate) fn fire_queued_messages(&self, can_gc: CanGc) {
    let messages: Vec<_> = self.queued_worker_tasks.borrow_mut().drain(..).collect();
    for msg in messages {
        // Process message with can_gc argument safely
    }
}

This pattern is essential in garbage-collected environments where operations can trigger collection cycles that conflict with active borrows.


API design patterns

Design APIs with appropriate parameter types, place conversion functions as trait implementations in the correct modules, and reuse existing patterns instead of creating new abstractions.

Key principles:

  1. Use appropriate parameter types: Prefer &[T] over &Vec<T> for function parameters to accept more input types and improve API flexibility.

  2. Place conversions as trait implementations: When creating conversion functions, implement them as traits (like From<&str>) in the module where the target type is defined, rather than standalone functions elsewhere.

  3. Reuse existing patterns: Before creating new IPC messages, traits, or abstractions, check if existing patterns can be extended or reused. Avoid adding dependencies just for cleaner conversions when simple functions suffice.

  4. Prefer functional patterns: Use map(), unwrap_or_else(), and similar combinators instead of imperative if-let chains when it improves readability.

Example of good API design:

// Good: slice parameter, functional style
fn process_link_headers(link_headers: &[LinkHeader]) -> Vec<ProcessedLink> {
    link_headers.iter()
        .map(|header| process_header(header))
        .collect()
}

// Good: trait implementation in type's module
impl From<&str> for CorsSettings {
    fn from(token: &str) -> Self {
        match_ignore_ascii_case! { token,
            "anonymous" => CorsSettings::Anonymous,
            "use-credentials" => CorsSettings::UseCredentials,
            _ => CorsSettings::Anonymous,
        }
    }
}

This approach creates more flexible, discoverable, and maintainable APIs while avoiding unnecessary complexity.


Handle unsafe code properly

Methods that access raw memory buffers, perform pointer operations, or interact with foreign function interfaces must be explicitly marked as unsafe to prevent memory safety vulnerabilities. Conversely, remove unnecessary unsafe blocks when calling safe functions to maintain code clarity and prevent masking actual unsafe operations.

Key principles:

Example of proper unsafe marking:

// BAD: Missing unsafe marker for dangerous operation
pub(super) fn bytes<'a>(&'a self) -> EncodedBytes<'a> {
    // Accesses raw JS string buffer that could be invalidated
}

// GOOD: Properly marked as unsafe
pub(super) unsafe fn bytes<'a>(&'a self) -> EncodedBytes<'a> {
    // Caller must ensure JS string won't be mutated/freed
}

// BAD: Unnecessary unsafe block
unsafe { root_from_handlevalue::<TrustedScriptURL>(value, cx).is_ok() }

// GOOD: Remove unsafe when function is safe
root_from_handlevalue::<TrustedScriptURL>(value, cx).is_ok()

This prevents memory corruption vulnerabilities and maintains Rust’s memory safety guarantees while clearly communicating risk to API consumers.


validate subprocess errors comprehensively

When executing external commands via subprocess, don’t rely solely on return codes for error detection. Some tools may return 0 even when they fail. Instead, check multiple error indicators including return codes, stderr output, and stdout content to ensure robust error handling.

Use higher-level subprocess methods like subprocess.run() or subprocess.check_output() when possible, as they provide better built-in error handling. When using subprocess.Popen(), always examine both the return code and error output:

# Instead of only checking return code:
if self.hdc_process.returncode != 0:
    logging.warning(f"HDC reverse port forwarding failed: {stderr.decode()}")

# Check both return code AND error message content:
stdout, stderr = self.hdc_process.communicate()
if self.hdc_process.returncode != 0 or "error" in stderr.decode().lower():
    logging.warning(f"HDC reverse port forwarding failed: {stderr.decode()}")
    return False

This approach is especially important when working with external tools that may not follow standard Unix conventions for exit codes.


avoid unnecessary Option operations

When working with Option types, prefer efficient and safe access patterns over unnecessary operations. Use .as_ref().unwrap() instead of .clone().unwrap() to avoid unnecessary cloning when you only need a reference to the contained value. When possible, prefer safe alternatives like to_string_lossy() over unwrap(), or use early returns with the ? operator to handle None cases gracefully.

Example of preferred patterns:

// Prefer this - no unnecessary clone
format!("version = \"{}\"", self.version.as_ref().unwrap())

// Instead of this - unnecessary clone
format!("version = \"{}\"", self.version.clone().unwrap())

// Prefer safe alternatives
test_file_name.to_string_lossy()

// Instead of unwrap when failure is possible
test_file_name.into_string().unwrap()

// Use early returns for None handling
Some(crate_path.parent())?;

// Instead of unwrap that can panic
crate_path.parent().unwrap()

This approach reduces unnecessary allocations, prevents potential panics, and makes code more robust when dealing with optional values.


Algorithm and data optimization

Choose efficient algorithms and appropriate data structures based on access patterns and computational requirements. Use built-in comparison methods like cmp() to avoid redundant checks, select data structures that match usage patterns (HashSet for lookups, Vec for iteration), and ensure algorithmic correctness by handling edge cases properly.

Key practices:

Example of efficient comparison:

// Instead of multiple if-else conditions
match new_version.cmp(&current_version) {
    Ordering::Less => eprintln!("Warning: new version is lower than current!"),
    Ordering::Greater => println!("Bumping version {current_version} to {new_version}"),
    Ordering::Equal => println!("Keeping version {current_version}"),
}

Simplify complex expressions

Break down complex code structures into simpler, more readable forms. This includes avoiding deep nesting, extracting complex logic into helper functions, simplifying boolean expressions, and reducing code duplication.

Key practices:

Example of improvement:

// Before: Complex nested conditions
if filename == "package.json" {
    // logic
}
if filename == "package.json" || filename == "pom.xml" {
    // more logic
}

// After: Clear match statement
match (generate_opts.author_url, filename) {
    (Some(url), "package.json" | "pom.xml") => replacement.replace(AUTHOR_URL_PLACEHOLDER, url),
    (None, "package.json") => replacement.replace(AUTHOR_URL_PLACEHOLDER_JS, ""),
    (None, "pom.xml") => replacement.replace(AUTHOR_URL_PLACEHOLDER_JAVA, ""),
    _ => {},
}

This approach improves code maintainability, reduces cognitive load, and makes the codebase more approachable for new contributors.


Pin dependency versions

Always specify exact versions for dependencies and avoid pointing to moving targets like “master” branches or “latest” tags in configuration files. This ensures reproducible builds and prevents unexpected breakages when upstream dependencies change.

When configuring dependencies across multiple components of a project, use consistent version numbers. For example, if your main project uses Kotlin 2.1.20, ensure all submodules and build configurations use the same version:

// In build.gradle - use consistent versions
plugins {
    id("com.android.library") version "8.7.1" apply false
    id("com.android.application") version "8.7.1" apply false
    id 'org.jetbrains.kotlin.android' version '2.1.20' apply false // Match react-native version
}
# In podspec files - pin to specific tags, not branches
spec.source = {
  :git => 'https://github.com/facebook/yoga.git',
  :tag => spec.version.to_s,  // Use tagged version
  # :branch => "master",      // Avoid this - causes unpredictable fetches
}

This practice prevents version drift, ensures all team members build with identical dependencies, and makes it easier to track which specific versions were used in each release.


Ensure documentation clarity

Documentation should be clear, accurate, and provide meaningful information to users. Avoid misleading descriptions, template text that doesn’t add value, and unclear explanations that leave users confused about functionality.

Key practices:

Example of unclear vs clear documentation:

// Unclear - misleading about actual behavior
/// Don't force rebuild the parser when `--grammar_path` is specified

// Clear - accurately describes the relationship
/// `--grammar_path` implies force rebuild

Documentation should help users understand not just what something does, but how and when to use it effectively.


API type definition consistency

When modifying API type definitions, ensure all related definition files are updated consistently and dependencies are properly managed. API types often exist in multiple formats (TypeScript definitions, JSON schemas, etc.) and must be kept in sync to maintain a coherent client interface.

Key practices:

Example from the discussions:

// When adding a new rule type
type ReservedRule = { type: 'RESERVED'; content: Rule; context_name: string };
// Also update grammar.schema.json with corresponding schema definition

// Use proper type modifiers for optional parameters
export default function MainModuleFactory(options?: Partial<EmscriptenModule>): Promise<MainModule>;
// Rather than requiring all EmscriptenModule properties

This ensures that API consumers have accurate, complete type information and that the API surface remains consistent across all definition formats.


Avoid unnecessary auto

Use explicit types instead of auto unless the type is obvious from the right-hand side of the assignment or impossible to spell. The LLVM coding standards recommend avoiding auto in most cases to improve code readability and maintainability.

When to use auto:

When to avoid auto:

Example:

// Bad - type not obvious
auto name = getValue();
auto count = getElementCount();
auto context = builder.getContext();

// Good - explicit types improve readability
StringRef name = getValue();
unsigned count = getElementCount();
MLIRContext *context = builder.getContext();

// Good - auto appropriate here
auto *CI = dyn_cast<CallInst>(instruction);
for (auto it = container.begin(); it != container.end(); ++it) { ... }

This practice ensures code remains readable without IDE assistance and makes type information immediately available to reviewers and maintainers.


Use descriptive names

Choose names that clearly describe the purpose, behavior, and content of functions, variables, and constants. Names should be self-documenting and unambiguous to other developers.

Function Names: Use verbs that accurately describe what the function does. For example, prefer getOrGenImplicitDefaultDeclareMapper over genImplicitDefaultDeclareMapper when the function both retrieves existing items and generates new ones. Similarly, use canPassByValue instead of isLiteralType when checking if a variable can be passed by value rather than just checking for literal types.

Variable Names: Choose names that clearly indicate the variable’s purpose and avoid ambiguity. For example, use hasMapHdr and hasStringHdr instead of hasMap and hasString when referring to header files, since the latter are common names that usually don’t refer to headers.

Constants: Define named constants instead of using magic strings or literals directly in code. Replace inline strings like "aligned_alloc" or "localabstract" with properly declared constants:

// Instead of magic strings
if (callOp.getCallee() != "aligned_alloc")

// Use named constants  
static constexpr char kAlignedAllocFunc[] = "aligned_alloc";
if (callOp.getCallee() != kAlignedAllocFunc)

Misleading Names: Avoid names that suggest different functionality than what is actually implemented. For instance, don’t use asan_dispatch_apply_f_block for a function that handles regular function callbacks rather than blocks - prefer asan_dispatch_apply_f_callback instead.

This approach makes code more maintainable, reduces the likelihood of errors, and improves code readability for all team members.


avoid unnecessary allocations

Minimize performance overhead by avoiding unnecessary memory allocations, expensive data structures, and redundant object creation. Choose appropriate data types and parameter passing methods based on actual requirements rather than convenience.

Key practices:

Example of inefficient vs efficient approaches:

// Inefficient: Creates many temporary strings and copies
std::string result = "{ ";
for (size_t i = 0; i < items.size(); ++i) {
  result += "\"" + items[i].first + "\", " + items[i].second;
  if (i < items.size() - 1) result += ", ";
}

// Efficient: Uses stringstream to avoid copies
std::stringstream ss;
ss << "{ ";
for (size_t i = 0; i < items.size(); ++i) {
  ss << "\"" << items[i].first << "\", " << items[i].second;
  if (i < items.size() - 1) ss << ", ";
}
std::string result = ss.str();

Profile performance-critical code paths to identify where expensive operations like TrackingVH creation or unnecessary allocations are causing bottlenecks, then replace them with more efficient alternatives.


cost-based algorithmic decisions

When implementing algorithmic transformations and optimizations, use cost analysis and profitability heuristics to guide decision-making rather than applying transformations blindly. This includes choosing appropriate data structures based on access patterns, placing optimizations at the correct architectural level, and validating that algorithmic changes actually improve performance.

Key principles:

  1. Data structure selection: Choose between alternatives based on access patterns. For example, use a map when you need efficient lookups and only want the most recent entry, but use a vector when linear iteration is acceptable and the number of elements is small.

  2. Optimization placement: Place algorithmic optimizations where they can be most effective. Constant folding should be in generic optimization passes rather than specialized locations, and profitability checks should override general heuristics when needed.

  3. Performance validation: Always measure the impact of algorithmic changes. Cost models can be wrong, leading to performance regressions that need to be detected and addressed.

Example from loop transformations:

// Use profitability analysis to guide loop interchange
bool shouldInterchange = profitabilityCheck(outerLoop, innerLoop);
if (shouldInterchange && canVectorizeInnerLoop(outerLoop)) {
  // Move vectorizable loop to innermost position
  interchangeLoops(outerLoop, innerLoop);
}

The goal is to make algorithmic decisions based on measurable criteria rather than assumptions, ensuring that optimizations actually improve performance for the target use cases.


minimize header dependencies

Organize code to minimize header dependencies and improve compilation times. Use forward declarations instead of includes when possible, avoid unnecessary dependencies, and follow proper header organization patterns.

Key practices:

Example:

// Good: Use forward declaration in header
// MyClass.h
class WarnUnusedResultAttr; // Forward declaration
class MyClass {
  WarnUnusedResultAttr* attr;
};

// MyClass.cpp - actual include in implementation
#include "clang/AST/Attr.h"

// Bad: Heavy include in header
// MyClass.h  
#include "clang/AST/Attr.h" // Unnecessary dependency

This approach reduces compilation times, minimizes rebuild cascades when headers change, and creates cleaner module boundaries.


Use descriptive semantic names

Choose specific, meaningful names that clearly convey purpose and follow established codebase patterns. Avoid generic terms that could apply to many different concepts.

Key principles:

Example:

// Avoid generic, overloaded terms
TemplateNameKind kind() const;  // ❌ Generic "kind"

// Use specific, descriptive names  
TemplateNameKind templateKind() const;  // ✅ Clear purpose

// Follow positive naming for booleans
def TuneDisableMISchedLoadClustering;  // ❌ Negative construction
def TuneEnableMISchedLoadClustering;   // ✅ Positive, clear methods

Configuration completeness validation

Ensure configuration options are complete and properly validated before use. When implementing configuration parsing or option handling, verify that all expected cases are covered and add appropriate validation checks for user inputs.

Key practices:

  1. Complete option coverage: When implementing configuration switches or parsers, ensure all documented or expected options are handled. Missing cases can lead to silent failures or unexpected behavior.

  2. Input validation: Add sanity checks for user-provided configuration values, especially when they override compiler-determined settings.

  3. Required attribute verification: When configuration depends on specific attributes or flags being present, validate their existence early in the process.

Example from MinGW CRT DLL configuration:

// Ensure all expected CRT DLL versions are handled
Opts.MinGWCRTDll = llvm::StringSwitch<enum LangOptions::WindowsCRTDLLVersion>(A->getValue())
    .StartsWithLower("crtdll", LangOptions::WindowsCRTDLLVersion::CRTDLL)
    .StartsWithLower("msvcrt10", LangOptions::WindowsCRTDLLVersion::MSVCRT10)
    // ... other cases ...
    .StartsWithLower("msvcrt-os", LangOptions::WindowsCRTDLLVersion::MSVCRT_OS) // Don't miss expected cases
    .Default(LangOptions::WindowsCRTDLLVersion::Unknown); // Handle unexpected input

Example of validation for user input:

// Validate user-specified vector sizes
if (!inputVectorSizes.empty()) {
    assert(inputVectorSizes.size() == expectedSize && 
           "Incorrect number of input vector sizes");
    // Add runtime validation for production code
}

This prevents configuration-related bugs and ensures robust handling of both expected and edge-case inputs.


optimize computational complexity

When implementing algorithms, be mindful of computational complexity and optimize for efficiency by avoiding expensive operations and reusing existing computations where possible.

Key principles:

  1. Avoid expensive object operations: When sorting or manipulating heavy objects, work with pointers or lightweight references instead of the objects themselves. For example, when sorting a collection of large structures, sort an array of pointers rather than moving the actual objects.

  2. Reuse existing computations: Before performing expensive calculations, check if equivalent results already exist that can be reused with minimal adjustment. Look for opportunities to reuse intermediate results rather than recomputing from scratch.

  3. Ensure deterministic ordering: Use consistent ordering (e.g., sorting) for data structures to avoid non-deterministic behavior that can lead to inconsistent optimization results or algorithmic outcomes.

  4. Consider phase ordering: Be aware that the sequence of applying algorithmic phases can significantly impact the final result quality. Design algorithms with careful consideration of when each optimization or transformation should be applied.

Example from the codebase:

// Instead of sorting heavy objects directly:
// std::sort(heavyObjects.begin(), heavyObjects.end());

// Sort pointers to avoid expensive object movement:
SmallVector<LSRUse *, 16> sortedPointers;
for (auto &use : heavyObjects)
  sortedPointers.push_back(&use);
std::sort(sortedPointers.begin(), sortedPointers.end(), comparator);

// Reuse existing computations when possible:
if (existingResult && canReuseWithOffset(existingResult, offset)) {
  return adjustWithOffset(existingResult, offset);
}

This approach reduces computational overhead while maintaining algorithmic correctness and improving overall performance.


minimize test complexity

Tests should be minimal and focused on the specific functionality being verified. Remove unnecessary passes, tools, or operations that aren’t directly related to what’s being tested to reduce noise and improve clarity.

Key principles:

Example of improvement:

// Before: Includes unnecessary canonicalizer pass
// RUN: mlir-opt %s -convert-complex-to-rocdl -canonicalize | FileCheck %s

// After: Focuses only on the conversion being tested  
// RUN: mlir-opt %s -convert-complex-to-rocdl | FileCheck %s

This approach makes tests easier to understand, maintain, and debug while ensuring they remain effective at catching regressions.


Choose appropriate string types

Select the most efficient string type based on ownership and lifetime requirements to optimize memory usage and prevent safety issues. Use StringRef for parameters and when you don’t need to own the string data, std::string when you need ownership and persistence, and avoid storing Twine objects as member variables.

Key guidelines:

Example from the discussions:

// Bad: Unnecessary string copy for constant data
class InvalidRSMetadataFormat {
  std::string ElementName;  // If always called with constants
};

// Good: Use StringRef when appropriate
class InvalidRSMetadataFormat {
  StringRef ElementName;  // For constant strings
};

// Bad: Dangerous storage of Twine
class GenericRSMetadataError {
  Twine Message;  // Can cause memory violations
};

// Good: Own the string data when needed
class GenericRSMetadataError {
  std::string Message;  // Safe ownership
};

This optimization reduces memory allocations, prevents unnecessary copying, and avoids potential memory safety issues while maintaining code correctness.


explicit invalid value handling

When designing enums or working with type casting, explicitly define and handle invalid states rather than relying on undefined behavior. Use designated invalid values that stand out clearly, and employ equality assertions for type compatibility checks.

For enums, avoid gaps in value sequences and use distinctive invalid values:

// Instead of skipping values:
enum WasmAddressType { Memory = 0x00, Object = 0x01, Invalid = 0x03 };

// Use clear, distinctive invalid values:
enum WasmAddressType { Memory = 0x00, Object = 0x01, Invalid = 0xff };

For type casting scenarios, use equality assertions when types must be compatible:

// Instead of just checking size compatibility:
static_assert(sizeof(Barrier) <= sizeof(pthread_barrier_t));

// Assert exact equality when casting between types:
static_assert(sizeof(Barrier) == sizeof(pthread_barrier_t));

This approach prevents undefined behavior, makes invalid states explicit and detectable, and ensures type safety through clear assertions rather than implicit assumptions.


match API complexity appropriately

Design APIs with complexity that matches their actual use cases and adopt established patterns that improve clarity. Avoid over-engineering interfaces when simpler alternatives suffice, and prefer modern, well-established patterns over legacy approaches.

When designing function parameters, choose the simplest form that meets current requirements rather than anticipating future complexity that may never materialize. For example, use boolean flags instead of function callbacks when the callback would only return true/false.

For error handling, prefer modern patterns like Expected over output parameters combined with status codes, as they provide clearer semantics and better composability.

Example of simplification:

// Instead of complex callback for simple cases:
bool LoopRotation(Loop *L, ..., 
    function_ref<bool(Loop *, ScalarEvolution *)> ProfitabilityCheck);

// Use simple boolean when that's all that's needed:
bool LoopRotation(Loop *L, ..., bool IgnoreProfitability);

Example of modern error handling:

// Instead of output parameter + status:
static Status ResolveDeviceID(const std::string &device_id, 
                             std::string &resolved_device_id);

// Use Expected<T> pattern:
static llvm::Expected<std::string> ResolveDeviceID(llvm::StringRef device_id);

preserve known test issues

When tests exhibit known false positives or false negatives, preserve these test cases with clear documentation rather than removing them. This practice prevents accidental “fixes” that mask underlying problems and helps track when issues are genuinely resolved.

As noted in code review discussions, removing tests for known issues can lead to situations where “someone could make a refactor/speedup patch of the check and accidentally fix FP. Without this test, developer wouldn’t know he fixed a FP with an NFC patch.”

When modifying test expectations:

  1. Document why the change occurred (e.g., “existing false negative: #65888 disabled this check”)
  2. Distinguish between intentional fixes and environmental changes
  3. Keep failing tests commented with FIXME or similar markers explaining the known issue

Example approach:

// FIXME: This triggers a false positive: the "passed to same function" heuristic
// can't map the parameter index 1 to A and B because myprint() has no
// parameters.
//     warning: 2 adjacent parameters of 'passedToSameKNRFunction' of similar type ('int')
#if 0
int myprint();
// Test case preserved to track when this FP is actually fixed
#endif

This ensures test suite integrity and prevents regression in issue tracking.


specify network protocol endianness

Always explicitly specify byte order (endianness) in network protocol documentation and implementations. Even when a specification mandates a particular endianness, make it clear in your documentation to avoid confusion and implementation errors.

When documenting network protocols, include explicit statements about byte ordering, especially when the protocol endianness might differ from the host system’s native endianness. This prevents ambiguity and helps developers implement the protocol correctly.

Example from qWasmCallStack documentation:

Get the Wasm callback for the given thread id. This returns a hex-encoding list
of 64-bit addresses for the frame PCs. To match the Wasm specification, the
addresses are encoded in little endian byte order, even if the endian of the 
Wasm runtime's host is not little endian.

This approach eliminates confusion about data representation and ensures consistent implementation across different platforms and architectures.


structure contextual log messages

Log messages should include sufficient contextual information and structured formatting to enable effective debugging and filtering. This means including relevant metadata, level information, and clear prefixes that help developers understand the source and severity of logged events.

For error logging, include references to relevant objects or metadata that can provide additional context:

void log(raw_ostream &OS) const override {
  OS << Message;
  if (MD)
    MD->printTree(OS);
}

For debug logging, include level information in prefixes to enable easy filtering:

if (DebugType) {
  if (Level == 0)
    Level = 1;
  OsPrefix << "[" << DebugType << ":" << Level << "] ";
}

This approach allows developers to filter verbose output by level and provides rich context when debugging issues. Well-structured log messages reduce debugging time and improve the overall development experience.


Write accessible documentation

Documentation should be written with clarity and completeness to serve readers who may not have deep domain expertise. Use precise, unambiguous language that avoids technical jargon when simpler alternatives exist, and provide necessary context about origins, rationale, and background information.

When writing technical documentation:

Example of improvement: Instead of: “This returns a hex-encoding list of 64-bit addresses for the frame PCs” Write: “This returns a hex-encoded list of PC values, one for each frame of the call stack”

Additionally, include contextual notes such as: “Note: This packet is an LLDB extension to the GDB remote protocol, originated from [specific runtime/system].”


parameter type clarity

Design API parameters using specific, intention-revealing types rather than generic or ambiguous ones. This improves code readability, prevents misuse, and makes the API’s behavior self-documenting.

Key principles:

Examples of improvements:

Replace default values with Option when appropriate:

// Before: Unclear if version is required
struct Version {
    #[arg(default_value = "0.0.0")]
    pub version: SemverVersion,
}

// After: Clear that version is optional
struct Version {
    pub version: Option<SemverVersion>,
}

Replace multiple bools with enum:

// Before: Multiple related flags
pub bump: bool,
pub bump_minor: bool, 
pub bump_major: bool,

// After: Single enum parameter
pub bump: Option<BumpType>, // where BumpType = { Patch, Minor, Major }

Use specific parameters over generic ones:

// Before: Generic but unclear
fn needs_recompile(lib_path: &Path, parser_c_path: &Path, scanner_path: &Option<PathBuf>, external_files_paths: &[PathBuf])

// After: Generalized and clear
fn needs_recompile(checking_paths: &[Path])

This approach makes function signatures self-documenting and reduces the cognitive load on API consumers by making valid usage patterns explicit in the type system.


Explicit configuration requirements

Always specify explicit configuration parameters rather than relying on default settings that may vary across different build environments or target platforms. This is particularly critical in test files where assumptions about default compiler settings, target triples, or language standards can cause failures in cross-compilation scenarios or different build configurations.

When writing tests, explicitly specify:

For example, instead of relying on default compiler behavior:

// Problematic - relies on default target triple
// RUN: %clang %s -Dheader="<stdio.h>" -E | tail -1 | FileCheck %s

// Better - explicit configuration
// RUN: %clang_cc1 -x c++ -internal-isystem %S/Inputs/include %s

Or when language features require specific standards:

// Explicit standard specification for C11 features
// RUN: %check_clang_tidy -std=c11-or-later -check-suffix=WITH-ANNEX-K %s

This approach prevents build failures when default configurations differ from expectations, such as when LLVM_DEFAULT_TARGET_TRIPLE is overridden or when different C standard versions are used.


improve code readability

When code expressions become complex or difficult to understand at first glance, refactor them for better readability. This can be achieved through several techniques: extracting complex expressions into well-named variables, using named regex groups instead of numeric indices, or reformatting conditional logic into more concise forms.

For complex expressions, consider extracting intermediate values:

# Instead of:
rewritten_line = (
    self.current_line[: match.start(2)]
    + str(self.frame_no)
    + self.current_line[match.end(2) :]
)

# Use:
frame_no_index = match.start(2)
rewritten_line = (
    self.current_line[:frame_no_index]
    + str(self.frame_no)
    + self.current_line[frame_no_index:]
)

For conditional assignments, prefer concise inline forms when they improve clarity:

# Instead of multi-line conditional blocks:
args.std = (
    ["c++11-or-later"]
    if extension in [".cpp", ".hpp", ".mm"]
    else ["c99-or-later"]
)

# Use:
args.std = [
    "c++11-or-later" if extension in [".cpp", ".hpp", ".mm"] else "c99-or-later"
]

The goal is to make code self-documenting and reduce cognitive load for future readers.


Provide contextual code documentation

Code should include documentation that explains the purpose, rationale, and context behind implementation decisions, not just what the code does. This helps future maintainers understand the reasoning and makes the codebase more maintainable.

Key areas requiring contextual documentation:

  1. Top-level entities: Document the purpose and role of classes, structs, and major functions
  2. File-level context: New files should include comments explaining why they were created or split from other files
  3. Complex logic blocks: When code implements intricate algorithms or generates complex structures, include comments explaining the overall approach
  4. Data structure semantics: Document the meaning and constraints of data structure elements, especially non-obvious ones
  5. Specification compliance: When implementing standards or specifications, quote the relevant text verbatim to preserve intent and context
  6. Conditional logic: Explain the reasoning behind complex conditions, especially when they handle edge cases or specific requirements

Example of good contextual documentation:

// SYCL 2020 section 5.10.1, "SYCL functions and member functions linkage":
//   When a function is declared with SYCL_EXTERNAL, that macro must be
//   used on the first declaration of that function in the translation unit.
//   Redeclarations of the function in the same translation unit may
//   optionally use SYCL_EXTERNAL, but this is not required.
if (hasFirstDeclSYCLExternal && !hasSYCLExternal) {
  // Implementation logic...
}

Avoid redundant comments that merely restate what the code obviously does. Focus on the “why” rather than the “what”.


Design thoughtful API interfaces

When designing APIs, prioritize clarity, appropriate abstraction levels, and user experience. Avoid magic numbers or unclear parameters by using named constants or helper functions. Choose the right balance between generic and specific interfaces - use specific types when the use case is well-defined, but design for genericity when supporting multiple contexts or languages.

Consider the user experience by minimizing complex parameter construction. Instead of requiring users to manually construct complex objects, provide convenience methods or specializations.

Example from the discussions:

// Instead of magic numbers:
Symbolizer->symbolizeData(SymbolizerPath.str(), {Address, 0})

// Use explicit helpers:
static object::SectionedAddress getSectionedAddress(uint64_t Address) {
  return {Address, object::SectionedAddress::UndefSection};
}
Symbolizer->symbolizeData(SymbolizerPath.str(), getSectionedAddress(Address))

// For return types, prefer specific over generic when appropriate:
std::pair<const NamedDecl *, const WarnUnusedResultAttr *>  // specific
// instead of:
std::pair<const NamedDecl *, const Attr *>  // generic

// Provide convenience builders to avoid complex parameter construction:
builder.create<linalg::MatmulTransposeAOp>(...)  // specialized
// instead of requiring users to construct affine maps manually

When designing cross-language or cross-context APIs, consider using discriminator fields or configuration parameters rather than embedding language-specific types in generic structures.


Eliminate redundant null checks

Avoid unnecessary null checks when the called function already handles null cases, and use references instead of pointers when null values are guaranteed not to occur.

Many codebases contain redundant null checks that add complexity without providing safety benefits. This occurs in several patterns:

  1. Double-checking optionals: When extracting values from optionals, avoid checking both the optional’s validity and the extracted value if the extraction method already handles empty cases.

  2. Redundant pre-checks: Don’t check for null before calling functions that already return null for invalid inputs.

  3. Use references for non-null guarantees: When a parameter is guaranteed to be non-null by preconditions, use references instead of pointers to make this contract explicit.

Examples:

// ❌ Redundant: AsCString() already returns nullptr for empty strings
auto mod_name = m_opaque_sp->GetObjectName();
if (!mod_name) {
    return nullptr;
}
return mod_name.AsCString();

// ✅ Simplified: Let AsCString() handle the empty case
auto mod_name = m_opaque_sp->GetObjectName();
return mod_name.AsCString();

// ❌ Redundant optional checking
std::optional<mlir::FlatSymbolRefAttr> aliasee = op.getAliaseeAttr();
if (aliasee && *aliasee)
    return matchAndRewriteAlias(op, *aliasee, ...);

// ✅ Simplified optional handling
if (std::optional<llvm::StringRef> aliasee = op.getAliasee())
    return matchAndRewriteAlias(op, *aliasee, ...);

// ❌ Using pointer when null is impossible
int processSymbol(const Symbol *symbol) {
    // symbol can't be NULL due to preconditions
}

// ✅ Use reference to express non-null contract
int processSymbol(const Symbol &symbol) {
    // Contract is clear: symbol cannot be null
}

Document null safety assumptions in comments when the non-null guarantee isn’t obvious from the function signature, and add explicit null checks (like LIBC_CRASH_ON_NULLPTR) only where parameters should never be null but the type system cannot enforce this.


proper error propagation

Ensure errors are properly propagated to callers rather than handled locally with exits or fatal errors. Library functions should return error information to allow callers to make appropriate decisions about error handling and recovery.

Key principles:

  1. Return errors, don’t exit: Library functions should return error codes or use error types like llvm::Expected instead of calling exit() or llvm::report_fatal_error()
  2. Handle multiple errors systematically: Use proper error handling APIs like handleAllErrors() instead of just converting errors to strings with toString()
  3. Check all return values: Always check return values from functions that can fail, even if they currently always succeed
  4. Use existing error infrastructure: Leverage existing diagnostic systems instead of creating custom error handling

Example of proper error propagation:

// Bad: Fatal error in library function
void parseDataAccessPerfTraces(StringRef File) {
  auto BufferOrErr = MemoryBuffer::getFile(File);
  if (auto EC = BufferOrErr.getError())
    llvm::report_fatal_error(StringRef(Error)); // Don't do this
}

// Good: Return error to caller
std::error_code parseDataAccessPerfTraces(StringRef File) {
  auto BufferOrErr = MemoryBuffer::getFile(File);
  if (auto EC = BufferOrErr.getError())
    return EC; // Let caller decide how to handle
  // ... continue processing
  return std::error_code{};
}

// Good: Handle multiple errors properly
if (!RSDOrErr) {
  handleAllErrors(RSDOrErr.takeError(), [&](ErrorInfoBase &EIB) {
    Ctx->emitError(EIB.message());
  });
} // Instead of: toString(std::move(Err))

This approach enables better error recovery, testing, and allows different callers to handle errors appropriately for their context.


comprehensive test coverage

Tests should comprehensively cover all relevant scenarios, including return values, edge cases, different compilation modes, and abnormal conditions. This includes:

  1. Return Value Testing: Always verify function return values rather than ignoring them. For example, instead of just calling pthread_barrier_wait(&barrier), check the return value and assert expected behavior:
    int result = LIBC_NAMESPACE::pthread_barrier_wait(&barrier);
    if (result == PTHREAD_BARRIER_SERIAL_THREAD) {
      serial_counter.fetch_add(1);
    } else {
      ASSERT_EQ(result, 0);
    }
    
  2. Edge Case Coverage: Add tests for abnormal scenarios like address capturing, incorrect function signatures, and boundary conditions that might not occur in normal usage but could reveal bugs.

  3. Multi-Mode Testing: When applicable, test across different compilation modes (host/device, different C++ standards) to ensure functionality works consistently:
    // RUN: %clang_cc1 -fsycl-is-host -fsyntax-only -verify %s
    // RUN: %clang_cc1 -fsycl-is-device -fsyntax-only -verify %s
    
  4. Coverage Analysis: Use coverage tools to identify untested branches and remove or test unreachable code paths. Functions with many branches should have their coverage verified to ensure all paths are exercised.

  5. Language Feature Testing: Include tests for relevant language features like constexpr, consteval, and other constructs that might interact with the code being tested.

This approach helps catch bugs that might only manifest in specific scenarios and ensures robust, reliable code across different environments and use cases.


environment loading order

Environment files and variables must be loaded before creating any factories, services, or components that depend on them. This ensures that environment-based configuration propagates correctly throughout the application lifecycle.

Load environment files early in the initialization sequence, before creating factories or services that read environment variables. Additionally, clean up sensitive environment variables after reading to prevent unintended propagation to subprocesses.

Example of correct ordering:

// Load environment file first
load_env_variables_from_env_file(
  flags.env_file,
  log_level,
);

// Then create factory (which may read env vars)
let factory = create_factory()?;
let cli_options = factory.cli_options()?;

// Clean up sensitive env vars after reading
let control_sock = std::env::var("DENO_CONTROL_SOCK")?;
std::env::remove_var("DENO_CONTROL_SOCK"); // Prevent subprocess propagation

Avoid using .env() in CLI argument definitions since the environment file hasn’t been processed yet at argument parsing time. Instead, read environment variables after the environment file has been loaded and apply them to the appropriate configuration structures.


network address validation

When validating network addresses and interfaces, properly handle special address values and use protocol-specific prefixes to avoid ambiguity. Network address validation should account for standard special addresses like INADDR_ANY (0.0.0.0) which allows the operating system to choose an appropriate interface, rather than treating them as invalid. For address parsing that supports multiple protocols, use explicit prefixes to disambiguate between different address types.

For multicast interface validation, allow 0.0.0.0 as a valid interface address:

// Instead of rejecting 0.0.0.0 as invalid
if !interface_addr.is_multicast() {
  return Err(NetError::InvalidHostname(address));
}

// Allow INADDR_ANY for OS interface selection
if interface_addr == Ipv4Addr::new(0, 0, 0, 0) || interface_addr.is_multicast() {
  // Valid interface specification
}

For address parsing supporting multiple protocols, require explicit prefixes:

// Use protocol prefixes to avoid parsing ambiguity
match address_str {
  addr if addr.starts_with("tcp:") => parse_tcp_address(&addr[4..]),
  addr if addr.starts_with("unix:") => parse_unix_address(&addr[5..]),
  addr if addr.starts_with("vsock:") => parse_vsock_address(&addr[6..]),
  _ => return Err("Address must specify protocol prefix"),
}

This approach prevents validation bugs where legitimate network configurations are incorrectly rejected and ensures consistent address parsing across different network protocols.


protect shared data

Always protect shared data that can be accessed by multiple threads using appropriate synchronization mechanisms. Identify potential race conditions where shared state could be modified concurrently and choose the right protection mechanism.

For simple data that needs atomic updates, use atomic operations:

// TODO: needs a mutex
// Better: use atomic for simple counters/flags
std::atomic<int> shared_counter{0};

For complex shared state or when you need to protect critical sections, use mutexes:

// Protect complex operations on shared data
std::mutex data_mutex;
void update_shared_state() {
    std::lock_guard<std::mutex> lock(data_mutex);
    // Critical section - modify shared data safely
}

Be especially careful with global variables that have external linkage, as they can be modified by other compilation units, breaking thread safety assumptions. Consider using static linkage or proper synchronization:

// Problematic: global linkage allows external modification
const int SHARED_CONSTANT = -1;

// Better: static linkage prevents external access
static const int SHARED_CONSTANT = -1;
// Or: use proper synchronization for truly shared data

When reviewing code, look for shared mutable state and verify it has appropriate protection against concurrent access.


Validate boundary conditions

Ensure algorithms handle boundary conditions and edge cases correctly by adding explicit validation for all input ranges. Special attention should be paid to index calculations, offset arithmetic, and memory management operations, as these are common sources of subtle bugs that only manifest in edge cases.

When implementing algorithms:

  1. Add explicit assertions or range checks for numerical bounds:
    // Add safety check for numerical bounds
    if let Some(ver) = ver {
     // Ensure version index doesn't conflict with special flags
     assert!(ver + 2 < VERSYM_HIDDEN);
     elf::VERSYM_HIDDEN | (2 + ver as u16)
    }
    
  2. Validate offset and length calculations to prevent overflows or out-of-bounds access:
    // Use correct length calculation (not offset + length)
    (inner_prov.alloc_id(), offset.bytes(), len)
    
  3. For memory-related operations, handle special cases like indirect arguments or resource deallocation explicitly:
    if tail {
     // Detect unsupported cases
     if has_indirect_args {
         bug!("musttail call with indirect arguments is not supported");
     }
     // Ensure proper ordering of operations
     bx.tail_call(fn_ty, fn_attrs, fn_abi, fn_ptr, llargs, self.funclet(fx), instance);
    }
    
  4. For complex dataflow analysis, verify that your algorithm handles uninitialized values, moved values, and aliasing correctly at all program points:
    // Check storage liveness at every use location
    if self.head_storage_to_check.contains(head) {
     self.maybe_storage_dead.seek_after_primary_effect(location);
     if self.maybe_storage_dead.get().contains(head) {
         self.storage_to_remove.insert(head);
     }
    }
    

Thorough boundary condition validation prevents difficult-to-diagnose bugs and makes code more robust against unexpected inputs or state changes.


Keep documentation purposefully minimal

Documentation should be concise, focused, and maintainable. Follow these principles:

  1. Keep examples short and demonstrate one concept at a time
  2. Avoid redundant documentation across related items
  3. Include maintenance notes (FIXME/TODO) with issue links for temporary documentation
  4. Document fields and parameters clearly but briefly

Good example:

/// A mutex guard for accessing protected data.
/// 
/// See [`Mutex`] for more usage examples.
#[must_use = "if unused the Mutex will immediately unlock"]
pub struct MutexGuard<'a, T: ?Sized + 'a> {
    /// The underlying mutex reference
    lock: &'a Mutex<T>,
}

Problematic example:

/// A mutex guard for accessing protected data.
/// This implements RAII pattern for mutex locking.
/// When dropped, it automatically unlocks the mutex.
/// 
/// # Examples
/// 
/// ```
/// // Long example duplicating documentation from Mutex
/// let mutex = Mutex::new(0);
/// let guard = mutex.lock();
/// *guard = 2;
/// // Many more lines...
/// ```
pub struct MutexGuard<'a, T: ?Sized + 'a> {
    lock: &'a Mutex<T>, // Undocumented field
}

Document function behavior completely

Functions should be documented with comprehensive JSDoc comments that cover:

  1. Purpose and behavior description
  2. All parameters with their types and constraints
  3. Return value and possible undefined cases
  4. Error conditions that may trigger exceptions
  5. Deprecation notices when applicable
  6. Explanatory comments for complex logic

Example:

/**
 * Returns a diagnostic message for ECMAScript module syntax errors
 * in CommonJS files under verbatimModuleSyntax.
 *
 * @param node - The AST node where the error occurred
 * @returns A DiagnosticMessage explaining the error. If the file has a .cts or .cjs extension,
 *          a specific error message for CommonJS files is returned. Otherwise, a more general
 *          error message with suggestions for resolving the issue is returned.
 * @throws {SyntaxError} If the node type is invalid for module syntax checking
 * @deprecated Use getModuleDiagnostic() instead
 */
function getVerbatimModuleSyntaxErrorMessage(node: Node): DiagnosticMessage {
    // Skip validation for non-module files to improve performance
    const sourceFile = getSourceFileOfNode(node);
    const fileName = sourceFile.fileName;
    // ...
}

Benchmark before optimizing code

Always validate performance optimizations with benchmarks before implementation. Ensure measurements account for:

  1. Platform-specific characteristics (32-bit vs 64-bit)
  2. Realistic usage patterns
  3. Appropriate metrics (wall time vs CPU time)

Example:

#[bench]
fn write_64bit_hex(bh: &mut Bencher) {
    // Test common cases first
    bh.iter(|| {
        write!(black_box(discard), "{:x}", black_box(0_u64)).unwrap();
        write!(black_box(discard), "{:x}", black_box(10000_i64)).unwrap();
        // Test edge cases
        write!(black_box(discard), "{:x}", black_box(-10000_i64)).unwrap();
    });
}

Avoid premature optimization based on theoretical gains. For instance, reusing buffers might seem beneficial but benchmarks often show stack allocation is equally efficient:

// Prefer simple, clear code unless benchmarks show meaningful gains
let mut buf = NumBuffer::new();  // Creates temporary buffer on stack
format!("{}", number)            // Let compiler optimize common case

Provide actionable errors

Error messages should not only identify problems but also guide developers toward solutions. Include specific steps, alternatives, or configuration changes that can resolve the issue.

When designing error handling:

  1. Make error messages specific to the exact construct causing the error
  2. Position error indicators at locations that clearly indicate the source of the problem
  3. Include remediation steps in the error message when possible
  4. Consider graceful degradation for non-critical errors where it improves user experience

Example of a good error message:

// Instead of:
if (fileExtensionIsOneOf(fileName, [Extension.Cts, Extension.Cjs])) {
    return Diagnostics.ECMAScript_imports_and_exports_cannot_be_written_in_a_CommonJS_file_under_verbatimModuleSyntax;
}

// Prefer:
if (fileExtensionIsOneOf(fileName, [Extension.Cts, Extension.Cjs])) {
    return Diagnostics.ECMAScript_imports_and_exports_cannot_be_written_in_a_CommonJS_file_under_verbatimModuleSyntax_Adjust_the_type_field_in_the_nearest_package_json_to_make_this_file_an_ECMAScript_module_or_adjust_your_verbatimModuleSyntax_module_and_moduleResolution_settings_in_TypeScript;
}

This approach reduces debugging time by helping developers understand not just what went wrong, but how to fix it. For complex configurations or language features, this guidance is especially valuable to both new and experienced developers.


Default over unsafe initialization

Prefer using safe initialization methods like Default::default() over unsafe alternatives like MaybeUninit::uninit() or null values when initializing variables. This reduces the risk of undefined behavior and eliminates unnecessary unsafe blocks.

Example - Instead of:

let mut config_data: MaybeUninit<ConfigData> = MaybeUninit::zeroed();
// ... later ...
unsafe { config_data.assume_init() }

Prefer:

let config_data = ConfigData::default();

This approach:

Only use MaybeUninit or manual null handling when there are specific performance requirements or when dealing with FFI boundaries where default initialization is not possible.


Standardize configuration value handling

Implement robust and type-safe configuration handling to avoid fragile hardcoding and improve maintainability. Key guidelines:

  1. Use type-safe structures for passing configuration between processes instead of raw strings
  2. Avoid hardcoding environment paths or configuration values
  3. Use environment variables through a centralized configuration system
  4. Validate configuration values at startup

Example of improved configuration handling:

// Instead of this:
let docs = env::args_os().nth(1).expect("doc path should be first argument");
let docs = env::current_dir().unwrap().join(docs);

// Do this:
#[derive(Parser)]
struct Config {
    docs: PathBuf,
    #[clap(long)]
    link_targets_dir: Vec<PathBuf>,
}

let config = Config::parse();
let docs = config.docs.canonicalize()?;

This approach:


Match function names to behavior

Function names and their documentation must accurately reflect what the function actually does. When a function handles more data than its name suggests, either rename the function or split the functionality.

In the example below, formatDate() actually formats both date and time components, making the name misleading:

/**
 * Formats the given date as a string in the form "YYYYMMdd".
 */
function formatDate(date: Date): string {
    const year = date.getFullYear().toString().padStart(4, "0");
    const month = (date.getMonth() + 1).toString().padStart(2, "0");
    const day = date.getDate().toString().padStart(2, "0");
    const hour = date.getHours().toString().padStart(2, "0");
    const minute = date.getMinutes().toString().padStart(2, "0");
    const seconds = date.getSeconds().toString().padStart(2, "0");
    return year + month + day + hour + minute + seconds;
}

Better approaches:

This prevents confusion about what data the function processes and ensures the API is self-documenting.


Conditional CI resource management

Configure CI workflows to intelligently manage system resources through conditional execution rather than duplicating steps. Use matrix variables or job conditions to determine when resource-intensive operations should run.

For resource monitoring tasks (like disk usage checks), define a condition that prevents redundant execution:

- name: print disk usage
  # Only run this step if the free_disk operation isn't executed
  if: ${{ !matrix.free_disk }}
  run: |
    echo "disk usage:"
    df -h

When configuring runners, explicitly document resource constraints and set appropriate flags that control resource management steps:

runners:
  - &job-windows
    os: windows-2025
    free_disk: true  # Explicitly mark jobs that need disk space freed
    <<: *base-job

This approach keeps workflows maintainable by avoiding duplicative steps, makes resource constraints visible, and ensures consistent behavior across different execution environments.


Ensure complete test coverage

Write comprehensive tests that cover all relevant cases and variations while maintaining proper organization and structure. Key practices:

  1. Place tests in appropriate locations (e.g., core tests in library/coretests)
  2. Include FileCheck annotations for validation
  3. Test both positive and negative cases separately
  4. Cover analogous behaviors and backwards compatibility
  5. Structure tests within proper test functions

Example:

// In library/coretests/your_module.rs
#[test]
fn test_feature_behavior() {
    // Test primary functionality
    let result = do_something();
    assert_eq!(result.primary(), expected);
    
    // Test analogous case
    let alt_result = do_something_similar();
    assert_eq!(alt_result.similar(), expected);
    
    // Test backwards compatibility
    assert_eq!(result.legacy_method(), old_expected);
    assert_eq!(result.new_method(), new_expected);
}

// Separate file for failure cases
// In tests/ui/your_module_failures.rs
//@ build-fail
//@ ignore-pass
fn test_invalid_case() {
    // Test expected failure
    let result = invalid_operation();
    //~^ ERROR expected error message
}

Name for semantic meaning

Choose names that clearly convey the semantic meaning and purpose of the identifier, rather than using clever or ambiguous names. Names should be explicit and descriptive enough that their purpose is immediately clear to readers.

Key guidelines:

Example:

// Less clear:
impl LintStoreMarker for Store { }
let id = trait_pred.self_ty();

// More clear:
impl DynLintStore for Store { }
let type_id = trait_pred.self_ty();

This approach makes code more maintainable and self-documenting by reducing cognitive load on readers. When multiple similar concepts are in scope, use more specific names to distinguish their roles.


Optimize dependency configurations

When configuring project dependencies, be mindful of feature flags that may introduce unnecessary build dependencies or slow down compilation. For libraries like serde, separate the core functionality from derive macros to improve build parallelization:

# Preferred approach - separates core from proc macros
serde = "1.0.219"
serde_derive = "1.0.219"

# Instead of:
# serde = { version = "1.0.219", features = ["derive"] }

For tools and utilities that need to be lightweight, avoid heavy dependencies with proc-macro features when alternatives exist. Consider using builder APIs instead of derive-based approaches, or explicitly opt out of default features that aren’t needed. This practice helps maintain fast build times and reduces the dependency footprint of your project.


Document lock behavior

When implementing or documenting synchronization primitives, always clearly specify how locks behave under exceptional conditions, particularly during thread panics. This information is critical for developers to write robust concurrent code.

Key aspects to document:

  1. What happens to the lock when a thread holding it panics
  2. How other threads can interact with previously locked resources
  3. Whether the implementation uses poisoning or non-poisoning semantics

For example, when documenting a mutex implementation, include explicit statements like:

/// If this thread panics while the lock is held, the lock will be released like normal.
/// 
/// # Example
/// 
/// ```rust
/// use std::thread;
/// use std::sync::{Arc, nonpoison::Mutex};
/// 
/// let mutex = Arc::new(Mutex::new(0u32));
/// let mut handles = Vec::new();
/// 
/// for n in 0..10 {
///     let m = Arc::clone(&mutex);
///     let handle = thread::spawn(move || {
///         let mut guard = m.lock();
///         *guard += 1;
///         panic!("panic from thread {n} {guard}")
///     });
///     handles.push(handle);
/// }
/// 
/// for h in handles {
///     h.join().unwrap_err(); // Threads panicked as expected
/// }
/// 
/// // The mutex can still be locked despite previous panics
/// println!("Finished, locked {} times", mutex.lock());
/// ```
///

Additionally, be explicit about concurrent operation limits and clearly distinguish between different types of memory operations (e.g., volatile vs. atomic) to prevent misuse in concurrent contexts.


Guard against undefined

Always protect against potential null or undefined values before attempting property access or method calls to prevent runtime errors. This applies especially to array access, method calls like .some() or .length, and property access on objects that might be null.

Bad practice:

// Might throw if entrypoints is undefined
if (some(entrypoints, e => project.toPath(e) === path)) { ... }

// Might throw "Cannot read property 'length' of undefined"
const length = text.length;

// Potential index out of bounds
while (sourceFile.statements[pos].end < statement.end) { ... }

// Creates keys with 'undefined' as string literal
const key = `${useOnlyExternalAliasing ? 0 : 1}|${firstRelevantLocation && getNodeId(firstRelevantLocation)}|${meaning}`;

Good practice:

// Guard with logical AND
if (entrypoints && some(entrypoints, e => project.toPath(e) === path)) { ... }

// Use optional chaining
const length = text?.length;

// Check array bounds
while (pos < sourceFile.statements.length && sourceFile.statements[pos].end < statement.end) { ... }

// Provide safe fallback value
const key = `${useOnlyExternalAliasing ? 0 : 1}|${firstRelevantLocation ? getNodeId(firstRelevantLocation) : 0}|${meaning}`;

Modern TypeScript provides several ways to handle nullable values safely: optional chaining (?.), nullish coalescing (??), and traditional guards (x !== undefined). Choose the approach that makes your code most readable while ensuring runtime safety.


Structure validation algorithms

When implementing or modifying parsing and validation algorithms, carefully consider both the correctness and user experience aspects:

  1. Preserve structural ordering in data structures like ASTs when order impacts semantics. As noted in discussion #1, “In some cases, like in macro scoping, the order is actually important,” so field reordering can introduce subtle bugs that are difficult to track down.

  2. Implement intelligent error recovery for mismatched delimiters by analyzing the context. For different mismatched delimiters scenarios, determine the most likely error:

// When suggesting missing delimiters, analyze the surrounding context
// BAD: Generic message for all cases
if 1 < 2 {
    let _a = vec!]; // Just showing "mismatched closing delimiter"
}

// GOOD: Context-aware message
if 1 < 2 {
    let _a = vec!]; // "mismatched closing delimiter, may be missing open `[`"
}
  1. Avoid over-suggesting fixes when multiple interpretations are possible. As mentioned in discussion #8, for constructs like #![w,), the fix could be either [w,] or (w,) depending on context, so the diagnostic algorithm should avoid suggesting a specific solution when ambiguous.

  2. Track related delimiter errors by collecting information about unmatched opening delimiters to provide more comprehensive diagnostics, as suggested in discussion #7.

These validation algorithms should prioritize correctness while providing meaningful guidance to developers when errors occur.


Use descriptive names

Choose variable, function, and parameter names that clearly communicate their purpose and avoid confusion. Names should be descriptive enough that their intent is obvious without requiring additional context or comments.

Key principles:

Examples of improvements:

// Poor: confusing parameter names
fn string_reproduces(file string, pattern string, command string, path string) bool

// Better: clear, distinct parameter names  
fn string_reproduces(file_content string, pattern string, command string, file_path string) bool

// Poor: abbreviated, unclear method name
fn (mut c DiffContext[T]) gen_str() string

// Better: descriptive method name
fn (mut c DiffContext[T]) generate_patch() string

// Poor: misleading function name vs return type
fn (mut g Gen) get_enum_type_idx_from_fn_name(fn_name string) (string, ast.Type)

// Better: name matches return type
fn (mut g Gen) get_enum_type_from_fn_name(fn_name string) (string, ast.Type)

This approach reduces cognitive load for code readers and makes the codebase more maintainable by eliminating ambiguity about what variables and functions represent.


Clear helpful error messages

Create user-friendly error messages that guide developers toward solutions. Error messages should:

  1. Include the problematic value in the message
  2. Provide clear suggestions for fixing the issue
  3. Avoid duplicate errors for the same problem
  4. Use help/note sections for additional context

Example:

// Instead of:
early_dcx.early_warn("option `-o` has no space between flag name and value");

// Do this:
early_dcx.early_warn(
    "option `-o` has no space between flag name and value, which can be confusing"
);
early_dcx.early_help(
    format!("insert a space between `-o` and `{name}` if this is intentional: `-o {name}`")
);

The error message should clearly identify the issue, show the problematic value, and provide actionable guidance for resolution. Use help/note sections to separate the error description from suggestions and additional context.


Extract complex logic helpers

Complex or duplicated logic should be extracted into well-named helper functions to improve code readability and maintainability. This applies to:

  1. Large blocks of code in functions that handle a specific subtask
  2. Similar logic repeated in multiple places
  3. Complex conditional logic that can be given a descriptive name

Example:

Instead of:

fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<getopts::Matches> {
    // ... other code ...
    
    if let Some(name) = matches.opt_str("o")
        && let Some(suspect) = args.iter().find(|arg| arg.starts_with("-o") && *arg != "-o")
    {
        let confusables = ["optimize", "o0", "o1", "o2", "o3", "ofast", "og", "os", "oz"];
        if let Some(confusable) = check_confusables(&suspect, &confusables) {
            early_dcx.early_warn(
                "option `-o` has no space between flag name and value, which can be confusing",
            );
            early_dcx.early_note(format!(
                "option `-o {}` is applied instead of a flag named `o{}` to specify output filename `{}`",
                name, name, name
            ));
            if !confusable.is_empty() {
                early_dcx.early_note(format!("Do you mean `{}`?", confusable));
            }
        }
    }
}

Better:

fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<getopts::Matches> {
    // ... other code ...
    warn_on_confusing_output_filename_flag(early_dcx, &matches, args);
}

fn warn_on_confusing_output_filename_flag(early_dcx: &EarlyDiagCtxt, matches: &Matches, args: &[String]) {
    if let Some(name) = matches.opt_str("o")
        && let Some(suspect) = args.iter().find(|arg| arg.starts_with("-o") && *arg != "-o")
    {
        let confusables = ["optimize", "o0", "o1", "o2", "o3", "ofast", "og", "os", "oz"];
        if let Some(confusable) = check_confusables(&suspect, &confusables) {
            early_dcx.early_warn(
                "option `-o` has no space between flag name and value, which can be confusing",
            );
            early_dcx.early_note(format!(
                "option `-o {}` is applied instead of a flag named `o{}` to specify output filename `{}`",
                name, name, name
            ));
            if !confusable.is_empty() {
                early_dcx.early_note(format!("Do you mean `{}`?", confusable));
            }
        }
    }
}

This improves code by:


avoid expensive repeated operations

Cache results of expensive computations and order operations from cheapest to most expensive to minimize performance overhead. This includes storing function call results in local variables, extracting constants to avoid repeated allocations, using appropriate buffer sizes, and placing fast conditional checks before slower ones.

Key optimization strategies:

Example of caching expensive operations:

// Before: expensive repeated calls
if !n.contains('.') && n !in c.g.fn_addr.keys() {
    // ... later in code
    if n !in c.g.fn_addr.keys() {
        // keys() called again
    }
}

// After: cache the expensive result
fn_addr_keys := c.g.fn_addr.keys()
if !n.contains('.') && n !in fn_addr_keys {
    // ... later in code  
    if n !in fn_addr_keys {
        // reuse cached result
    }
}

Example of condition ordering:

// Before: expensive check first
if node.expr is ast.StringLiteral && node.field_name == 'str' && !f.pref.backend.is_js()

// After: cheap check first
if !f.pref.backend.is_js() && node.field_name == 'str' && node.expr is ast.StringLiteral

Consistent descriptive identifiers

Use camelCase for all variables, parameters, methods, and functions in JavaScript/TypeScript code to maintain consistency with language conventions. Choose names that accurately describe the purpose and behavior of identifiers, and avoid naming collisions between different scopes.

Do this:

interface CSVParserOptions {
  header?: boolean;
  delimiter?: string;
  trimWhitespace?: boolean; // camelCase instead of snake_case
  dynamicTyping?: boolean;  // camelCase instead of snake_case
}

function diagnose(
  fixtureDir: string,
  config: {
    options?: Partial<ts.CompilerOptions>;
    extraFiles?: Record<string, string>; // Clear, descriptive name that won't conflict
  } = {},
) {
  const tsconfig = config.options ?? {};
  const extraFiles = config.extraFiles;
  // ...
}

Don’t do this:

interface CSVParserOptions {
  header?: boolean;
  delimiter?: string;
  trim_whitespace?: boolean; // Inconsistent with JS/TS conventions
  dynamic_typing?: boolean;  // Inconsistent with JS/TS conventions
}

function diagnose(
  fixtureDir: string,
  config: {
    options?: Partial<ts.CompilerOptions>;
    files?: Record<string, string>; // Could conflict with local variables
  } = {},
) {
  const tsconfig = config.options ?? {};
  const files = config.files;
  // Can lead to confusion with other 'files' variables in the function
}

Avoid unused identifiers, or clearly document why they’re being parsed but not used. Choose names that accurately reflect the behavior of functions rather than their implementation details to improve code readability and maintainability.


Follow naming conventions

Maintain consistent naming conventions across the codebase:

// Correct static void All(const v8::FunctionCallbackInfo<v8::Value>& info); static void Get(const v8::FunctionCallbackInfo<v8::Value>& info);


- Use snake_case for property names and variables
```cpp
// Incorrect
V(clientId_string, "clientId")

// Correct
V(client_id_string, "clientId")

// Correct static constexpr size_t kReserveSizeAndAlign = … // or static constexpr size_t RESERVE_SIZE_AND_ALIGN = …


- Use PascalCase for concepts and templates that define types
```cpp
// Incorrect
template <typename T>
concept is_callable = ...

// Correct
template <typename T>
concept IsCallable = ...

Following these conventions improves code readability and maintains consistency throughout the codebase.


Limit environment variable scope

When working with environment variables for configuration:

  1. Reuse existing environment variables rather than creating new ones. Leverage established variables like NODE_TEST_CONTEXT where possible to avoid fragmentation.

  2. Extract only necessary environment variables instead of passing the entire environment. This improves security and makes dependencies explicit.

// Avoid:
proxyEnv: process.env.NODE_USE_ENV_PROXY ? process.env : undefined,

// Prefer:
proxyEnv: process.env.NODE_USE_ENV_PROXY ? {
  HTTP_PROXY: process.env.HTTP_PROXY,
  HTTPS_PROXY: process.env.HTTPS_PROXY,
  NO_PROXY: process.env.NO_PROXY
} : undefined,
  1. Check environment variables consistently and be mindful of truthiness. Remember that environment variables are strings or undefined, and plan accordingly.

  2. Document new environment variables if you absolutely must create them, and ensure they follow established naming conventions for your project.


Optimize frequent operations

Identify code paths that execute frequently (loops, hot functions, repeated calls) and optimize them by avoiding redundant computations, expensive operations, and unnecessary allocations.

Key optimization strategies:

Example of avoiding redundant calls:

// Before: calling node.is_named() twice
fn caller() {
    if node.is_named() {
        render_node_range(cursor, node.is_named()); // redundant call
    }
}

// After: cache the result
fn caller() {
    let is_named = node.is_named();
    if is_named {
        render_node_range(cursor, is_named);
    }
}

Focus especially on optimizing code that processes large datasets, handles user input, or runs in tight loops where small inefficiencies compound into significant performance impacts.


Technical documentation accuracy

Documentation must precisely reflect the current state of the codebase to prevent confusion and ensure developers can rely on it. Ensure that:

  1. References to packages, tools, or features that have been removed or renamed are updated or deleted from documentation
  2. Technical specifications (architectures, versions, etc.) accurately match the actual components they describe
  3. Configuration options and parameters are described using correct terminology that reflects their actual type and function

Example of correct documentation:

You can run the test suite either using `bun test <path>` or by using the wrapper script `bun node:test <path>`. The `bun node:test` command runs every test file in a separate instance of bun.exe, to prevent a crash in the test runner from stopping the entire suite.

Rather than referencing deleted packages or using imprecise terminology, this accurately describes the current testing capabilities and their behavior.


Resource-aware programming patterns

When optimizing application performance, be mindful of system resource constraints and use appropriate patterns to handle different scenarios efficiently:

  1. I/O operations: Use streaming APIs for large files instead of loading entire files into memory. This avoids hitting internal constraints and reduces memory pressure.
// Inefficient for large files - may hit 2 GiB limit
fs.readFile('large-file.txt', (err, data) => {
  // Process the entire file at once
});

// Better approach - process chunks incrementally
const stream = fs.createReadStream('large-file.txt');
stream.on('data', (chunk) => {
  // Process each chunk as it arrives
});
  1. Memory management: Monitor memory usage metrics to identify potential issues. Watch for signs like rising rss values while heapTotal remains stable, which may indicate memory fragmentation or leaks.

  2. Buffering strategy: For performance-critical I/O operations, implement proper buffering with explicit flush control. Handle system resource constraints like EAGAIN errors gracefully with appropriate backpressure or fallback mechanisms.

Addressing these resource constraints proactively will help your application maintain consistent performance under various load conditions and system states.


Descriptive behavior-based tests

Tests should be named to describe the expected behavior or outcome being verified, not the input parameters or implementation details. This makes tests more meaningful as documentation and easier to understand when they fail.

When writing test names:

Instead of:

test('help arg value config must be a string', () => {
  // Test code
});

Prefer:

test('when help option receives non-string value, then throws type error', () => {
  // Test code
});

Tests should also have exactly one expected outcome without conditional assertions. This ensures deterministic tests that clearly indicate what behavior is considered correct.

Avoid:

if (stderr) {
  // One assertion path
} else {
  // Different assertion path
}

Instead, be explicit about what the test expects:

strictEqual(stderr, '');
strictEqual(stdout, 'exports require module __filename __dirname\n');

Validate loop boundary conditions

When implementing iterative algorithms, ensure comprehensive handling of edge cases and boundary conditions. This includes:

  1. Using while loops instead of if-else chains for repetitive operations
  2. Explicitly handling overflow/underflow scenarios
  3. Validating both start and end conditions
  4. Testing with boundary values

Example - Before (problematic):

if (strings.endsWith(normalized_name, "/")) {
    normalized_name = normalized_name[0 .. normalized_name.len - 1];
} else if (strings.endsWith(normalized_name, "\\")) {
    normalized_name = normalized_name[0 .. normalized_name.len - 1];
}

Example - After (robust):

while (strings.endsWith(normalized_name, "/") or 
       strings.endsWith(normalized_name, "\\")) {
    normalized_name = normalized_name[0 .. normalized_name.len - 1];
}

This approach prevents issues like:

When implementing iterative algorithms, always consider:

  1. What happens at zero/empty input?
  2. What happens at maximum values?
  3. Can the operation need to be repeated?
  4. Are all edge cases handled explicitly?

Evolve return values

When extending APIs with new capabilities, carefully consider how changes to return values affect consumers. Avoid creating polymorphic return types based on input options as this reduces predictability and makes it difficult to programmatically detect supported features.

Instead, follow these patterns:

  1. For APIs already returning objects:
    • Extend the existing object with new capabilities (e.g., adding Symbol.dispose)
    • Maintain backward compatibility by preserving all existing properties
  2. For APIs returning primitives or immutable types:
    • Create a new, distinctly named API variant (e.g., mkdtempmkdtempDisposable)
    • Return an object that includes both the original value and the new capability
    • Clearly document the relationship between the original and new APIs
// AVOID: Polymorphic returns based on options
function createTempDir(prefix, { disposable = false } = {}) {
  const path = makeTempDir(prefix);
  return disposable ? 
    { path, [Symbol.dispose]: () => removeTempDir(path) } : 
    path;
}

// BETTER: Separate, clearly named APIs
function createTempDir(prefix) {
  return makeTempDir(prefix);
}

function createDisposableTempDir(prefix) {
  const path = makeTempDir(prefix);
  return {
    path,
    [Symbol.dispose]: () => removeTempDir(path)
  };
}

When introducing new return types:


Informative error messages

Error messages should be specific, actionable, and include context that helps developers understand and fix the issue. Use standard error codes that can be tested and suppressed rather than relying only on text messages. Create errors at the point of detection rather than inside callbacks to preserve useful stack traces.

When creating custom error messages for complex scenarios, include:

  1. What went wrong (the specific condition that failed)
  2. Why it matters (the impact of the failure)
  3. How to fix it (clear steps to resolve the issue)

Example of an improved error message:

// Instead of:
throw new Error('Invalid module format');

// Prefer:
throw new ERR_AMBIGUOUS_MODULE_SYNTAX(
  'Cannot determine intended module format because both `require()` and top-level ' +
  '`await` are present. If the code is intended to be CommonJS, wrap `await` in an ' +
  'async function. If the code is intended to be an ES module, replace `require()` ' +
  'with `import`.'
);

// And when testing, check the code, not the message:
assert.throws(() => moduleOperation(), { code: 'ERR_AMBIGUOUS_MODULE_SYNTAX' });

For warnings that should be suppressible, always use a warning code:

process.emitWarning(
  'Detected `fs.readFile()` to read a huge file in memory. Consider using ' +
  '`fs.createReadStream()` instead to minimize memory overhead.',
  'ERR_FS_FILE_TOO_LARGE'
);

When handling errors in async contexts, create the error object before entering the async callback to ensure it has a useful stack trace:

// Instead of:
if (options.signal?.aborted) {
  return process.nextTick(() => callback(new AbortError()));
}

// Prefer:
if (options.signal?.aborted) {
  const err = new AbortError();
  return process.nextTick(() => callback(err));
}

Version APIs with care

When introducing new API features or changes, implement proper versioning to maintain stability and backward compatibility. Key practices:

  1. Guard experimental features behind version flags
  2. Add new enum values only at the end of existing enums
  3. Maintain explicit version checks in implementation
  4. Document version dependencies clearly

Example:

// Good: New enum value added at end with experimental guard
typedef enum {
  napi_uint32_array,
  napi_float32_array,
  napi_float64_array,
#ifdef NAPI_EXPERIMENTAL
  napi_float16_array,  // New experimental feature
#endif
} napi_typedarray_type;

// Good: Implementation with version check
if (env->module_api_version != NAPI_VERSION_EXPERIMENTAL) {
  // Handle non-experimental version appropriately
}

This approach ensures API stability, enables proper testing between versions, and provides clear migration paths for API consumers.


prefer compile-time configuration

Use compile-time configuration checks with cfg! macros instead of runtime environment variable parsing when the configuration decision can be determined at build time. This improves performance by eliminating runtime checks and makes the code’s behavior more predictable.

Prefer this:

if cfg!(target_family = "wasm") {
    let sysroot = std::path::Path::new("bindings/rust/wasm-sysroot");
    c_config.include(sysroot);
}

#[cfg(target_env = "msvc")]
c_config.flag("-utf-8");

#[cfg(feature = "std")]
use std::fs;

Instead of this:

if std::env::var("TARGET").unwrap() == "wasm32-unknown-unknown" {
    let sysroot_dir = std::path::Path::new("bindings/rust/wasm-sysroot");
    c_config.include(sysroot_dir);
}

Use cfg! for target platform checks, #[cfg(feature = "...")] for optional features, and #[cfg(target_env = "...")] for toolchain-specific behavior. Reserve runtime environment variable checks for user-configurable settings that must be determined at runtime, not build-time architectural decisions.


Follow consistent naming patterns

Maintain consistent naming conventions throughout the codebase to improve readability and reduce confusion. Adhere to these guidelines:

  1. Function naming patterns: Use established prefixes like create for factory functions, which accurately conveys their purpose and aligns with existing patterns.
    // Preferred
    const counter = createCounter('api.calls', { service: 'web' });
    const timer = createTimer('api.request.duration', { service: 'web' });
       
    // Avoid
    const counter = counter('api.calls', { service: 'web' });
    
  2. Method capitalization: Document instance methods with lowercase first letters, reserving capitalization for static methods.
    // Preferred (instance method)
    blockList.fromJSON(value)
       
    // Avoid (incorrect capitalization for instance method)
    BlockList.fromJSON(value)
    
  3. Semantic specificity: Choose specific method names that prevent collisions and clearly communicate purpose. Avoid overly generic names like use() when more descriptive alternatives like useEventListener() or addDisposableEventListener() are clearer.

  4. Domain-consistent terminology: Use consistent terminology across related APIs. For example, if most of your file system API uses “file descriptor” or “fd”, maintain that terminology throughout rather than using alternatives like “handle” for the same concept.

  5. Documentation formatting: Follow established documentation patterns. Don’t introduce formatting inconsistencies like prefixing types with “Type:” when the rest of the documentation uses a different convention.

Consistent naming makes codebases easier to learn, navigate, and maintain while reducing cognitive load for developers.


Use consistent test patterns

Standardize testing by leveraging established patterns and helper functions throughout your test suite. Extract repetitive test setup into lifecycle hooks like beforeEach or shared fixtures. Use existing test helpers rather than duplicating logic, and organize tests logically by functionality.

For example, instead of repeating server setup in multiple tests:

test("test case 1", async () => {
  using server = Bun.serve({
    port: 0,
    async fetch(req, res) { /* ... */ },
  });
  // test logic
});

test("test case 2", async () => {
  using server = Bun.serve({
    port: 0,
    async fetch(req, res) { /* ... */ },
  });
  // test logic
});

Prefer using lifecycle hooks:

describe("server tests", () => {
  let server;
  
  beforeEach(() => {
    server = Bun.serve({
      port: 0,
      async fetch(req, res) { /* ... */ },
    });
  });
  
  afterEach(() => {
    server.stop();
  });
  
  test("test case 1", async () => {
    // test logic using server
  });
  
  test("test case 2", async () => {
    // test logic using server
  });
});

Similarly, use established helper functions (like fixtureURL, itBundled) for resource loading and specific testing scenarios. Group related tests into logical units and place tests in files that match their functionality. This approach reduces code duplication, improves maintainability, and makes tests easier to understand.


Target-aware configuration handling

When implementing features that depend on specific compilation targets or modes, design configuration mechanisms that gracefully handle target availability differences. Provide clear detection methods for feature availability on the current target, and ensure attributes and builtins work consistently across different compilation contexts.

For heterogeneous compilations, distinguish between general feature availability and target-specific availability. Use __has_target_builtin for target-specific checks rather than __has_builtin when the actual code generation capability matters:

#ifdef __CUDA__
#if __has_target_builtin(__builtin_trap)
  __builtin_trap();
#else
  abort();
#endif
#endif

For attributes that span multiple compilation modes, allow them to be present across all relevant targets even if they only affect specific ones. This enables consistent semantic analysis and diagnostics while maintaining target-specific behavior. For example, allow sycl_external on both host and device compilations to support unified diagnostic checking.

When target validation is complex or depends on build-time configuration, prefer graceful degradation over strict validation that could fail based on build flags. Treat target specifications as authoritative at the IR level and only validate what can be reliably checked without external dependencies.


Use modern nullish operators

When dealing with potentially null or undefined values, use optional chaining (?.) and nullish coalescing (??) operators instead of verbose conditionals. These operators make code more readable, concise, and prevent null reference errors.

// Verbose and error-prone
if (object && object.property) {
  value = object.property;
} else {
  value = defaultValue;
}

// Concise and safe
value = object?.property ?? defaultValue;

In real-world code, these operators simplify common patterns:

// From discussion #1: Safely access property with fallback
innerOk(this?.ok ?? ok, args.length, ...args);

// From discussion #13: Conditional assignment with fallback
this.secureOptions = secureOptions || undefined;

// From discussion #15: Lazy loading with nullish assignment
inspect ??= require('util').inspect;
return inspect;

These operators are particularly valuable for:

Remember that optional chaining short-circuits when a reference is nullish, while nullish coalescing only falls back when the left side is specifically null or undefined (not other falsy values like 0 or '').


Initialize default values

Always initialize class attributes with default values to prevent AttributeError exceptions when accessing potentially undefined values. Use defensive coding patterns:

  1. Set default values in __init__() for critical attributes
  2. Initialize attributes with safe fallback values in exception handlers
  3. Use defensive checks (e.g., hasattr()) before accessing attributes that might be undefined

Example:

def update(self):
    # Initialize with defaults before try block
    self.len = 0
    self.cap = 0
    self.ptr = None
    self.elem_type = None
    self.elem_size = 0
    
    try:
        self.ptr = self.value.GetChildMemberWithName('ptr')
        self.len = self.value.GetChildMemberWithName('len').unsigned
        self.cap = self.value.GetChildMemberWithName('cap').unsigned
        self.elem_type = self.ptr.type.GetPointeeType()
        self.elem_size = self.elem_type.size
    except:
        # Already have default values
        pass
        
def get_child_at_index(self, index):
    if index not in range(self.len): 
        return None
    try: 
        if not hasattr(self, 'ptr') or not hasattr(self, 'elem_size') or not hasattr(self, 'elem_type'):
            return None
        return self.ptr.CreateChildAtOffset('[%d]' % index, index * self.elem_size, self.elem_type)
    except: 
        return None

This pattern ensures your code is resilient to initialization failures and prevents null reference issues in dependent methods.


Synchronize configuration files

Ensure all related configuration files are updated consistently when making changes to dependencies, versions, or other configuration settings. When updating a dependency version in one file (e.g., package.json), ensure that all related files (e.g., lockfiles, version specifications) are also updated to maintain consistency. This prevents subtle integration issues and build failures.

Example:

// When updating package.json
{
  "dependencies": {
    "browser-ui-test": "0.21.1",  // Updated from 0.20.6
    // other dependencies...
  }
}

// Also update related files like browser-ui-test.version to match

For build configurations, consider separating build artifacts from source code by copying configuration files to the build directory and running commands from there. This maintains source directory immutability during builds.


Thread-safe resource management patterns

Ensure thread-safe access to shared resources while following proper resource management patterns. When implementing concurrent operations:

  1. Prefer worker threads over process spawning for parallel tasks
  2. Use instance-based implementations instead of static instances for thread-safe access
  3. Implement proper resource management using smart pointers and RAII patterns
  4. Carefully manage object ownership across thread boundaries

Example of proper thread-safe resource management:

// Instead of static instance
class NetworkResourceManager {
 private:
  std::mutex mutex_;
  std::unordered_map<std::string, std::shared_ptr<Resource>> resources_;
 
 public:
  void Put(const std::string& url, std::unique_ptr<Resource> data) {
    std::lock_guard<std::mutex> lock(mutex_);
    resources_[url] = std::move(data);
  }
  
  // For parallel processing
  void ProcessResource(const std::string& url) {
    auto worker = std::make_unique<WorkerThread>([this, url]() {
      // Thread-safe resource access
      std::lock_guard<std::mutex> lock(mutex_);
      if (auto it = resources_.find(url); it != resources_.end()) {
        it->second->process();
      }
    });
    worker->start();
  }
};

This pattern ensures:


Contextual error messages

Error messages should provide specific context about the error and guide users toward solutions. When reporting syntax errors like mismatched delimiters, include both the location of the error and references to related code elements to help users quickly identify the problem.

For parser errors, prefer specific diagnostics over generic ones. Instead of vague messages like “mismatched closing delimiter”, use more helpful guidance such as “missing open ( for this delimiter” with clear indication of where both delimiters are located.

Example:

error: missing open `(` for a `)` delimiter
  --> file.rs:3:1
   |
LL | pub fn foo(x: i64) -> i64 {
   |                           - the last matched opening delimiter
LL |     x.abs)
   |          ^ missing open `(` for this delimiter

This approach helps users quickly understand the scope of the error and reduces debugging time by pinpointing both the error and its context. Remember that the goal of error messages is not just to report problems but to guide users toward solutions.


Never swallow errors

Always ensure errors are properly surfaced rather than silently ignored. Silent error handling can lead to confusing behavior where features fail without any indication of what went wrong, making debugging difficult or impossible.

There are several ways to properly handle errors instead of silently swallowing them:

  1. Use logging channels to surface errors that aren’t immediately user-facing: ```typescript // Bad try { await this.findTestFiles(); } catch (error) { // Silent error handling }

// Good try { await this.findTestFiles(); } catch (error) { this.outputChannel.appendLine(Test discovery failed: ${error.message}); }


2. Maintain important assertions that validate input requirements:
```typescript
// Bad
export function isReadableStreamLocked(stream) {
  // $assert($isReadableStream(stream));  // Don't remove assertions!
}

// Good
export function isReadableStreamLocked(stream) {
  $assert($isReadableStream(stream));
}
  1. Check return values from critical operations that may fail: ```typescript // Bad handle.init(initParamsArray, pledgedSrcSize, writeState, processCallback);

// Good const initResult = handle.init(initParamsArray, pledgedSrcSize, writeState, processCallback); if (initResult !== 0) { throw new Error(Initialization failed with code ${initResult}); }


When errors are properly surfaced, developers can identify and fix issues more efficiently, leading to more robust and maintainable code.

---

## Respect existing configurations

<!-- source: oven-sh/bun | topic: Configurations | language: TypeScript | updated: 2025-07-10 -->

When integrating with external services or tools, design your configuration options to respect users' existing environment settings rather than overriding them with hardcoded defaults. This ensures your tool works seamlessly within various environments and avoids disrupting users' workflows.

Key practices:
1. Use environment-aware defaults that fall back to system conventions when no explicit value is provided
2. Apply configuration parameters consistently throughout the codebase
3. Use correct references to external resources

**Example 1:** For AWS CLI integration, omit the `--profile` flag when no profile is specified rather than hardcoding "default":

```typescript
// ❌ Bad: Hardcoding a default profile name
profile: Flags.string({
  description: "The AWS CLI profile to use.",
  multiple: false,
  default: "default", // Forces "default" even if user has AWS_PROFILE set
})

// ✅ Good: Make profile optional and apply it conditionally
profile: Flags.string({
  description: "The AWS CLI profile to use.",
  multiple: false,
  required: false,
})

// Then in code:
if (profile) {
  // Apply profile parameter consistently to all AWS commands
  this.#aws(["command", "--profile", profile]);
}

Example 2: Ensure external resource references are correct and complete:

//  Bad: Incomplete GitHub issues URL
"bugs": "https://github.com/oven-sh/issues"

//  Good: Complete URL to the repository's issues page
"bugs": "https://github.com/oven-sh/bun/issues"

Following these practices helps users integrate your tool with their existing environment without unexpected side effects or configuration conflicts.


Verify assertions properly

Ensure test assertions correctly validate the intended behavior by:

  1. Awaiting promise assertions when testing async code: ```javascript // PROBLEMATIC: Test may pass even if promise never resolves expect(promise).resolves.toBe(expectedValue);

// CORRECT: Properly wait for and validate promise resolution await expect(promise).resolves.toBe(expectedValue); // OR return expect(promise).resolves.toBe(expectedValue);


2. **Comparing appropriate values** when testing transformations:
```javascript
// PROBLEMATIC: Comparing decompressed output to compressed input
expect(decompressedBuffer).toEqual(compressedBuffer);

// CORRECT: Verifying the transformation worked as expected
expect(decompressedBuffer.toString()).toEqual(originalInputString);

Understanding your testing framework’s behavior is important - some frameworks may handle certain assertions differently (e.g., in some environments expect(...).resolves might implicitly await).

Tests should validate that functions behave as expected, not just that they run without errors. Always ask: “Is this assertion actually testing what I intend to test?”


Path comparison precision

When implementing file path matching or exclusion algorithms, use precise comparison techniques that respect directory boundaries rather than simple string operations. Naïve prefix matching using startsWith() can lead to unexpected behavior by accidentally matching unrelated paths that share prefixes.

For example, with an exclude pattern of 'foo', a simple implementation might exclude both 'foo/bar' (intended) and 'foobar' (likely unintended).

Instead, implement directory-aware comparisons:

// Incorrect - too inclusive
if (excludeGlobs?.some(([glob, p]) => glob.match(ent) || ent.startsWith(p)))

// Correct - respects directory boundaries
if (excludeGlobs?.some(([glob, p]) => glob.match(ent) || p === ent || ent.startsWith(p + path.sep)))

For complex pattern matching like glob implementations, consider both exact matches and proper directory hierarchy to ensure your algorithm behaves predictably across edge cases, especially when handling wildcards or path separators that may differ between operating systems.


Validate workflow files

Ensure all CI/CD workflow configuration files are validated for accuracy and consistency. Small errors in workflow files can prevent automation from triggering correctly or cause unexpected behavior. Pay special attention to:

  1. File extension consistency between actual files and path triggers
  2. Correct property names according to the platform’s documentation

Examples of common issues:

Incorrect path trigger (file extension mismatch):

on:
  pull_request:
    paths:
      - ".github/workflows/bun-release-test.yml" # Wrong: actual file has .yaml extension

Correct path trigger:

on:
  pull_request:
    paths:
      - ".github/workflows/bun-release-test.yaml" # Matches the actual file extension

Incorrect property name:

- name: Create Pull Request
  uses: peter-evans/create-pull-request@v3
  with:
    lables: "automation" # Wrong: 'lables' is a typo

Correct property name:

- name: Create Pull Request
  uses: peter-evans/create-pull-request@v3
  with:
    labels: "automation" # Correct property name

Consider implementing a validation step in your workflow development process to catch these issues early.


prefer efficient built-ins

When multiple built-in methods can accomplish the same algorithmic task, prefer the single comprehensive method over combining multiple operations. This reduces computational overhead, simplifies code logic, and often provides better performance characteristics.

For example, instead of combining separate property retrieval methods:

// Less efficient - two separate operations
let allProperties = [
  ...Object.getOwnPropertyNames(obj),
  ...Object.getOwnPropertySymbols(obj),
];

// More efficient - single comprehensive method
let allProperties = Reflect.ownKeys(obj);

Similarly, use direct comparison methods when they handle edge cases automatically:

// Manual edge case handling
return NumberIsNaN(a) && NumberIsNaN(b) || a === b;

// Built-in handles all cases efficiently
return Object.is(a, b);

This approach improves algorithmic efficiency by leveraging optimized native implementations and reduces the cognitive load of understanding complex conditional logic.


Maintain consistent style

Maintain consistent style patterns throughout the codebase to improve readability, reduce maintenance overhead, and prevent errors. Key areas to focus on:

  1. Use consistent struct declarations: For top-level structs, prefer:
    const Installer = @This();
    

    instead of:

    pub const Installer = struct {
    
  2. Eliminate redundancies: Remove duplicate declarations such as repeated flags, option definitions, or multiple type declarations.
    // Bad - duplicates in options list
    GLOBAL_OPTIONS[LONG_OPTIONS]="--extension-order --jsx-factory --jsx-fragment --extension-order --jsx-factory --jsx-fragment"
       
    // Good - no duplicates
    GLOBAL_OPTIONS[LONG_OPTIONS]="--extension-order --jsx-factory --jsx-fragment"
    
  3. Maintain consistent formatting: Ensure proper spacing, consistent namespace qualifiers, and appropriate control structures.
    // Bad - inconsistent namespace qualification
    if (comptime Environment.debug_checks) {
       
    // Good - consistent qualification
    if (comptime bun.Environment.debug_checks) {
    
  4. Use appropriate control structures: Choose the most readable structure for the logic being expressed.
    // Consider switch statements for multiple conditions
    fn isValidRedirectStatus(status: u16) bool {
        return switch (status) {
            301, 302, 303, 307, 308 => true,
            else => false,
        };
    }
    

Consistent style makes code easier to read, review, and maintain for the entire team.


Use memory pools

Reuse memory with buffer pools for temporary allocations instead of creating new buffers each time. This reduces memory allocation overhead and improves performance, especially for operations that frequently need temporary storage.

// Instead of this:
var link_target_buf: bun.PathBuffer = undefined;

// Use this:
const link_target_buf = bun.PathBufferPool.get();
defer bun.PathBufferPool.put(link_target_buf);

Using memory pools for buffers that are only needed temporarily during a function call helps avoid expensive allocation and deallocation cycles. The pattern of getting from a pool and deferring the return ensures the memory is properly recycled without leaking, even if the function returns early through different code paths.


avoid implementation detail leakage

APIs should provide clean abstraction boundaries without exposing internal implementation details or creating unwanted dependencies between modules. When designing public interfaces, carefully consider what needs to be exposed versus what can remain internal.

Common violations include:

Instead, prefer:

Example of good abstraction:

// Instead of exposing complex internal resolver
pub fn op_require_fallback_resolve<T: NodeRequireLoader>(
  state: &mut OpState,
  request: String,
  parent_filename: Option<String>,
) -> Result<String, RequireError>

// Expose simpler options-based API
#[derive(Debug, Default, Clone)]
pub struct ConditionOptions {
  pub conditions: Vec<Cow<'static, str>>,
  pub import_conditions_override: Option<Vec<Cow<'static, str>>>,
}

This approach reduces coupling, improves maintainability, and provides cleaner interfaces for API consumers.


Validate operation permissions

Ensure appropriate permission checks are implemented before performing security-sensitive operations that access files, networks, or system resources. Different operation types require different permission validations, and the timing of these checks matters for security.

Key considerations:

Example implementation:

#[op2]
pub fn op_node_database_backup(
  #[cppgc] source_db: &DatabaseSync,
  #[string] path: String,
  #[serde] options: Option<BackupOptions>,
) -> std::result::Result<(), SqliteError> {
  // Add write permission checks here for the target path
  // Since path can have different forms, check permissions accordingly
  let src_conn_ref = source_db.conn.borrow();
  // ... rest of implementation
}

Always verify that permission checks align with the security model of the operation and consider whether the check should occur at operation time or resource creation time.


Maintain portable config values

Always use portable, environment-agnostic values in configuration files. Avoid hardcoded absolute paths, system-specific values, or mismatched feature flags. Instead:

  1. Use relative paths and environment variables
  2. Ensure error messages accurately reflect configuration conditions
  3. Use correct and specific feature flags for analytics and tracking

Example - Instead of:

-Wl,-non_global_symbols_no_strip_list,/Users/username/project/src/symbols.txt
bun.Analytics.Features.lockfile_migration_from_package_lock += 1  # for pnpm migration

Use:

-Wl,-non_global_symbols_no_strip_list,${CMAKE_SOURCE_DIR}/src/symbols.txt
bun.Analytics.Features.lockfile_migration_from_pnpm_lock += 1  # specific to migration type

This ensures configurations work consistently across different environments and accurately reflect system behavior.


Hide implementation details

When designing APIs, carefully consider which elements of your implementation become part of the public interface. Avoid exposing internal types, naming patterns, and implementation details that could confuse API consumers or lock you into supporting implementation details as part of your contract.

For example, instead of exposing internal types in public modules:

// Avoid this:
declare module "net" {
  type SocketHandleData = { self: Socket; req?: object };
  // Makes it look like a standard Node.js type
}

// Prefer this:
// Option 1: Move to your own namespace
declare module "bun" {
  namespace internal {
    type SocketHandleData = { self: Socket; req?: object };
  }
}

// Option 2: Inline the type where needed
interface Socket {
  _handle: { self: Socket; req?: object };
}

When dependencies might be deprecated or change, consider vendoring your own implementation rather than relying on shared code that might evolve independently:

// Instead of depending on potentially changing shared implementations:
resultBindings.push(
  `    pub inline fn ${formatZigName(fn.name)}(...) {`,
  `        return bun.JSC.${callName}(...);`, // Depends on external implementation
  `    }`,
);

Clean all error paths

Ensure all error paths properly clean up resources and handle errors appropriately. This includes:

  1. Using errdefer for cleanup when allocating resources
  2. Checking all possible error paths
  3. Properly freeing resources in each error case
  4. Ensuring consistent error propagation

Example of proper resource cleanup:

// Bad - potential resource leak
const data = allocator.alloc(u8, size);
const result = processData(data); // May fail
if (result == .err) return error.ProcessFailed;

// Good - cleanup guaranteed on error
const data = try allocator.alloc(u8, size);
errdefer allocator.free(data);
const result = try processData(data);

// For multiple resources
const key = try allocator.dupe(u8, input_key);
errdefer allocator.free(key);
try map.put(allocator, key, value);

Common issues to watch for:

This practice helps prevent resource leaks and ensures robust error handling across all execution paths.


Validate network request parameters

Always validate and sanitize all network request parameters to prevent injection attacks. This includes:

  1. URL validation: Consider restricting URLs to trusted origins only (e.g., localhost/loopback interfaces) to reduce the attack surface.
// Bad - No validation on URL source
fetch(url, { signal: controller.signal })

// Better - Restrict URLs to trusted origins
const urlObj = new URL(url);
if (!['localhost', '127.0.0.1', '::1'].includes(urlObj.hostname)) {
  throw new Error('URL must be a loopback address for security reasons');
}
fetch(url, { signal: controller.signal })
  1. Header/payload sanitization: Validate inputs used in constructing HTTP requests to prevent request smuggling attacks. Check for control characters like \r and \n that could manipulate request boundaries.
// Bad - No validation against control characters
let payload = `CONNECT ${requestHost}:${reqOptions.port} HTTP/1.1\r\n`;
if (auth) {
  payload += `proxy-authorization: ${auth}\r\n`;
}

// Better - Validate parameters to prevent request smuggling
function validateNoControlChars(value, name) {
  if (/[\r\n]/.test(value)) {
    throw new Error(`${name} contains invalid control characters`);
  }
  return value;
}
let payload = `CONNECT ${validateNoControlChars(requestHost, 'requestHost')}:${validateNoControlChars(reqOptions.port, 'port')} HTTP/1.1\r\n`;
if (auth) {
  payload += `proxy-authorization: ${validateNoControlChars(auth, 'auth')}\r\n`;
}

These practices help prevent server-side request forgery (SSRF), HTTP request smuggling, and other injection-based attacks.


informative error messages

Error messages should be specific, contextual, and include relevant information to aid debugging and user understanding. Avoid generic messages like “invalid syntax” in favor of descriptive explanations that specify what was expected, what was found, and include the problematic data when helpful.

Key practices:

Example transformation:

// Before: Generic and unhelpful
if ch > 9 {
    return error('strconv.atoi: parsing "${s}": invalid syntax')
}

// After: Specific and informative  
if ch > 9 {
    return error('strconv.atoi: parsing "${s}": character `${s[i]}` is not a valid digit')
}

This approach significantly improves the debugging experience and helps users understand exactly what went wrong and how to fix it.


Use appropriate metric types

When instrumenting applications with metrics, choose the correct metric type based on what you’re measuring to ensure accurate and useful observability data:

  1. Use monotonic (increase-only) counters for events or cumulative quantities to ensure compatibility with systems like Prometheus that expect strictly increasing values.

  2. Use histograms or distributions for durations rather than simple counters, as durations represent a distribution of values.

  3. Consider specialized gauge types for specific use cases, such as high-water mark gauges for tracking peak values:

// GOOD: Using a histogram/distribution for request durations
const requestDuration = createHistogram('api.request.duration.ms');
function handleRequest(req, res) {
  const startTime = performance.now();
  // Process request...
  requestDuration.record(performance.now() - startTime);
}

// GOOD: Using a monotonic counter for counting events
const apiCalls = createCounter('api.calls.total');
function handleRequest(req, res) {
  apiCalls.increment();
  // Process request...
}

// GOOD: Using a high-water mark gauge for tracking peak memory usage
const memoryHighWaterMark = createHighWaterMarkGauge('memory.peak.bytes');
setInterval(() => {
  memoryHighWaterMark.update(process.memoryUsage().heapUsed);
}, 1000);

Choosing the right metric type ensures that monitoring systems can correctly interpret and visualize your data, leading to more meaningful insights and better observability.


Descriptive identifier names

Choose clear, consistent, and accurate identifiers that precisely reflect behavior and follow established patterns. This applies to function names, method names, variable types, and enum values.

For functions and methods:

For types and constants:

Consistent and precise naming reduces bugs from misinterpreting an identifier’s purpose, improves code readability, and makes integration with other libraries more intuitive.


Secure credentials handling

When handling credentials or secrets in code, avoid passing them directly through command substitution or template literals in shell commands, as this can lead to security vulnerabilities. Instead, write sensitive data to temporary files with restricted permissions, use those files for operations requiring credentials, and ensure proper cleanup afterward.

Example:

// Insecure way - potential command injection or exposure risk
await Bun.$`bash -c 'age -d -i <(echo "$AGE_CORES_IDENTITY")' < ${cores} | tar -zxvC ${dir}`;

// Secure way - controlled lifecycle for sensitive data
const identityFile = join(dir, "identity.key");
await Bun.write(identityFile, process.env.AGE_CORES_IDENTITY);
await Bun.chmod(identityFile, 0o600); // Restrict file permissions
await Bun.$`age -d -i ${identityFile} < ${cores} | tar -zxvC ${dir}`;
await Bun.rm(identityFile); // Clean up the sensitive file

This approach prevents credential leakage through command history, process lists, or insecure file permissions, and ensures sensitive data is promptly removed after use.


Optimize allocation hotspots

Identify and optimize object allocation in performance-critical paths by applying appropriate allocation strategies based on usage patterns. For frequently accessed objects, consider reusing instances rather than creating new ones. For short-lived objects in hot code paths, evaluate whether the JIT can optimize allocations away or if explicit object pooling/caching is needed.

For example, instead of creating new handler instances for each channel:

// Inefficient - creates new instance per channel
channel.pipeline().addLast(new MyHandler());

// Efficient - reuses single instance across channels
private static final MyHandler SHARED_HANDLER = new MyHandler();
// Add @Sharable annotation to handler class
channel.pipeline().addLast(SHARED_HANDLER);

For frequent operations, consider thread-local caching when appropriate:

// Cache event objects per thread for high-frequency operations
private static final ThreadLocal<MyEvent> EVENT_CACHE = 
    ThreadLocal.withInitial(MyEvent::new);

public void onHighFrequencyOperation() {
    MyEvent event = EVENT_CACHE.get();
    event.reset(); // Prepare for reuse
    // Use event...
}

When dealing with buffer management, ensure proper release and consider zero-copy approaches:

ByteBuf buffer = null;
try {
    buffer = allocator.directBuffer(size);
    // Use buffer...
} finally {
    if (buffer != null) {
        buffer.release(); // Ensure proper release
    }
}

For frequently used resource handles like file descriptors, consider caching and reuse:

// Instead of creating new pipes for each operation
if (pipe == null) {
    pipe = FileDescriptor.pipe();
}

Measure performance impact of allocation strategies with benchmarks before committing to complex optimization patterns, as JIT may already optimize simple allocation patterns in some cases.


Release locks before waking

In concurrent systems, it’s critical to release locks before performing operations that might trigger reentrancy or block the current thread, such as waking waiters. Holding locks while waking tasks can lead to deadlocks if the awakened code attempts to acquire the same lock.

This pattern applies to any concurrency primitive that maintains a list of waiters, such as semaphores, notification systems, or task schedulers.

// PROBLEMATIC: Holding lock while waking waiters
let mut lock = self.waiters.lock();
while let Some(waker) = lock.waiters.pop() {
    waker.wake(); // Deadlock risk if woken task tries to acquire the same lock
}

Instead, collect the wakers to wake while holding the lock, then drop the lock before waking them:

let wakers_to_wake = {
    let mut lock = self.waiters.lock();
    std::mem::take(&mut lock.waiters) // Take ownership of waiters
    // Lock is released at the end of this block
};

// Wake waiters after releasing the lock
for waker in wakers_to_wake {
    waker.wake();
}

For batch operations, you can use a helper structure like WakeList to avoid waking too many waiters at once:

let mut waker_list = WakeList::new();
let mut lock = self.mutex.lock();

while let Some(waker) = process_next_waiter(&mut lock) {
    waker_list.push(waker);
    
    if !waker_list.can_push() {
        // Wake a batch of waiters with the lock temporarily dropped
        drop(lock);
        waker_list.wake_all();
        
        // Reacquire the lock to continue processing
        lock = self.mutex.lock();
    }
}

// Don't forget to wake remaining waiters
drop(lock);
waker_list.wake_all();

By following this pattern, you maintain system liveness and avoid deadlocks in concurrent code.


Descriptive function names

Function and method names should precisely describe their purpose and behavior. Choose names that explicitly communicate what the function does, including any special conditions or behaviors.

Key guidelines:

Example:

// ❌ Poor naming - ambiguous about purpose and behavior
function setup(instance, memory) {
  // Implementation
}

// ✅ Better naming - clearly describes what's being set up
function setupBindings(instance, { memory = instance.exports.memory } = {}) {
  // Implementation
}

// ❌ Poor naming - doesn't indicate conditional behavior
const emitDeprecationWarning = getDeprecationWarningEmitter();

// ✅ Better naming - indicates the warning is conditional
const maybeEmitDeprecationWarning = getDeprecationWarningEmitter();

Control cache lifecycle

Design cache systems so that higher-level components control when cache entries are invalidated or cleaned up, rather than having cache operations happen automatically at lower levels. This allows callers to make informed decisions about cache lifecycle based on their broader context and requirements.

Lower-level components should provide cache management methods but not automatically invoke them. Instead, let the calling code decide the optimal timing for cache operations based on request boundaries, configuration changes, or other application-specific events.

Example of problematic automatic cleanup:

// Don't do this - automatic cleanup removes caller control
.map_err(JsErrorBox::from_err)?;
self.parsed_source_cache.free(&specifier); // Automatic cleanup

Better approach - let caller control:

// Provide cleanup methods but let caller decide when to use them
impl CachedProvider {
    pub fn clear_cache(&self) { /* cleanup logic */ }
}

// Caller decides optimal timing (e.g., after request completion)
provider.process_request()?;
provider.clear_cache(); // Controlled by caller

This separation of concerns allows for more flexible caching strategies, such as keeping long-lived services with short-lived caches, and enables smarter invalidation timing that considers the broader application context.


Explain non-obvious decisions

When code contains non-obvious parameter choices, conditional logic, or unexpected implementation changes, add comments explaining the reasoning behind these decisions. This helps other developers understand the context and prevents confusion during code reviews.

Key scenarios requiring explanation:

Example:

// Force dynamic loading to true because static analysis 
// cannot determine module type at compile time
.load_asset(&specifier, true, requested_module_type)

if !skip_graph_roots_validation {
  // Skip validation when called from dynamic imports where
  // root validation has already been performed upstream
  self.graph_roots_valid(graph, roots, allow_unknown_media_types)?;
}

The goal is to make the code self-documenting so that future maintainers can understand not just what the code does, but why specific decisions were made.


Match API conventions

Ensure API implementations match established conventions and reference implementations to maintain compatibility and predictability. When implementing APIs that parallel existing systems (like Node.js APIs or REST services), follow their error codes, response formats, and naming conventions precisely.

For error handling, return the same error types as reference implementations:

// INCORRECT: Using mismatched error type
if (array_buffer.typed_array_type != .ArrayBuffer) {
    return env.setLastError(.arraybuffer_expected); 
}

// CORRECT: Matching Node.js convention
if (array_buffer.typed_array_type != .ArrayBuffer) {
    return env.setLastError(.invalid_arg);
}

For memory management in API responses, use memory-safe methods:

// INCORRECT: Potential memory leak
deletedObject.put(globalObject, JSC.ZigString.static("Key"), bun.String.init(item.key).toJS(globalObject));

// CORRECT: Memory-safe alternative
deletedObject.put(globalObject, JSC.ZigString.static("Key"), bun.String.createUTF8ForJS(globalObject, item.key));

Consider API property naming and response structure consistency to ensure your implementation is compatible with expected conventions, while avoiding unintended behaviors and resource leaks.


Optimize for readability

Write code that clearly communicates intent by using appropriate naming and formatting techniques. Improve readability by:

  1. Replacing magic numbers and string literals with named constants: ```csharp // Instead of: if (valueType.Module == SystemModule && valueType.Name.StartsWith(“ValueTuple`”, StringComparison.OrdinalIgnoreCase))

// Prefer: private const string ValueTuplePrefix = “ValueTuple`”; if (valueType.Module == SystemModule && valueType.Name.StartsWith(ValueTuplePrefix, StringComparison.OrdinalIgnoreCase))


2. Using explicit types instead of `var` when the type isn't obvious:
```csharp
// Instead of:
var relativePathToSpec = GetFilteredFileSpecs(fileSpecs);

// Prefer:
Dictionary<string, FileSpec> relativePathToSpec = GetFilteredFileSpecs(fileSpecs);
  1. Using standard language patterns like Array.Empty<byte>() over raw literals: ```csharp // Instead of: SHA256.Create().ComputeHash([])

// Prefer: SHA256.Create().ComputeHash(Array.Empty())


4. Using pattern matching for null checks:
```csharp
// Instead of:
if (m_getterMethod != null && m_getterMethod.IsVirtual)

// Prefer:
if (m_getterMethod is not null && m_getterMethod.IsVirtual)
  1. Adding parentheses to clarify operator precedence in complex conditionals: ```csharp // Instead of: bool taken = (opcode is ILOpcode.brtrue or ILOpcode.brtrue_s && val.Value != 0) || (opcode is ILOpcode.brfalse or ILOpcode.brfalse_s && val.Value == 0);

// Prefer: bool taken = ((opcode is ILOpcode.brtrue or ILOpcode.brtrue_s) && val.Value != 0) || ((opcode is ILOpcode.brfalse or ILOpcode.brfalse_s) && val.Value == 0);


6. Using operators for more concise code when available:
```csharp
// Instead of:
Vector256<int> result = Vector256.And(Vector256.LoadUnsafe(ref left, i), Vector256.LoadUnsafe(ref right, i));

// Prefer:
Vector256<int> result = Vector256.LoadUnsafe(ref left, i) & Vector256.LoadUnsafe(ref right, i);

Specific exceptions with context

Always throw the most specific exception type appropriate for the error condition and include contextual information in the error message. This helps developers quickly identify and fix issues.

Key practices:

  1. Use derived exception types instead of base types (e.g., PlatformNotSupportedException instead of NotSupportedException)
  2. For cancellation scenarios, accept both OperationCanceledException and TaskCanceledException
  3. Include relevant context in exception messages, avoiding generic “unknown error” messages
  4. Test exception messages to ensure they provide meaningful information

Example:

// Bad
throw new Exception("Operation failed");
// or
throw new CryptographicException("Unknown error (0xc100000d)");

// Good
throw new PlatformNotSupportedException(
    SR.Format(SR.ProcessStartSingleFeatureNotSupported, nameof(feature)));
// or
await Assert.ThrowsAnyAsync<OperationCanceledException>(() => 
    operation.ExecuteAsync(cancellationToken));

Validate nullability explicitly

Always validate null or undefined values before using them to prevent crashes and undefined behavior. When implementing null-handling code, consider these principles:

  1. Use nullable types (like ?*Type in Zig) when a value might be null, rather than assuming non-nullability:
// BAD - Compiler will optimize out this check
fn requestTermination(handle: *WebWorkerLifecycleHandle) void {
    if (@intFromPtr(handle) == 0) return;
    // ...
}

// GOOD - Explicitly mark as nullable
fn requestTermination(handle: ?*WebWorkerLifecycleHandle) void {
    if (handle == null) return;
    // ...
}
  1. Never default-initialize struct fields with undefined unless they’re guaranteed to be assigned before use:
// BAD - Creates potential undefined behavior
struct {
    last_modified_buffer: [32]u8 = undefined,
}

// GOOD - Safe initialization
struct {
    last_modified_buffer: [32]u8 = [_]u8{0} ** 32,
}
  1. Always initialize boolean flags and state fields in constructors:
// BAD - Uninitialized fields
return bun.new(FileRoute, .{
    .ref_count = .init(),
    .server = opts.server,
    .blob = blob,
    .headers = headers,
    .status_code = opts.status_code,
    // Missing has_last_modified_header initialization
});

// GOOD - All fields explicitly initialized
return bun.new(FileRoute, .{
    .ref_count = .init(),
    .server = opts.server,
    .blob = blob,
    .headers = headers,
    .status_code = opts.status_code,
    .has_last_modified_header = headers.get("last-modified") != null,
    .has_content_length_header = headers.get("content-length") != null,
});
  1. Respect API contracts regarding null handling. When wrapping libraries like V8, understand their null semantics:
// DANGEROUS - Will crash if MaybeLocal is empty
Local<T> ToLocalChecked() const {
    return m_local;
}

// SAFE - Explicit check before dereferencing
bool ToLocal(Local<T>* out) const {
    if (IsEmpty()) {
        return false;
    }
    *out = m_local;
    return true;
}

Design error handling carefully

When implementing error handling, balance between propagation and recovery. Design error types to preserve context while providing users with meaningful ways to handle failure.

For error propagation:

For recovery paths:

// Poor: May panic unexpectedly and loses context
let pos = std.stream_position().unwrap();

// Better: Provides fallback and preserves error context
let pos = std.stream_position().unwrap_or(0);

// Poor: Error type lacks context and proper trait implementation
struct MyError(());

// Better: Full featured error with context preservation
struct MyError<T> {
    inner: T,
    cause: io::Error,
}

impl<T> std::error::Error for MyError<T> {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        Some(&self.cause)
    }
}

// Even in examples, show proper error handling
// Poor: Ignores errors
let _ = compress_data(reader).await;

// Better: Shows proper error handling
compress_data(reader).await?;

Follow import style

Tokio projects follow specific import conventions for consistency and readability. Adhere to these guidelines:

  1. Use separate use statements for different modules
  2. Group imports from the same module with braces
  3. Don’t use nested/grouped braces for imports from different modules
  4. Place safety comments directly before unsafe blocks
// Incorrect
use std::{
    future::Future,
    os::unix::io::{AsRawFd, RawFd},
};

// Correct
use std::future::Future;
use std::os::unix::io::{AsRawFd, RawFd};

// Incorrect - safety comment is too far from unsafe block
let filled = read.filled().len();
// Safety: This is guaranteed by invariants...
unsafe { pin.rd.advance_mut(filled) };

// Correct
// Safety: This is guaranteed by invariants...
unsafe { pin.rd.advance_mut(read.filled().len()) };

Following consistent import style and proper safety comment placement improves code readability and maintainability across the project.


Use appropriate synchronization mechanisms

Select and implement synchronization primitives that match your concurrency requirements and avoid unsafe patterns. Consider the number of consumers, thread safety requirements, and proper initialization order.

Key guidelines:

Example of correct async flag implementation:

impl AsyncFlag {
  pub fn raise(&self) {
    self.0.add_permits(1);  // Preserve semaphore state
  }

  pub async fn wait_raised(&self) {
    drop(self.0.acquire().await);  // Proper waiting mechanism
  }
}

Avoid unsafe patterns like direct environment modification in multi-threaded contexts, and ensure synchronization primitives maintain proper ordering and state consistency throughout their lifecycle.


Avoid busy waiting

When implementing concurrent code that waits for conditions to be met, avoid busy-wait loops that continuously consume CPU resources. Busy-waiting wastes processing power, reduces overall system performance, and can increase power consumption.

Instead, use proper synchronization primitives or give up execution time:

// Bad practice - continuously consumes CPU
bool receivedSignal = false;
while (!receivedSignal) { }

// Better option 1 - use synchronization primitives
var signal = new ManualResetEventSlim(false);
signal.Wait(timeoutMs); // Efficiently waits without consuming CPU
// In signal handler: signal.Set();

// Better option 2 - at minimum, yield execution time
while (!receivedSignal) 
{
    Thread.Sleep(1); // Or Thread.Yield()
}

For more complex scenarios, consider higher-level synchronization constructs like SemaphoreSlim, AutoResetEvent, or async/await patterns with TaskCompletionSource. These approaches not only improve performance but also make your concurrent code more maintainable and less error-prone.


Maintainable test structure

Write tests that are maintainable, self-documenting, and that promote good testing practices:

  1. Use proper assertion mechanisms: Prefer modern assertion patterns over legacy approaches. Use built-in assertion methods that clearly indicate what is being tested.
    // Bad: Custom test logic with manual exception checking
    bool canceled = false;
    try {
        await GetAsync(useVersion, testAsync, uri, cts.Token);
    } catch (TaskCanceledException) {
        canceled = true;
    }
    Assert.True(canceled);
       
    // Good: Use built-in assertion methods
    await Assert.ThrowsAsync<TaskCanceledException>(() => 
        GetAsync(useVersion, testAsync, uri, cts.Token));
    
  2. Create reusable test helpers for common operations instead of duplicating test code. This improves maintainability and readability while reducing the chance of inconsistencies.

  3. Use modern test patterns: Replace legacy patterns like “return 100 == success” with proper Assert-based validation that clearly communicates test expectations and failures.

  4. Remove commented-out or dead test code that doesn’t contribute to validation. Keep tests clean and focused on what’s actually being tested.

  5. Use appropriate conditional attributes to ensure tests properly convert Debug.Assert failures to test failures and run only when the tested functionality is supported.

Design flexible APIs

When designing APIs, prioritize flexibility, ergonomics, and intuitiveness to create better user experiences. APIs should accept the most general parameter types appropriate for the functionality, handle edge cases gracefully, and provide methods that align with user expectations.

Key practices:

  1. Accept general parameter types (e.g., impl Into<String> instead of String)
  2. For asynchronous operations, consider returning values directly from awaited functions
  3. Provide inspection methods that allow users to query object state
  4. Handle edge cases explicitly in your API design

Example of flexible parameter types:

// Instead of this:
pub fn name(&mut self, name: String) -> &mut Self {
    // implementation
}

// Prefer this:
pub fn name(&mut self, name: impl Into<String>) -> &mut Self {
    let name = name.into();
    // implementation
}

Example of intuitive async API design:

// Instead of requiring separate calls:
pub async fn wait(&self) {
    // implementation that just waits
}
pub fn get(&self) -> Option<&T> {
    // implementation
}

// Consider this more ergonomic design:
pub async fn wait(&self) -> &T {
    // implementation that returns the value directly
}

Example of providing inspection methods:

impl<T> Receiver<T> {
    /// Checks if this receiver is finished.
    ///
    /// Returns true if this receiver has been polled and yielded a result.
    pub fn is_finished(&self) -> bool {
        self.inner.is_none()
    }
    
    // Additional inspection methods to query other aspects of state
}

Choose appropriate error mechanisms

Use the right error handling mechanism for each scenario: exceptions for recoverable situations, assertions only for true programming bugs, and consistent error codes for API boundaries. Don’t assert unreachable for scenarios that could legitimately occur, such as in this example:

// Instead of this:
if (!BlockRange().TryGetUse(mask, &use))
{
    unreached(); // Bad: this could legitimately occur
}

// Do this:
if (BlockRange().TryGetUse(mask, &use))
{
    use.ReplaceWith(node);
}
else 
{
    node->SetUnusedValue(); // Gracefully handle the case
}

Always validate input values to prevent runtime errors like division-by-zero:

DWORD cacheSize = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_NativeToILOffsetCacheSize);
if (cacheSize < 1)
{
    cacheSize = 1; // Ensure cache size is at least 1 to prevent division-by-zero
}

For API design, use standard error reporting mechanisms rather than boolean out parameters. When throwing exceptions, select appropriate exception types that reflect the nature of the error, such as PlatformNotSupportedException for unsupported hardware features instead of failing fast with generic errors.


Preserve naming consistency

Maintain consistent naming patterns and casing across all related code entities to ensure clarity and prevent errors. This includes:

  1. Use consistent casing for technical identifiers across all occurrences (in code, documentation, and translations)
  2. When entities are conceptually related (like types and namespaces sharing the same name), ensure naming consistency is maintained across all instances
  3. When renaming an identifier, ensure all related occurrences are updated consistently

Example:

// CORRECT: Consistent casing of 'checkJs' option
// In code:
compiler.options.checkJs = true;

// In documentation:
// "Use the 'checkJs' option to get errors from JavaScript files."

// CORRECT: Consistent naming across related entities
type Foo = number;
namespace Foo {
   export type U = string;
}
export = Foo;
// When renaming 'Foo', ensure it's renamed in all three places

Inconsistent naming leads to confusion, makes code harder to maintain, and can cause runtime errors when references don’t match.


Choose appropriate containers

Select data structures based on expected collection size and usage patterns. For small collections (typically fewer than 30 elements), consider using ordered containers like std::map instead of hash-based ones like std::unordered_map. With small collections, the theoretical O(log n) vs O(1) lookup time difference becomes negligible in practice, while ordered containers avoid hash function computation overhead and potential collision handling.

// Instead of using unordered_map for small collections:
std::unordered_map<ModuleRequest, ModuleWrap*> module_requests;

// Consider using an ordered map:
std::map<ModuleRequest, ModuleWrap*> module_requests;

When working with hash-based containers, reuse precomputed hash values when available (like V8’s GetIdentityHash()) instead of recomputing hashes with std::hash. This avoids unnecessary computation and improves performance, especially for string data that might already have an identity hash from the JavaScript engine.


Normalize variable test output

When writing tests that capture output (like UI tests, stderr, or stdout), ensure you normalize any variable content that might change between runs or versions to prevent fragile tests. This includes version numbers, debug information, instruction identifiers, and other implementation details that don’t affect the functionality being tested.

For UI tests, use normalization directives:

//@ normalize-stderr: "!(dbg|noundef) ![0-9]+" -> "!$1 !N"
//@ normalize-stderr: "%[0-9]+" -> "%X"
//@ normalize-stdout: "current rust version: [0-9]+.[0-9]+.[0-9]+" -> "current rust version: #.#.#"

For complex output with potentially changing instruction ordering, consider using run-make tests with FileCheck instead of UI tests:

// In your run-make test
run(|config| {
    let filecheck = llvm_filecheck();
    filecheck
        .arg("--check-prefix=CHECK")
        .arg("--input-file=output.txt")
        .arg("expected.txt");
});

This approach ensures tests remain stable across version updates and implementation changes, reducing maintenance overhead and preventing false test failures.


Simplify code expressions

Strive for clarity by simplifying code expressions and reducing unnecessary complexity. Complex or verbose expressions decrease readability and increase the chance of errors during maintenance.

Key simplification practices:

  1. Simplify verbose expressions - Use the most direct syntax possible: ```cpp // Overly verbose: PrecodeMachineDescriptor::Init(&(&g_cdacPlatformMetadata)->precode);

// Simplified: PrecodeMachineDescriptor::Init(&g_cdacPlatformMetadata.precode);


2. **Use appropriate types** - Prefer language-native types for internal details:
```cpp
// Less appropriate for internal usage:
Volatile<BOOL> g_GCBridgeActive = FALSE;

// Better:
Volatile<bool> g_GCBridgeActive = false;
  1. Reduce nesting - Flatten nested conditions and blocks when possible: ```cpp // Highly nested and harder to follow: if (g_interpModule != NULL) { if (methodInfo->scope == g_interpModule) doInterpret = true; else doInterpret = false; }

// Flattened and clearer: bool doInterpret = false; if ((g_interpModule != NULL) && (methodInfo->scope == g_interpModule)) doInterpret = true;


4. **Use parentheses in logical expressions** per coding guidelines:
```cpp
// Incorrect:
if (ins == INS_rcl_N || ins == INS_rcr_N || ins == INS_rol_N || ins == INS_ror_N)

// Correct:
if ((ins == INS_rcl_N) || (ins == INS_rcr_N) || (ins == INS_rol_N) || (ins == INS_ror_N))
  1. Extract helper methods for repeated patterns: ```cpp // Repeated pattern: if (attr == EA_4BYTE) { GetEmitter()->emitIns_R_R_I(INS_addiw, attr, retReg, op1->GetRegNum(), 0); } else { GetEmitter()->emitIns_R_R(INS_mov, attr, retReg, op1->GetRegNum()); }

// Extract to helper: emitMoveIfZeroImmediate(retReg, op1->GetRegNum(), attr);


6. **Collapse related conditionals** into helper functions:
```cpp
// Verbose:
if (IsAVXVNNIInstruction(ins) || IsAVXVNNIINT8Instruction(ins) || IsAVXVNNIINT16Instruction(ins))

// Better:
if (IsAvxVnniFamilyInstruction(ins))

Simpler code is easier to read, test, and maintain.


Abstract traversal patterns

When implementing algorithms that operate on complex data structures (trees, graphs, dominator structures), abstract the traversal mechanism from the operation performed at each node. Use visitor patterns or callbacks to separate concerns, making algorithms more maintainable and reusable.

For example, instead of directly traversing a data structure and performing operations:

// Tightly coupled approach
void ScaleLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk)
{
    for (BasicBlock* const curBlk : BasicBlockRangeList(begBlk, endBlk))
    {
        // Direct operations on curBlk mixed with traversal logic
        if (curBlk->hasProfileWeight()) continue;
        if (curBlk->isRunRarely()) continue;
        if (!m_reachabilitySets->GetDfsTree()->Contains(curBlk)) continue;
        
        // More operations...
    }
}

Abstract the traversal pattern to separate it from node operations:

// Decoupled approach
void ScaleLoopBlocks(FlowGraphNaturalLoop* loop)
{
    loop->VisitLoopBlocks([&](BasicBlock* curBlk) -> BasicBlockVisit {
        if (curBlk->hasProfileWeight()) return BasicBlockVisit::Continue;
        if (curBlk->isRunRarely()) return BasicBlockVisit::Continue;
        
        // Operations on curBlk without traversal concerns
        
        return BasicBlockVisit::Continue;
    });
}

This approach offers several benefits:

  1. Traversal logic is centralized and maintained in one place
  2. Algorithm implementations become clearer and more focused
  3. Traversal strategies can be optimized independently
  4. Testing becomes easier with separated concerns
  5. Reuse becomes natural for similar algorithms on the same structures

Cache expensive computations

Avoid recomputing expensive operations by caching results when they will be used multiple times. This applies to method calls, property access, and static property lookups. The performance impact of repeated calculations can be significant, especially in hot code paths.

Consider these approaches:

  1. Pass computed values as parameters: When a method needs a value that is expensive to compute, calculate it once and pass it to all methods that need it.
// Instead of this:
if (type.GetClassLayout().Kind != MetadataLayoutKind.Auto) { ... }
// And later:
return type.GetClassLayout().Kind switch { ... }

// Do this:
var layout = type.GetClassLayout();
if (layout.Kind != MetadataLayoutKind.Auto) { ... }
// And later:
return layout.Kind switch { ... }
  1. Cache static or repeated property lookups: Store values from static properties or repeated lookups in local variables.
// Instead of this:
if (IsHttp3Supported() && GlobalHttpSettings.SocketsHttpHandler.AllowHttp3 && _http3Enabled) { ... }
// And later again:
if (GlobalHttpSettings.SocketsHttpHandler.AllowHttp3) { ... }

// Do this:
bool allowHttp3 = GlobalHttpSettings.SocketsHttpHandler.AllowHttp3;
if (IsHttp3Supported() && allowHttp3 && _http3Enabled) { ... }
// And later:
if (allowHttp3) { ... }
  1. Pre-allocate collections with appropriate capacity: When creating collections that will grow, initialize them with an appropriate capacity to avoid expensive resize operations.
// Instead of this:
symbolRemapping = new Dictionary<ISymbolNode, ISymbolNode>();

// Do this:
symbolRemapping = new Dictionary<ISymbolNode, ISymbolNode>(
    (int)(1.05 * (previousSymbolRemapping?.Count ?? 0)));

Caching computed values not only improves performance but also makes code more readable by reducing duplication and making dependencies explicit.


Prevent null references

Use defensive coding practices to prevent null reference exceptions by properly handling potentially null values throughout your code.

  1. Properly initialize objects instead of using default values when instantiation is needed: ```csharp // AVOID: Using default without initialization ArrayBuilder processes = default; // Could cause NullReferenceException when adding items

// PREFER: Proper instantiation ArrayBuilder processes = new ArrayBuilder();


2. **Capture and check results** of methods that might return null before using them:
```csharp
// AVOID: Potential NullReferenceException if ReadLine() returns null
while (!remoteHandle.Process.StandardOutput.ReadLine().EndsWith(message))
{
    Thread.Sleep(20);
}

// PREFER: Capture and check for null
string? line;
while ((line = remoteHandle.Process.StandardOutput.ReadLine()) != null && 
       !line.EndsWith(message))
{
    Thread.Sleep(20);
}
  1. Map null values to appropriate empty structures to maintain consistent behavior: ```csharp // AVOID: Will throw if context is null return SignData(new ReadOnlySpan(data), destination.AsSpan(), new ReadOnlySpan(context));

// PREFER: Properly handle null context return SignData(new ReadOnlySpan(data), destination.AsSpan(), context == null ? ReadOnlySpan.Empty : new ReadOnlySpan(context));


4. **Use pattern matching** for more readable and concise null checks:
```csharp
// AVOID: Traditional null check with equality operator
if (setMethod == null || !setMethod.IsPublic)

// PREFER: Modern pattern matching
if (setMethod is null || !setMethod.IsPublic)
  1. Combine conditions using pattern matching for cleaner code: ```csharp // AVOID: Multiple conditions checked separately if (changeToken is not null && changeToken is not NullChangeToken)

// PREFER: Combine related checks if (changeToken is not (null or NullChangeToken))


When adding validation in public APIs, favor the built-in helpers like `ArgumentNullException.ThrowIfNull()` over custom throw helpers for better readability and standardization.

---

## Always await promises

<!-- source: oven-sh/bun | topic: Concurrency | language: TypeScript | updated: 2025-07-01 -->

Consistently use the `await` keyword when working with Promise-returning functions to ensure proper execution flow and prevent race conditions. Missing awaits can lead to unexpected behavior where code continues execution without waiting for asynchronous operations to complete.

Common issues to watch for:
1. Built-in async functions like `Bun.sleep()` or `fetch()`
2. Custom async functions that return Promises
3. Promise-returning methods like `sink.end()` or `server.stop()`
4. Async operations within loops

```javascript
// Incorrect: Function continues executing immediately
async function processWithSleep() {
  Bun.sleep(1000); // Missing await!
  return new Response(html);
}

// Correct: Function properly pauses execution
async function processWithSleep() {
  await Bun.sleep(1000);
  return new Response(html);
}

// Incorrect: Could create race conditions
async function performOperation() {
  const res = await fetch(server.url);
  server.stop(); // Server might stop before response is processed
  expect(await res.text()).toContain("expected content");
}

// Correct: Ensures operations complete before cleanup
async function performOperation() {
  const res = await fetch(server.url);
  expect(await res.text()).toContain("expected content");
  await server.stop();
}

In loops with async operations, ensure each iteration properly awaits its results:

// Incorrect: Results might not be processed in order
for await (const params of paramGetter) {
  callRouteGenerator(type, i, layouts, pageModule, params);
}

// Correct: Each iteration waits for completion
for await (const params of paramGetter) {
  await callRouteGenerator(type, i, layouts, pageModule, params);
}

Choose descriptive names

Names should clearly convey purpose and meaning. Parameter, variable, and method names should be self-explanatory and accurately reflect their behavior and intent. Rename elements when their original name no longer captures their purpose or could lead to confusion.

For example, if a parameter indicates whether side effects can be ignored:

// Less clear
bool IsRedundantMov(instruction ins, format fmt, size_t size, operand dst, operand src, bool canSkip)

// More clear
bool IsRedundantMov(instruction ins, format fmt, size_t size, operand dst, operand src, bool canIgnoreSideEffects)

Similarly, ensure that error messages and user-facing text use precise, accurate terminology that reflects current platform realities (like changing “not a managed .dll or .exe” to “not a managed .dll” when managed .exe files aren’t relevant in modern .NET).

When variables are used across different scopes (like in lambdas), be especially attentive to naming clarity to avoid ambiguity about which variables are being referenced.


Memory ordering matters

When working with shared data in multithreaded environments, memory ordering is critical to prevent race conditions and ensure thread safety:

  1. Avoid transient incorrect states - Don’t write an incorrect value before replacing it with the correct one, as other threads may see the intermediate state:
// INCORRECT: Creates a race window where incorrect value is visible
*ppvRetAddrLocation = (void*)pfnHijackFunction;
#if defined(TARGET_ARM64)
*ppvRetAddrLocation = PacSignPtr(*ppvRetAddrLocation);
#endif

// CORRECT: Prepare final value before publishing
void* pvHijackAddr = (void*)pfnHijackFunction;
#if defined(TARGET_ARM64)
pvHijackAddr = PacSignPtr(pvHijackAddr);
#endif
*ppvRetAddrLocation = pvHijackAddr;
  1. Use atomic operations correctly - Pay careful attention to argument order in functions like InterlockedCompareExchange(destination, exchange, comparand):
// INCORRECT: Arguments in wrong order
if (versionStart != InterlockedCompareExchange(&s_stackWalkNativeToILCacheVersion, versionStart, versionStart | 1))

// CORRECT: Proper argument order
if (versionStart != InterlockedCompareExchange(&s_stackWalkNativeToILCacheVersion, versionStart | 1, versionStart))
  1. Use memory barriers when publishing shared data - Ensure supporting data is visible before publishing pointers:
// INCORRECT: May be reordered
s_stackWalkCacheSize = cacheSize;
s_stackWalkCache = newCache; // Other threads might see the pointer before size is set

// CORRECT: Memory barrier ensures proper ordering
VolatileStore(&s_stackWalkCacheSize, cacheSize);
s_stackWalkCache = newCache;

Proper memory ordering is essential for preventing subtle multithreading bugs that may only appear under high load or on specific hardware architectures.


Optimize build dependency chains

When configuring build and test processes in CI/CD pipelines, ensure proper dependency chains with clear inputs and outputs to avoid unnecessary execution steps and cross-platform failures. Use techniques like:

  1. Explicit dependencies between build targets - Define clear dependency relationships to ensure components are built in the correct order

  2. Up-to-date checks - Implement input/output dependency tracking to skip steps when source files haven’t changed

  3. Cross-platform validation - Verify that file references and environment variables work across all target platforms and architectures

For example, when setting up build targets in MSBuild:

<Target Name="ExecuteGenerateTests"
        Inputs="$(MSBuildAllProjects);$(SourceFiles)"
        Outputs="$(GeneratedTestListFile)"
        DependsOnTargets="BuildPrerequisites">
  <!-- Command that generates test files -->
</Target>

<Target Name="CompileGeneratedTests"
        BeforeTargets="BeforeCompile;CoreCompile"
        DependsOnTargets="ExecuteGenerateTests">
  <!-- Include generated test files in compilation -->
</Target>

This approach ensures that tests are only regenerated when source files change, dependencies are built in the correct order, and builds work consistently across different platforms, resulting in faster and more reliable CI/CD pipelines.


Honor API contracts

When implementing or modifying APIs, carefully preserve the historical behavior and semantic contracts of existing interfaces, even when those behaviors seem counterintuitive. This includes maintaining consistent exception throwing patterns and honoring the distinct purposes of method overloads.

For example, when implementing overloaded methods:

// Different overloads may have subtly different semantics by design
// This overload conditionally includes entries based on trimTarget being marked
public void AddExternalTypeMapEntry(string name, Type target, Type trimTarget) {
    // Only include if trimTarget is marked
    if (IsTrimTargetMarked(trimTarget)) {
        RecordTypeMapEntry(name, target);
    }
}

// While this overload is meant as an "escape hatch" with unconditional behavior
public void AddExternalTypeMapEntry(string name, Type target) {
    // Always include this entry regardless of other conditions
    RecordTypeMapEntry(name, target);
}

Similarly, maintain expected exception behaviors. If an API historically throws for certain inputs (like Sign throwing for NaN values), preserve this pattern even if it seems inconsistent with similar methods. These behaviors form part of the API’s contract that users may depend on.


Constant-time cryptographic validation

Always use constant-time comparison methods when validating cryptographic values to prevent timing side-channel attacks. Operations like comparing authentication tags, MACs, hashes, or any security-sensitive values should use dedicated APIs such as CryptographicOperations.FixedTimeEquals() rather than standard equality operators or methods.

Example:

// INSECURE: Vulnerable to timing attacks
if (header != 0xA65959A6UL)
    throw new CryptographicException();

// SECURE: Use constant-time comparison
uint err = (uint)(header) ^ 0xA65959A6U;
// Aggregate other validation results with bitwise OR
err |= pad & ~0x7;
// ...
if (err != 0)
    throw new CryptographicException();

For larger data structures or byte sequences:

// INSECURE: String equality is not constant-time
if (computedTag == expectedTag)
    return true;

// SECURE: Use crypto-specific APIs
return CryptographicOperations.FixedTimeEquals(
    computedTag.AsSpan(), 
    expectedTag.AsSpan());

This practice is especially important for operations that verify authentication tags, decrypt ciphertexts, or validate signatures, where timing differences could reveal information about secret values to attackers.


Structure conditional compilation

Use organized structural patterns for conditional compilation to improve code maintainability and readability. Avoid applying #[cfg] attributes directly to function parameters - instead wrap conditionally available data in structs that can be zero-sized when features are disabled:

// Instead of this:
fn function(
    param1: Type1,
    #[cfg(some_feature)] param2: Type2,
) {
    // ...
}

// Use this:
struct ConditionalParams {
    #[cfg(some_feature)]
    param2: Type2,
}

fn function(
    param1: Type1,
    conditional: ConditionalParams,
) {
    // ...
}

For functions with different implementations based on configuration, use macro blocks to separate complete implementations rather than conditionally compiling within function bodies:

cfg_feature! {
    fn my_function() {
        // Implementation when feature is enabled
    }
}

cfg_not_feature! {
    fn my_function() {
        // Implementation when feature is disabled
    }
}

When stabilizing features gradually, split implementations into stable and unstable parts to avoid duplication and potential divergence. Group all related unstable functions within a single configuration block. Prefer established configuration macros like cfg_coop over direct feature checks when they more accurately represent the conditions for enabling functionality.


Structural configuration approaches

When working with feature flags and conditional compilation, prefer structural approaches over scattered configuration attributes throughout your code. This creates more maintainable code and reduces the chance of bugs when features are added or removed.

For conditionally included parameters:

// AVOID: Using cfg directly on function parameters
fn spawn(
    &mut self,
    task: T,
    scheduler: S,
    id: super::Id,
    #[cfg(tokio_unstable)] spawned_at: &'static Location<'static>,
) { /* ... */ }

// PREFER: Wrapping conditional data in a struct
struct SpawnLocation {
    #[cfg(tokio_unstable)]
    location: Option<&'static Location<'static>>,
    // The struct is effectively zero-sized when the feature is disabled
}

fn spawn(
    &mut self,
    task: T,
    scheduler: S,
    id: super::Id,
    location: SpawnLocation,
) { /* ... */ }

For platform-specific implementations:

// AVOID: Scattered cfg blocks within functions
fn now() {
    #[cfg(target_family = "wasm")]
    { return None; }
    #[cfg(not(target_family = "wasm"))]
    { return Some(Instant::now()); }
}

// PREFER: Abstraction functions that handle conditional logic
fn now() -> Option<Instant> {
    if cfg!(target_family = "wasm") { None } else { Some(Instant::now()) }
}

For feature-gated functionality, prefer separate function implementations over conditionally compiled code blocks:

// AVOID: Mixed conditional blocks within function bodies
fn submit(&mut self, worker: &WorkerMetrics, mean_poll_time: u64) {
    #[cfg(tokio_unstable)]
    {
        // unstable metrics code...
    }
    // stable metrics code...
}

// PREFER: Separate implementations with a common pattern
cfg_unstable_metrics! {
    fn submit_unstable(&mut self, worker: &WorkerMetrics, mean_poll_time: u64) {
        // unstable metrics code...
    }
}

fn submit(&mut self, worker: &WorkerMetrics, mean_poll_time: u64) {
    // stable metrics code...
    #[cfg(tokio_unstable)]
    self.submit_unstable(worker, mean_poll_time);
}

Consider creating specialized macros for common conditional patterns to standardize your approach:

// For metrics that have both stable and unstable implementations
macro_rules! cfg_metrics_impl {
    ($name:ident, stable: $stable_impl:block, unstable: $unstable_impl:block) => {
        cfg_unstable_metrics! {
            fn $name(&mut self) $unstable_impl
        }
        cfg_not_unstable_metrics! {
            fn $name(&mut self) $stable_impl
        }
    }
}

These structural approaches make conditional code easier to maintain, test, and understand.


Standardize null pointer checks

Always use standard null-checking patterns like CHECK_NOT_NULL for pointer validation instead of manual null checks. This ensures consistent error handling and improves code readability. For functions that may return null objects, consider using wrapper types like MaybeLocal to properly propagate null states.

Example:

// Incorrect - manual null check
if (network_resource_manager_ == nullptr) {
  return protocol::DispatchResponse::ServerError("...");
}

// Correct - using standard macro
CHECK_NOT_NULL(network_resource_manager_);

// Correct - using MaybeLocal for nullable returns
MaybeLocal<Object> CreateObject(Isolate* isolate) {
  if (some_condition) return MaybeLocal<Object>();  // Return empty handle
  return Object::New(isolate);
}

Maintain consistent formatting

Ensure consistent formatting and organization throughout the codebase to improve readability and maintainability. This includes:

  1. Consistent spacing and alignment
    • Avoid spaces before commas or parentheses
    • Use consistent indentation and alignment within similar code blocks
    • Be explicit about whitespace rules when exceptions are needed
  2. Logical organization of related elements
    • Group related functionality together (e.g., instructions of the same type)
    • Sort lists and collections in a logical order (alphabetical, numerical, etc.)
  3. Consistent use of delimiters and separators
    • Follow project conventions for spacing around operators and separators

Examples:

Instead of inconsistent spacing in macro definitions:

#define s390_trap2(code)                S390_E(code, 0x01ff)
#define s390_vab(c , v1, v2, v3)        S390_VRRc(c, 0xe7f3, v1, v2, v3, 0, 0, 0)

Use consistent spacing:

#define s390_trap2(code)		S390_E(code, 0x01ff)
#define s390_vab(c, v1, v2, v3)		S390_VRRc(c, 0xe7f3, v1, v2, v3, 0, 0, 0)

For ordered lists like package sources, maintain logical ordering:

<add key="darc-pub-dotnet-emsdk-b567cdb-1" value="..." />
<add key="darc-pub-dotnet-emsdk-b567cdb-2" value="..." />

When formatting rules must be violated, document the exception:

<!-- SA1001: Commas should not be preceded by a whitespace; needed due to ifdef -->
<NoWarn>$(NoWarn);SA1001</NoWarn>

For grouping related elements, keep them together:

#define FIRST_AVXVNNIINT8_INSTRUCTION INS_vpdpwsud
// Group all AVXVNNI instructions together rather than spreading them
// throughout different sections

Validate before access

Always validate parameters and initialize variables before access to prevent null dereference and undefined behavior. When handling arrays or pointers, require and validate length parameters. For conditionally initialized variables, ensure all code paths explicitly set values.

Example:

// Unsafe: No length validation before indexing
static bool IsPathNotFullyQualified(WCHAR* path)
{
    // Potential null dereference or buffer overflow
    if (path[0] == VOLUME_SEPARATOR_CHAR) return false;
}

// Safe: Length parameter and validation
static bool IsPathNotFullyQualified(WCHAR* path, size_t length)
{
    // Validate before accessing
    if (path == NULL || length < 1) return true;
    if (path[0] == VOLUME_SEPARATOR_CHAR) return false;
}

// For conditional initialization, always set values in all branches:
if (!bitmap_only)
    interface_offsets_full[i] = gklass->interface_offsets_packed[i];
else
    interface_offsets_full[i] = 0; // Prevent uninitialized value use

When modifying control flow to prevent null pointer dereferences, add explanatory comments to clarify the safety measures for future maintainers.


Idempotent error-safe disposers

When implementing resource cleanup logic, especially disposers for explicit resource management, always design for resilience during error conditions:

  1. Make disposal methods idempotent - they should work correctly when called multiple times without side effects
  2. Avoid throwing errors from disposers - thrown exceptions in cleanup code can mask original errors in a SuppressedError
  3. Always assume disposers may be called during exception handling - they receive no information about whether an exception is pending
class MyDisposableResource {
  #disposed = false;
  
  dispose() {
    // ✅ Idempotent - safe to call multiple times
    if (this.#disposed) return;
    this.#disposed = true;
    
    try {
      // Cleanup logic here
      console.log('Resource cleaned up');
    } catch (error) {
      // ✅ Avoid throwing from disposers
      console.error('Error during disposal:', error);
      // Don't re-throw - this would mask any pending exception
    }
  }

  [Symbol.dispose]() {
    // ✅ Delegate to explicit disposal method
    this.dispose();
  }
}

This pattern ensures resources are cleaned up reliably even during error conditions. By making disposers idempotent and error-safe, you prevent cascading failures where cleanup code compounds the original problem. It’s especially important in using/await using blocks where disposers are called automatically during both normal and exceptional exits, with no information about pending exceptions.


Use modern C++ features

Embrace modern C++20 features throughout the codebase to improve code readability, maintainability, and performance. Specifically:

  1. Use condensed namespace syntax:
    // Preferred
    namespace node::inspector::protocol {
    // ...
    }
       
    // Instead of
    namespace node {
    namespace inspector {
    namespace protocol {
    // ...
    }
    }
    }
    
  2. Prefer std::string_view over const std::string& for parameters that don’t need ownership:
    // Preferred
    const auto function = [](std::string_view path) {
      // Use path directly without copying
    };
       
    // Instead of
    const auto function = [](const std::string& path) {
      // Potentially causes unnecessary copies
    };
    
  3. Use enum class for better type safety and scope control:
    // Preferred
    enum class Mode { Shared, Exclusive };
       
    // Instead of
    enum Mode { kShared, kExclusive };
    
  4. Properly manage v8::Global objects using move semantics and reset():
    // Preferred
    v8::Global<v8::Promise::Resolver> holder(isolate, resolver);
    // When done:
    holder.reset();
       
    // Instead of
    auto* holder = new v8::Global<v8::Promise::Resolver>(isolate, resolver);
    // When done:
    delete holder;
    

Benchmark before optimizing code

Performance optimizations should be validated through benchmarks before implementation. This helps prevent premature optimization and ensures changes actually improve performance in real-world scenarios.

Key practices:

  1. Run benchmarks to establish baseline performance
  2. Test multiple input sizes to find stabilization points
  3. Consider edge cases and different environments
  4. Document benchmark results in the PR

Example:

// Before optimizing this:
const pairs = ArrayPrototypeMap(entries, ({ 0: k, 1: v }) => `${k}:${v}`);

// Run benchmarks to validate if this is better:
let pairs = new Array(entries.length);
for (let i = 0; i < entries.length; i++) {
  pairs[i] = `${entries[i][0]}:${entries[i][1]}`;
}

/* Example benchmark results:
n=10:        19,123 ops/sec
n=100:      222,985 ops/sec
n=1000:   1,262,360 ops/sec
n=10000:  3,751,348 ops/sec
n=100000: 4,789,673 ops/sec
*/

This approach helps prevent optimization work that doesn’t provide meaningful benefits while identifying changes that do improve performance significantly.


Model actual hardware costs

Base optimization decisions on accurate hardware cost models rather than outdated assumptions. Modern architectures have different performance characteristics for operations than older hardware, especially for SIMD and memory operations.

When modeling operation costs:

  1. Use realistic encoding and execution cycle estimates for different instruction types
  2. Consider alignment requirements that balance performance with code size
  3. Account for specialized hardware features like SIMD register volatility

For example, instead of using simplified cost models:

// Outdated cost model assumes all floating point operations are expensive
if (varTypeIsFloating(candidate->Expr()->TypeGet()))
{
    // floating point loads/store encode larger
    cse_def_cost += 2;
    cse_use_cost += 1;
}

Consider the actual hardware characteristics:

// Accurate cost model based on instruction encoding and execution cycles
if (varTypeIsFloating(candidate->Expr()->TypeGet()))
{
    // 32/64-bit FP move: encoding 4 bytes; execution: 4-7 cycles
    cse_def_cost += 4;
    cse_use_cost += 2;
}
else if (candidate->Expr()->TypeIs(TYP_SIMD16))
{
    // 128-bit SIMD move: encoding 3-4 bytes; execution: 4-7 cycles
    cse_def_cost += 3;
    cse_use_cost += 2;
}
else if (candidate->Expr()->TypeIs(TYP_SIMD32))
{
    // 256-bit SIMD move: encoding 4-5 bytes; execution: 5-8 cycles
    cse_def_cost += 4;
    cse_use_cost += 3;
}

For alignment decisions, consider both performance and code size goals:

// Balance alignment with code size goals
UNATIVE_OFFSET cnsSize  = genTypeSize(targetType);
UNATIVE_OFFSET cnsAlign = (compiler->compCodeOpt() != Compiler::SMALL_CODE) ? cnsSize : 1;

When optimization decisions depend on hardware-specific behavior (like SIMD register spilling), document the rationale to prevent future regressions.


Explicit API versioning

When extending interfaces with new methods or functionality, always implement proper versioning to ensure compatibility across different clients. Breaking changes should increment major versions, while additive changes should increment minor versions. More importantly, implement version checks in your code to gracefully handle compatibility.

For example, when adding a new method to an interface:

// 1. Update the version constant when adding functionality
#define API_INTERFACE_MAJOR_VERSION 2  // Increment for breaking changes
#define API_INTERFACE_MINOR_VERSION 5  // Increment for non-breaking additions

// 2. Implement version checks in code that calls the new functionality
if (runtimeVersion >= API_INTERFACE_MAJOR_VERSION) {
    // Call new method safely knowing it exists
    interface.NewMethod();
} else {
    // Provide alternative implementation or graceful degradation
    FallbackImplementation();
}

This approach allows clients on older versions to continue functioning when interacting with newer APIs and vice versa. Remember that versioning is only useful if actively checked during runtime - simply incrementing version numbers without implementing corresponding checks provides no actual compatibility benefits.


Document with precise accuracy

Maintain precise and accurate documentation through both JSDoc annotations and explanatory comments. Ensure all technical documentation matches the actual implementation, avoiding inconsistencies between code and documentation.

Key practices:

  1. Keep JSDoc parameter and return types strictly accurate
  2. Avoid default values in JSDoc to prevent inconsistencies
  3. Document unusual patterns or complex implementations
  4. Include clear examples for non-obvious functionality

Example:

/**
 * Format help text for printing.
 * @param {string} longOption - long option name e.g. 'foo'
 * @param {object} optionConfig - option config from parseArgs({ options })
 * @returns {string} formatted help text for printing
 * @example
 * formatHelpTextForPrint('foo', { type: 'string', help: 'help text' })
 * // returns '--foo <arg>                   help text'
 */
function formatHelpTextForPrint(longOption, optionConfig) {
  // Implementation using unusual pattern - explain why
  if (isSpecialCase(optionConfig)) {
    // Document why this special case exists
    // and how it affects the output
  }
  // ... rest of implementation
}

---

## Document code meaningfully

<!-- source: dotnet/runtime | topic: Documentation | language: C# | updated: 2025-06-27 -->

Provide meaningful documentation that enhances code maintainability and understanding. Follow these practices:

1. **Explain the "why"** - Document complex or non-obvious code behavior with comments that explain reasoning, not just functionality:
```csharp
// Checking HasNewValue ensures the property setter is called even with null values,
// as setters may contain important initialization logic that should not be bypassed
if (bindingPoint.HasNewValue || bindingPoint.Value != null)
  1. Track TODOs properly - Replace generic TODO comments with specific GitHub issue references:
    // TODO: Implement caching mechanism (see issue #1234)
    
  2. Attribute borrowed code - When adapting code from external sources, include clear attribution with links and license information:
    // These definitions are derived from CDDL-licensed source code.
    // Original source: https://src.illumos.org/source/xref/illumos-gate/usr/src/uts/common/sys/procfs.h
    
  3. Document APIs with XML comments - Use XML documentation for public, internal, and significant private APIs to explain their purpose, parameters, and usage patterns, even for parameterless constructors that seed documentation.

  4. Keep documentation readable - Ensure comments are concise, valuable, and formatted to avoid requiring horizontal scrolling.

Following these practices helps both current and future developers understand code intent, origin, and pending work, significantly reducing maintenance costs.


Optimize search operations

Enhance search algorithm performance by prioritizing common cases, using appropriate data structures, and avoiding unnecessary operations.

When implementing binary search:

  1. Consider checking common values first (e.g., the max value) before running a full binary search
  2. Add clarifying comments for binary search results like index = ~index; // same as -(index + 1)
  3. Store repeated calculation results as constants when used in loops
  4. Ensure container sizes are powers of two when using bit-masking (& (size - 1)) for indexing

Example of optimized binary search with fast-path check:

public int findIndex(int[] sortedArray, int value) {
    // Fast path: check if value is at the max position
    if (sortedArray.length > 0 && sortedArray[sortedArray.length - 1] == value) {
        return sortedArray.length - 1;
    }
    
    // Standard binary search
    int index = Arrays.binarySearch(sortedArray, value);
    if (index < 0) {
        index = ~index; // same as -(index + 1), insertion point
    }
    return index;
}

When working with collections, prefer iteration methods that don’t create unnecessary copies. For example, use iterator() instead of methods that create new collections just for iteration.


Follow naming patterns

Maintain consistent naming patterns throughout your code to improve readability and maintainability. Follow these guidelines:

  1. Use PascalCase for public methods and members
    // Incorrect
    public static int iCreateProcessInfo() { ... }
       
    // Correct
    public static int CreateProcessInfo() { ... }
    
  2. Method names should accurately reflect their purpose
    // Misleading (doesn't return anything)
    public static void GetExtendedHelp(ParseResult _) { ... }
       
    // Better
    public static void DisplayHelp(ParseResult _) { ... }
    
  3. Match related parameter names for clarity
    // Inconsistent
    GetConnectionInfo(connection, out protocol, out cipherSuite, ref negotiatedAlpn, out alpnLength);
       
    // Consistent
    GetConnectionInfo(connection, out protocol, out cipherSuite, ref negotiatedAlpn, out negotiatedAlpnLength);
    
  4. Design enums with meaningful defaults
    // Poor design (default value is meaningful)
    public enum ExtendedLayoutKind
    {
        None = -1,
        CStruct = 0  // This becomes the default!
    }
       
    // Better design
    public enum ExtendedLayoutKind
    {
        None = 0,    // Default is semantically "none"
        CStruct = 1
    }
    
  5. Use consistent abbreviations based on platform conventions
    // Unnecessarily verbose when platform uses "Nw" consistently
    internal sealed class SafeNetworkFrameworkHandle : SafeHandleZeroOrMinusOneIsInvalid
       
    // Better
    internal sealed class SafeNwHandle : SafeHandleZeroOrMinusOneIsInvalid
    

When selecting names, consider how they’ll be read in context and their alignment with existing patterns in your codebase and the platform.


Optimize memory access

When implementing performance-critical algorithms, carefully consider memory access patterns. Document alignment assumptions when using low-level operations like MemoryMarshal.Cast or SIMD intrinsics. Prefer reference-based APIs over pinning to avoid GC interference. For bulk operations, use specialized helpers like LoadUnsafe(ref T source, nuint elementOffset) instead of pointer arithmetic.

// Less optimal: Uses pinning that can hinder GC
unsafe void ProcessBytes(ReadOnlySpan<byte> source)
{
    fixed (byte* ptr = source)
    {
        for (int i = 0; i < source.Length - 7; i += 8)
        {
            ulong value = *(ulong*)(ptr + i);
            // Process 8 bytes at once
        }
    }
}

// More optimal: Uses ref-based API without pinning
void ProcessBytes(ReadOnlySpan<byte> source)
{
    ref byte sourceRef = ref MemoryMarshal.GetReference(source);
    for (int i = 0; i + 8 <= source.Length; i += 8)
    {
        // Use LoadUnsafe with explicit offset
        ulong value = Vector64.LoadUnsafe(ref sourceRef, (nuint)i);
        // Process 8 bytes at once
    }
}

When handling data in bulk, consider the impact of alignment requirements and document edge cases like zero-length inputs. For operations on numeric types, select appropriate operations based on platform characteristics (e.g., prefer unsigned division over signed when possible).


avoid panics gracefully

Replace panic-prone operations like unwrap() and expect() with graceful error handling that provides meaningful feedback. When encountering unexpected conditions, prefer logging warnings and falling back to reasonable defaults rather than crashing the application.

Key practices:

Example transformation:

// Avoid this - can panic on unexpected input
let path = output.canonicalize().unwrap().to_string_lossy().to_string();

// Prefer this - graceful error handling
let path = match output.canonicalize() {
    Ok(path) => path.to_string_lossy().to_string(),
    Err(err) => {
        eprintln!("Failed to canonicalize path: {}", err);
        return Err(err);
    }
};

This approach prevents application crashes from unexpected conditions while still providing useful diagnostic information for debugging and user feedback.


Prevent TOCTOU vulnerabilities

Time-of-Check-to-Time-of-Use (TOCTOU) race conditions occur when a program checks a condition and then uses the result of that check, but the condition might have changed between the check and use. This pattern creates security vulnerabilities, particularly in file system operations, but can affect any multi-step operation where state might change.

To prevent TOCTOU vulnerabilities:

  1. Use atomic operations whenever possible instead of separate check-then-act sequences
    // VULNERABLE TO TOCTOU:
    if !Path::new("file.txt").exists() {
        File::create("file.txt")?; // Race condition: file might be created here by another process
    }
       
    // SAFER APPROACH:
    let file = File::options().create_new(true).open("file.txt"); // Atomic operation
    
  2. Maintain resource handles throughout operations rather than repeatedly checking state
    // Keep the file open while working with it rather than reopening based on metadata checks
    let mut file = File::open("data.txt")?;
    // Continue using the same file handle for subsequent operations
    
  3. Be skeptical of metadata obtained from previous checks, as it may be stale

  4. For security-critical operations, verify that operations succeeded with their intended effect rather than assuming success

  5. Never trust user input or external data without validation, especially in multi-step operations

Remember that even file locks may be insufficient protection against malicious actors, as they’re often advisory and can potentially be bypassed.


Scope security settings

Avoid modifying global security state in favor of connection-specific or context-bound security settings. Global security state changes can lead to unexpected security vulnerabilities when modified by dependencies without application awareness.

When working with security-critical components like TLS:

  1. Configure security options at the connection level rather than globally
  2. Be wary of APIs that make one-way security changes affecting all connections
  3. Design APIs that allow explicit security configuration for specific contexts

For example, instead of using global security state changes:

// Avoid globally changing security state
tls.useSystemCA();  // Affects ALL connections

// Preferred: Scope security settings to specific connections
const connection = tls.connect({
  ca: tls.getCACertificates('system')  // Only affects this connection
});

This approach maintains clear security boundaries and prevents dependencies from silently weakening your application’s security posture through unexpected global state mutations.


Optimize common paths

Design algorithms that optimize for the most common execution paths by prioritizing frequent scenarios in conditional logic, data structures, and resource allocation.

For conditional code, order checks to minimize branching in frequent cases:

// Better: Common case first requires only one check
if (varTypeUsesIntReg(type))
{
    return IntRegisterType;
}
// Less common case
else if (varTypeUsesMaskReg(type))
{
    return MaskRegisterType;
}
// Least common case with assertion
else
{
    assert(varTypeUsesFloatReg(type));
    return FloatRegisterType;
}

Pre-compute constants instead of calculating them at runtime, especially for cross-platform compatibility:

// Better: Pre-computed value
cmp         rsi, 0x8000000 // (0x40000000 / sizeof(void*))

// Worse: Compiler-dependent calculation
cmp         rsi, (0x40000000 / 8) // sizeof(void*)

Focus testing and optimization efforts on the most frequently used combinations of features rather than exhaustively covering all permutations. This “pay for play” approach ensures users only bear the computational cost for features they actually use.


Match filenames to contents

Files should be named to clearly reflect their primary contents:

  1. When a file contains a single primary type:
    • Name the file exactly after the type
    • Use PascalCase for both the file and type names
    • Make the type the top-level struct
  2. For utility/process files:
    • Use descriptive names that indicate the file’s purpose
    • Avoid generic terms that could mean multiple things

Example:

// Good: HTTPThread.zig
const HTTPThread = @This();

// Bad: http_thread.zig
pub const HTTPThread = struct {

// Good: processDependencyList.zig
// Bad: process.zig (too generic)

This convention improves code navigation, maintains consistency, and makes the codebase more intuitive to work with. It also helps prevent confusion when multiple files could potentially have similar generic names.


Propagate errors with context

Always propagate errors with their original context instead of swallowing them or throwing new errors that hide the original cause. This helps with debugging and allows proper error handling up the call stack.

Key practices:

  1. Avoid using USE() or Check() which hide errors
  2. Return Maybe/MaybeLocal for error propagation
  3. Preserve original error context in promise chains
  4. Only catch errors when you can properly handle them

Example of proper error propagation:

// Bad - Swallows error with USE
USE(promise->Then(context, callback));

// Good - Propagates error
if (promise->Then(context, callback).IsEmpty()) {
  return;  // Error already scheduled
}

// Bad - Hides original error
if (!CreateObject(isolate, context).ToLocal(&obj)) {
  return ThrowError("Failed to create object");
}

// Good - Preserves original error
if (!CreateObject(isolate, context).ToLocal(&obj)) {
  return;  // Original error propagates
}

This practice ensures:


Eliminate unnecessary constructs

Remove redundant or unnecessary code constructs to improve readability and maintainability. This includes avoiding empty blocks, blocks containing only empty statements, and unnecessary variable declarations that don’t enhance code clarity.

Example (before):

try {
    const resource = __addDisposableResource(env, resource_1, true);
    {
        ; // Empty block with just a semicolon
    }
}

// Or unnecessary variables:
__assign = Object.assign || function(t) {
    for (var s, i = 1, n = arguments.length; i < n; i++) {
        s = arguments[i];
        for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
            t[p] = s[p];
    }
    return t;
};

Example (after):

try {
    const resource = __addDisposableResource(env, resource_1, true);
    // No empty block
}

// Simplified variables:
__assign = Object.assign || function(t) {
    for (var i = 1; i < arguments.length; i++) {
        var source = arguments[i];
        for (var key in source) {
            if (Object.prototype.hasOwnProperty.call(source, key)) {
                t[key] = source[key];
            }
        }
    }
    return t;
};

comprehensive validated examples

Documentation examples should be self-sufficient, comprehensive, and use proper syntax tags to enable automated validation. Examples must include all necessary context and demonstrate multiple related features rather than isolated snippets. Use v syntax tags instead of generic ones like codeblock to ensure examples are validated by v check-md during CI, keeping them current and consistent.

For example, instead of a minimal snippet:

ch.try_push(42)

Provide a complete, informative example:

ch := chan int{cap: 2}
println(ch.try_push(42)) // `.success` if pushed, `.not_ready` if full, `.closed` if closed
println(ch.len) // Number of items in the buffer
println(ch.cap) // Buffer capacity
println(ch.closed) // Whether the channel is closed

This approach makes examples immediately usable for learning and ensures they remain valid through automated testing, while providing comprehensive coverage of related functionality.


Optimize aligned SIMD operations

Always use proper memory alignment for SIMD (Single Instruction, Multiple Data) operations to maximize performance. When implementing vector operations:

  1. Use platform-specific aligned memory allocation functions when available
  2. Provide alignment hints in vector load/store instructions even on platforms that don’t strictly require alignment
  3. Define specialized aligned versions of memory operations that can take advantage of hardware features

Example:

// Prefer this approach with platform-specific optimizations
#if HAVE_ALIGNED_ALLOC
    return aligned_alloc(alignment, size);
#elif HAVE_POSIX_MEMALIGN
    void* result = nullptr;
    posix_memalign(&result, alignment, size);
    return result;
#else
    #error "Platform doesn't support aligned_alloc or posix_memalign"
#endif

// For memory operations, leverage alignment hints when available
#ifdef TARGET_ARCHITECTURE_WITH_ALIGNMENT_HINTS
    // Define aligned versions that use hardware alignment hints
    case OP_LOADX_ALIGNED_MEMBASE:
    case OP_STOREX_ALIGNED_MEMBASE_REG:
#endif

Proper alignment can lead to dramatic performance improvements for vector operations (up to 295x faster for some SIMD comparison operations) by enabling hardware-specific optimizations and avoiding cache-line splitting.


Prefer clarity over cleverness

Write code that prioritizes readability and maintainability over cleverness or excessive optimization. Avoid overly clever techniques that might confuse other developers or make the code harder to maintain.

Key principles:

Example - Instead of this clever approach:

const handleTypes = ['TCP', 'TTY', 'UDP', 'FILE', 'PIPE', 'UNKNOWN'];
setOwnProperty(handleTypes, -1, null);
// Later using handleTypes[someIndex]

Prefer this more explicit approach:

const handleTypes = ['TCP', 'TTY', 'UDP', 'FILE', 'PIPE', 'UNKNOWN'];

function getHandleType(type) {
  return type >= 0 && type < handleTypes.length ? handleTypes[type] : null;
}

Similarly, prefer direct string creation over array joining for static content:

// Instead of:
const message = [
  'Error: This file cannot be parsed as either CommonJS or ES Module.',
  '- CommonJS error: await is only valid in async functions.',
  '- ES Module error: require is not defined in ES module scope.'
].join('\n');

// Prefer:
const message = 'Error: This file cannot be parsed as either CommonJS or ES Module. ' +
  'CommonJS error: await is only valid in async functions. ' +
  'ES Module error: require is not defined in ES module scope.';

When functions are called multiple times, consider the performance implications of inlining vs. extracting. Unnecessary function extraction can hinder compiler optimizations in hot paths.


Document configuration intent

Configuration settings should be self-documenting with clear intent. When adding temporary workarounds, conditional flags, or platform-specific settings, include descriptive comments explaining their purpose, limitations, and lifecycle. Use TODO comments with issue references for temporary configurations, and choose clear, descriptive names for all configuration properties. This practice helps future developers understand why certain configurations exist and when they can be modified or removed.

Examples:

  1. For temporary workarounds: ```xml
<_Crossgen2Supported Condition="'$(TargetOS)' != 'illumos' and '$(TargetOS)' != 'solaris'">true

2. For feature flags with specific scope:
```xml
<FeatureJavaMarshal Condition="'$(Configuration)' == 'Debug' or '$(Configuration)' == 'Checked' or '$(TargetOS)' == 'Android'">true</FeatureJavaMarshal>
  1. For clear, descriptive naming: ```xml
true true

---

## Reuse computed values efficiently

<!-- source: nodejs/node | topic: Performance Optimization | language: Other | updated: 2025-06-24 -->

Move variable declarations and computations outside of loops when their values don't change between iterations. This reduces memory allocations and avoids redundant computations, improving performance.

Example - Before:
```cpp
for (const auto& resource_entry : manager->held_locks_) {
  for (const auto& held_lock : resource_entry.second) {
    Local<Object> lock_info = CreateLockInfoObject(...);
    // Use lock_info
  }
}

Example - After:

Local<Object> lock_info;
for (const auto& resource_entry : manager->held_locks_) {
  for (const auto& held_lock : resource_entry.second) {
    lock_info = CreateLockInfoObject(...);
    // Use lock_info
  }
}

Similarly, cache computed values that are used repeatedly:

// Before: Computing in every call
std::string normalised_cache_dir = NormalisePath(cache_dir);

// After: Store as member variable
class CompileCacheHandler {
  std::string normalised_cache_dir_;
  // Compute once in constructor
};

Platform-agnostic network APIs

When implementing networking functionality, ensure code uses platform-agnostic APIs and appropriate abstraction layers to handle differences between Windows, Unix, and macOS systems. Similar to how string operations require platform-specific handling (as seen in discussion 1 where strchr was replaced with app_candidate.find(DIR_SEPARATOR)), networking code should avoid direct OS-specific socket APIs in favor of cross-platform abstractions.

Example:

// Avoid platform-specific code like this:
#ifdef _MSC_VER
    SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
    // Windows-specific socket operations
#else
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    // Unix-specific socket operations
#endif

// Instead, use platform abstraction layers:
pal::socket_t sock = pal::create_socket(pal::AddressFamily::IPv4, pal::SocketType::Stream);
if (pal::connect_socket(sock, address, port))
{
    // Platform-agnostic socket operations
}

This approach ensures consistent behavior across all supported platforms and simplifies maintenance by centralizing platform-specific code in the abstraction layer.


Names reflect actual purpose

Name variables, properties, and functions to accurately reflect their purpose and actual usage in code, not just their technical classification. This ensures other developers can understand the intent without having to analyze implementation details.

Key guidelines:

Example:

// Avoid misleading names
var _maskData = new int[size]; // Not actually used as a mask

// Better - name reflects actual usage
var _selectParameters = new int[size]; // Used as parameters in select operations

// For configurations, prefer descriptive names over technical terms
// Less clear for users:
options.WasmEnableEventPipe = true;

// More descriptive of purpose:
options.WasmEnablePerformanceTracing = true;

Follow this principle even when a name seems technically correct - what matters is whether it effectively communicates how the element is actually used in your codebase.


Streamline workflow configurations

Maintain efficient and properly structured CI/CD workflows by removing unnecessary dependencies and using consistent formatting patterns. Each workflow step should serve a specific purpose for the job it’s part of, and matrix configurations should follow a consistent structure.

Remove unnecessary setup steps:

# AVOID: Including unused toolchains or setup steps
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
- uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable
- uses: ./.github/actions/setup-go

# PREFER: Only include steps required for the specific job
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0

Use consistent matrix configuration structures:

# PREFER: Use structured objects for better readability and extensibility
runtime:
  - { name: node, version: 20 }
  - { name: node, version: 18 }
  - { name: bun, version: 'latest' }

# For includes, maintain the same structure:
include:
  - { os: ubuntu-latest, runtime: { name: node, version: 20 }, bundle: false }

Regular workflow audits should be performed to remove outdated or unnecessary steps that might slow down builds or waste resources. Well-structured workflows are easier to maintain, extend, and debug when issues arise.


Avoid ambiguous naming

Choose names that clearly convey their purpose and avoid ambiguous identifiers that can be misinterpreted. This applies to methods, variables, parameters, and types.

Key principles:

Examples:

Instead of confusing boolean parameters:

// Bad - unclear what true/false means
fn parse_inner(s: &str, allow_subdomain_wildcard: bool)

// Good - descriptive enum makes intent clear
enum SubdomainWildcardSupport {
  Enabled,
  #[default]
  Disabled
}
fn parse_inner(s: &str, wildcard_support: SubdomainWildcardSupport)

Instead of ambiguous method names:

// Bad - unclear what this cancels
fn op_read_cancel()

// Good - clearly describes the operation
fn op_read_with_cancel_handle()

// Bad - too generic when context matters
fn get_usage()

// Good - specific to the type of usage
fn get_cpu_usage()

Instead of unclear type names:

// Bad - not descriptive enough
struct Unconfigured

// Good - clearly describes the state
struct UnconfiguredRuntime

This practice is especially important in permission-related code and public APIs where clarity prevents misuse and security issues.


Assert before cast

Always validate values before performing unsafe operations like dynamic casting. When a value could be null, zero, or undefined, store it in an intermediate variable and verify it before proceeding.

Bad:

// Risky: jsDynamicCast on a zero value is undefined behavior
auto* existing_tag = jsDynamicCast<Bun::NapiTypeTag*>(globalObject->napiTypeTags()->get(js_object));

// Dangerous: No verification before dereferencing
return handleSlot ? JSC::JSValue::encode(*handleSlot) : JSC::JSValue::encode(JSC::JSValue());

Good:

// Safe: Store the result first, then check before casting
JSValue napiTypeTagValue = globalObject->napiTypeTags()->get(js_object);
auto* existing_tag = jsDynamicCast<Bun::NapiTypeTag*>(napiTypeTagValue);

// Better: Assert your assumptions explicitly
ASSERT(handleSlot);
return JSC::JSValue::encode(*handleSlot);

For functions that can return null or trigger exceptions, add appropriate assertions after critical operations:

// Assert getDirect doesn't return null
auto value = thisObject->getDirect(vm, builtinNames.statePrivateName());
ASSERT(value);

// Check for exceptions after conversions
auto state = value.toInt32(lexicalGlobalObject);
assertNoExceptionExceptTermination();

This approach prevents undefined behavior, makes code intent clearer, and helps catch bugs earlier in the development process.


Document non-intuitive code

Add clear comments to explain complex logic, function differences, and non-obvious implementation details. This is especially important for:

When a future developer reads your code, they should understand the reasoning without needing to reverse-engineer the logic. Documentation is particularly valuable for code that will be maintained by others.

For example:

// Document differences between similar functions
// hashDigest: Creates a fixed-length hash from input data
// xofHashDigest: Creates an extendable-output function hash with custom length
DataPointer hashDigest(const Buffer<const unsigned char>& data,
                       const EVP_MD* md);
DataPointer xofHashDigest(const Buffer<const unsigned char>& data,
                          const EVP_MD* md,
                          size_t length);

// Explain non-intuitive checks
if (content.front() == '[') {
  // This identifies the start of a section like [section_name]
  // ...
}

// Document complex methods
// InitWldp: Initializes Windows Lockdown Policy features
// Loads required DLLs and resolves function pointers for code integrity checks
void InitWldp(Environment* env) {
  // implementation...
}

Prioritize documentation that answers “why” over “what” when the code itself already clearly shows what it’s doing.


Await all promises

Always explicitly await all asynchronous operations, especially in cleanup code paths and resource management. Failing to properly await promises can lead to race conditions, resource leaks, and unpredictable behavior in concurrent environments.

When writing concurrent code:

  1. Await all async operations, especially file operations and resource cleanup: ```javascript // Bad: Resource may not be fully closed when code continues if (options.autoClose) this.close();

// Good: Ensures the resource is fully closed before continuing if (options.autoClose) await this.close();


2. Use modern Promise patterns for cleaner async code:
```javascript
// Better: Use Promise.withResolvers() for cleaner promise creation
const { promise, resolve, reject } = Promise.withResolvers();
fs.stat(filePath, { signal }, (err, stats) => {
  if (err) {
    return reject(err);
  }
  resolve(stats);
});
await assert.rejects(promise, { name: 'AbortError' });
  1. Ensure async context is preserved across asynchronous boundaries:
    // Ensure AsyncLocalStorage context is preserved in callbacks
    const als = new AsyncLocalStorage();
    als.run(123, () => {
      navigator.locks.request('lock-name', async (lock) => {
     // Context should be maintained across the async boundary
     assert.strictEqual(als.getStore(), 123);
      });
    });
    

By properly awaiting promises and managing async context, you’ll write more reliable concurrent code with fewer race conditions and resource leaks.


Behavior-focused test design

Tests should focus on verifying behavior rather than implementation details to ensure they remain robust during refactoring. Avoid dependencies on timers or internal code structure that can lead to flaky and brittle tests.

Always use appropriate assertion utilities to verify expected behavior:

// ❌ Fragile: Tests implementation details
assert(tapReporterSource.includes('return result; // Early return...'));

// ✅ Robust: Tests actual behavior with proper utilities
const result = await reader.read(new Uint8Array(16));
assert.deepStrictEqual(result, { 
  value: expectedBytes,
  done: false
});

// ✅ Verify callbacks execute
reader.read(receive).then(common.mustCall((result) => {
  assert.strictEqual(result.done, false);
}));

Avoid using timers in tests as they create non-deterministic behavior, leading to flakiness and slowness. Instead, use event hooks or synchronous assertions that verify the expected outcome directly.


Check exceptions consistently

Always check for exceptions immediately after operations that might throw them, especially before using the results in control flow decisions. When accessing properties that might be used in conditionals, retrieve the property first, check for exceptions, and then use the property in the conditional.

Incorrect pattern:

if (JSValue property = object->getIfPropertyExists(globalObject, propertyName)) {
    // Use property...
    RETURN_IF_EXCEPTION(scope, {});  // Too late - exception may have occurred during getIfPropertyExists
}

Correct pattern:

JSValue property = object->getIfPropertyExists(globalObject, propertyName);
RETURN_IF_EXCEPTION(scope, {});  // Check immediately after the operation
if (property) {
    // Now safe to use property...
}

This pattern applies to any function that might throw exceptions, including property access, method calls, and object construction. Ensure exception checking occurs after each potentially throwing operation and before using its results. Use consistent macros like RETURN_IF_EXCEPTION or RELEASE_AND_RETURN based on your codebase’s conventions.

For property chains or multiple operations, check after each step:

auto value = params->get(globalObject, property);
RETURN_IF_EXCEPTION(scope, nullptr);
// Now safe to use value

Following this pattern prevents hard-to-debug crashes and ensures exceptions are properly handled throughout all code paths.


Format docs for readability

Documentation should follow consistent formatting and structural patterns to maximize readability and maintainability. Key guidelines:

  1. Keep line lengths to 80 characters maximum
  2. Place all document links at the bottom of the file and use in-doc references
  3. Document default behaviors before introducing exceptions
  4. Use proper spacing and indentation for examples and code blocks

Example of proper documentation formatting:

# Feature Name

Default behavior description first, followed by any exceptions or special cases.

## Usage

```js
// Code example with proper indentation
const example = require('node:example');
example.doSomething();

Options


This format ensures consistency across documentation and makes it easier for users to find and understand information.

---

## Structure configuration options

<!-- source: dotnet/runtime | topic: Configurations | language: C++ | updated: 2025-06-20 -->

Design and document configuration options (feature flags, environment variables, conditional compilation) to be clear, consistent, and maintainable. Group related configurations together and avoid unnecessary splits or redundancies. Document the purpose and behavior of each option, including valid values and interaction effects.

For conditional compilation:
```cpp
// GOOD: Clear hierarchy and purpose
#if !defined(DACCESS_COMPILE) && !defined(FEATURE_CDAC_UNWINDER)
// Code for in-process execution only
#endif

// AVOID: Redundant or overly specific conditions
#if defined(HOST_WINDOWS) // Redundant if file is Windows-only
// ...
#endif

For environment variables, provide clear levels with documented behavior:

// GOOD: Well-documented configuration with clear levels
// DOTNET_InterpreterMode=0: default, interpreter only used with explicit opt-in
// DOTNET_InterpreterMode=1: use interpreter except for R2R code and System.Private.CoreLib
// DOTNET_InterpreterMode=2: use interpreter for everything except intrinsics
// DOTNET_InterpreterMode=3: full interpreter-only mode, no fallbacks

For feature flags, consolidate related functionality until there’s a clear need for separation:

// PREFER: Single feature flag for closely related functionality
#ifdef FEATURE_JAVAMARSHAL
// All Java interop code including GC bridge
#endif

// AVOID: Premature separation that creates confusing boundaries
#ifdef FEATURE_JAVAMARSHAL
// Some Java interop code
#endif
#ifdef FEATURE_GCBRIDGE
// Closely related GC bridge functionality
#endif

Minimize configuration dependencies

Keep configuration dependencies minimal and platform-aware. Avoid including unnecessary configuration files or external tools that can introduce unpredictable behaviors or unrelated settings. For platform-specific code, use conditional compilation to ensure that components are only built and executed in relevant environments.

When working with build configurations:

  1. Only include necessary configuration files that are directly relevant to the component being built
  2. Use conditional compilation for platform-specific code
  3. Minimize dependencies on external tools with behaviors that may change unexpectedly

Example of good practice for platform-specific code:

// For header files
#ifndef SRC_NODE_PLATFORM_FEATURE_H_
#define SRC_NODE_PLATFORM_FEATURE_H_

#ifdef _WIN32
// Windows-specific declarations
#endif

// Cross-platform declarations

#endif  // SRC_NODE_PLATFORM_FEATURE_H_

// For implementation files
#ifdef _WIN32
// Windows-specific implementation
#endif

Example of good configuration file practice:

// Only include what you need
'includes': ['toolchain.gypi'],  // Correct if only toolchain config is needed

// Avoid unnecessary inclusions
'includes': ['toolchain.gypi', 'features.gypi'],  // Incorrect if features.gypi adds unneeded complexity

Ensure comprehensive documentation

Documentation should be complete, properly formatted, and clearly explain purpose with adequate examples. When writing documentation, ensure that:

  1. Code examples are properly formatted - Match indentation requirements and follow established formatting conventions
  2. Examples are comprehensive - Include examples that illustrate all requirements, constraints, and edge cases, not just the happy path
  3. Functions and concepts are clearly explained - Provide explanatory comments for functions with unclear or ambiguous names, especially when terminology has specific technical meanings

For example, when documenting an attribute with requirements:

// Good: Comprehensive examples showing both valid and invalid usage
[[clang::sycl_external]] void Foo(); // Ok.

[[clang::sycl_external]] void Bar() { /* ... */ } // Ok.

[[clang::sycl_external]] extern void Baz(); // Ok.

[[clang::sycl_external]] static void Quux() { /* ... */ } // error: Quux() has internal linkage.

Similarly, when adding functions with potentially ambiguous names, include comments explaining their purpose:

// Generates a concise string representation of a NamedDecl for diagnostic purposes
SmallString<128> toTerseString(const NamedDecl &D) const;

This approach prevents confusion and ensures documentation serves as an effective reference for both current and future developers.


Maintain configuration compatibility

When modifying configuration systems, prioritize backward compatibility unless there’s an explicit breaking change planned. If a breaking change is necessary, implement compatibility handlers for older configurations and clearly communicate the transition plan.

For example, when modifying configuration enums or data structures:

// When adding new configuration values, append them rather than reordering
// to maintain compatibility with serialized configurations
enum ConfigValues 
{
    // Existing values - don't change these ids
    Value1 = 1,
    Value2 = 2,
    
    // New values - add at the end
    NewValue = 3
}

// For major changes, implement version detection and compatibility handling
public ProcessConfig(ConfigData data) 
{
    if (data.Version < CurrentVersion) {
        // Handle older format compatibility
        return ProcessLegacyConfig(data);
    }
    
    // Process current format
}

This approach ensures tools and systems can continue to process configurations from previous versions, maintaining reliability across version updates. As seen in the discussions, breaking configuration compatibility (like removing enum definitions) can break tools that need to process older versions, requiring changes to be reverted or additional compatibility code to be written.


Public over internal APIs

When designing or implementing APIs, always prefer publicly documented APIs over internal ones. Internal APIs may change without notice as they aren’t subject to semantic versioning guarantees.

If you need functionality that’s only available through internal APIs, either:

  1. Look for an equivalent public API that might already exist
  2. Consider creating a proper public API with appropriate documentation

For example, instead of using internal modules:

// Avoid this
const { setSourceMapsSupport } = require('internal/source_map/source_map_cache');
const { SourceMap } = require('internal/source_map/source_map');

// Prefer this
const { setSourceMapsSupport } = require('node:module');
const { SourceMap } = require('node:module');

When exposing new APIs, ensure they’re properly documented and don’t leak internal implementation details. If an API returns values with specific formats (like ‘commonjs-typescript’), either document these formats as part of the public contract or convert them to standard documented values.

Using internal APIs can lead to code that breaks unexpectedly during updates, creates maintenance burdens, and prevents APIs from being properly stabilized in the future.


explicit dependency configuration

Ensure dependency configurations are explicit and predictable to avoid confusion and unexpected build behavior. Avoid package aliases that obscure the actual dependency being used, prefer published versions over git dependencies for stability, and be explicit about features that control critical behaviors like linking.

When specifying dependencies:

This prevents silent fallbacks, reduces confusion about what’s actually being used, and makes build behavior more predictable across different environments.


Document algorithm behavior

When implementing or documenting algorithms, clearly specify their behavior, expected outputs, and usage patterns. This includes documenting mathematical operation semantics, output characteristics, and providing complete examples that demonstrate the algorithm’s behavior.

Key aspects to document:

Example from cryptographic algorithm documentation:

// Alice derives shared secret with her own private key with Bob's public key
alice_shared_sec := curve25519.derive_shared_secret(mut alice_pvkey, bob_pbkey)!

// Bob derives shared secret with his own private key with Alice's public key  
bob_shared_sec := curve25519.derive_shared_secret(mut bob_pvkey, alice_pbkey)!

// the two shared secrets (derived by Alice, and derived by Bob), should be the same
// Output: 32-byte shared secret
println('Alice secret: ${alice_shared_sec}')
println('Bob secret: ${bob_shared_sec}')

This ensures developers understand not just how to use the algorithm, but what to expect from it and how it behaves in different scenarios.


Use TypeScript-specific tests

Always use fourslash tests (for IDE/language service features) or compiler tests (for TypeScript compilation behavior) instead of direct unit tests. Place tests in the correct directories: tests/cases/compiler or tests/cases/fourslash.

Fourslash tests validate IDE features like completions and refactoring:

/// <reference path='fourslash.ts'/>

//// interface User {
////     name: string;
//// }
//// 
//// const user: User = {
////     /*completion*/
//// };

verify.completions({
    marker: "completion",
    includes: { name: "name" }
});

Compiler tests validate TypeScript type checking:

// @Filename: test.ts
// @strict: true

interface Config {
    required: string;
    optional?: number;
}

const config1: Config = { required: "test" }; // Should work
const config2: Config = { optional: 42 }; // Should error - missing required

When adding tests, ensure you run them individually first with hereby runtests --tests=path/to/test.ts to verify they demonstrate the expected behavior correctly before committing.


Actionable error messages

When designing APIs, provide error messages that are contextually accurate, descriptive, and actionable. Generic error suggestions can confuse users when they don’t apply to the specific situation. Instead, tailor error responses to include:

  1. The precise reason for the failure
  2. Context-aware suggestions that are applicable to the specific error case
  3. Clear steps for resolution when possible

For example, instead of a generic message like:

Could not find a declaration file for module 'bar'. Try `npm i --save-dev @types/bar` if it exists or add a new declaration (.d.ts) file containing `declare module 'bar';`

A more contextually aware message might be:

Could not find a declaration file for module 'bar' at '/path/to/bar.js'. This file is being treated as a JavaScript module. Consider one of the following:
- If this is your own module, add type definitions with a matching .d.ts file
- If using a third-party module, check if @types/bar exists and is compatible with your version
- If neither applies, verify the module path is correct

Error messages that adapt to the specific situation help API consumers resolve issues more efficiently and reduce support burden.


Consistent module resolution

Configure consistent module resolution strategies across related projects and ensure package.json files are properly set up for the chosen strategy. Different strategies (Node10, NodeNext) have distinct behaviors regarding package.json handling, which can cause subtle resolution errors and confusing tracing output.

For example, when using NodeNext:

// tsconfig.json
{
  "compilerOptions": {
    "moduleResolution": "NodeNext",
    // Ensure traceResolution is consistently set across projects if needed for debugging
    "traceResolution": true
  }
}

And ensure your package.json correctly defines module entry points:

// package.json
{
  "name": "my-package",
  "main": "build/index.js",  // Used by Node.js and some module resolution strategies
  "types": "build/index.d.ts" // Used by TypeScript to find type declarations
}

When troubleshooting module resolution issues, remember that inconsistent configuration can lead to unexpected behavior. If you need to trace module resolution, make sure the traceResolution option is set consistently across all relevant projects in your workspace.


consistent error diagnostics

When implementing attributes, language features, or compiler diagnostics, always provide explicit error diagnostics rather than default warnings for misuse scenarios. Error messages should be clear, specific about the violation, and consistent with existing diagnostic patterns in the codebase.

For attributes, explicitly request error diagnostics using ErrorDiag in the SubjectList to ensure consistent behavior across all attributes. For custom error messages, follow established naming conventions and provide specific guidance about correct usage.

Example of proper error diagnostic implementation:

// In Attr.td - Request explicit error diagnostics
def SYCLExternal : InheritableAttr {
  let Spellings = [Clang<"sycl_external">];
  let Subjects = SubjectList<[Function], ErrorDiag>;  // Use ErrorDiag, not default warning
}

// In DiagnosticSemaKinds.td - Provide clear, specific error messages
def err_sycl_external_invalid_linkage : Error<
  "'sycl_external' can only be applied to functions with external linkage">;

This approach ensures users receive immediate, clear feedback about incorrect usage rather than potentially overlooked warnings, leading to better code quality and faster debugging cycles.


consistent formatting preferences

Maintain consistent formatting and use concise, standard syntax throughout the codebase. This includes several specific formatting rules:

  1. Preprocessor directives: Do not add spaces after the # symbol
  2. Indentation: Use consistent indentation sizes (e.g., 2 spaces for C/C++ files)
  3. Shell variables: Avoid wrapping variables in double quotes when it breaks parameter expansion
  4. String operations: Use concise operators and built-in language features over verbose alternatives
  5. Conditional operators: Prefer concise test operators (e.g., -n instead of ! -z)

Examples:

// Good - no space after #
#pragma warning(push)
#pragma GCC diagnostic push

// Bad - space after #
# pragma warning(push)
# pragma GCC diagnostic push
// Good - concise string concatenation
auto path = binary_directory + "/" + filename;

// Bad - verbose string construction  
auto path = binary_directory + std::string("/") + std::string(filename);
# Good - concise test operator
if [[ -n "$variable" ]]; then

# Bad - verbose test combination
if [[ ! -z "$variable" ]]; then

These formatting preferences improve code readability and maintain consistency across different languages and contexts in the codebase.


Clear accurate documentation

Documentation should be both technically accurate and contextually helpful for developers. Comments and JSDoc entries must correctly describe the behavior, purpose, and relationships of code elements.

Key practices:

Examples:

Instead of vague comments:

// keep this in sync with src/bun.js/bindings/webcore/JSReadableStream.cpp customInspect
// keep this in sync with src/bun.js/bindings/webcore/JSWritableStream.cpp customInspect

Use explanatory comments that convey purpose:

// These must match the order of the stateNames arrays in JSReadableStream.cpp and JSWritableStream.cpp

Instead of imprecise JSDoc:

/**
 * Local IP address connected to the socket
 * @example "192.168.1.100" | "2001:db8::1"
 */
readonly localFamily: string;

Use technically accurate descriptions:

/**
 * IP protocol family used for the local endpoint of the socket
 * @example "IPv4" | "IPv6"
 */
readonly localFamily: string;

defensive null handling

Use defensive programming patterns to prevent null-related issues before they occur. This includes creating safe object copies to prevent mutations, using explicit null/undefined checks, and initializing objects safely.

Key practices:

Example:

// Good - defensive copy prevents mutation
ObjectAssign(internals, { core, nodeGlobals: { ...nodeGlobals } });

// Good - explicit length check
const formattedMessage = message.length === 0 ? "" : `${message} `;

// Good - null prototype prevents pollution
attributes = { __proto__: null };

This approach prevents null reference errors, unintended mutations, and makes null handling intentions explicit in the code.


Cache repeated accesses

When accessing the same property or calling the same function multiple times, especially in loops or performance-critical sections, cache the result in a local variable. This reduces redundant memory access operations and improves execution speed.

Why it matters: Each property access or function call involves memory lookups and potentially complex operations. Repeating these unnecessarily can significantly impact performance in hot code paths.

Example - Before optimization:

// Repeated access to nested property in each loop iteration
for (int i = 0; i < sk_X509_num(default_ca_certificates->root_extra_cert_instances); i++) {
  X509 *cert = sk_X509_value(default_ca_certificates->root_extra_cert_instances, i);
  // Use cert...
}

Example - After optimization:

// Cache the property access before the loop
auto instances = default_ca_certificates->root_extra_cert_instances;
for (int i = 0; i < sk_X509_num(instances); i++) {
  X509 *cert = sk_X509_value(instances, i);
  // Use cert...
}

This technique is particularly important for:


Function invocation syntax

Use the appropriate invocation syntax for functions based on their intended usage. Regular functions should be called directly without the new keyword, while constructor functions (typically capitalized) should be instantiated with new.

Incorrect:

// Using constructor syntax with a regular function
const context2 = new vm.createContext(context);

Correct:

// Calling a regular function properly
const context2 = vm.createContext(context);

// Using constructor syntax with an actual constructor
const myDate = new Date();

This distinction is important for code correctness and readability. Using new with a non-constructor function can lead to unexpected behavior, while omitting new when required can cause the function to execute in the global context instead of creating a new object instance.


Platform-aware algorithm optimization

When implementing performance-critical algorithms, design your code to detect and utilize platform-specific hardware features while maintaining compatibility across different architectures. Create abstraction layers that allow the same algorithm to run on various platforms but take advantage of specialized instruction sets (like AVX extensions) when available.

For example, instead of directly using platform-specific code:

// Not recommended - tightly coupled to specific hardware
public void ProcessData(float[] data)
{
    if (Avx2.IsSupported)
    {
        // Use AVX2 instructions
    }
    else
    {
        // Fallback implementation
    }
}

Create a strategy pattern that selects the appropriate implementation:

// Recommended approach
public interface IDataProcessor
{
    void ProcessData(float[] data);
}

public class DataProcessorFactory
{
    public static IDataProcessor Create()
    {
        if (Avx2.IsSupported)
        {
            return new Avx2DataProcessor();
        }
        else if (Sse.IsSupported)
        {
            return new SseDataProcessor();
        }
        return new DefaultDataProcessor();
    }
}

This approach facilitates platform-specific optimizations while maintaining clean separation of concerns, makes testing easier, and allows for future extensions as new instruction sets become available.


Document function contracts

Always document function contracts completely, even when surrounding code lacks documentation. Include header comments that describe the function’s purpose and behavior, and explicitly specify preconditions using appropriate annotations (like PRECONDITION) to clarify execution requirements.

For example:

// Processes cross-component references during garbage collection
// Returns true if any references were processed
void Interop::TriggerClientBridgeProcessing(
    _In_ size_t sccsLen,
    _In_ StronglyConnectedComponent* sccs,
    _In_ size_t ccrsLen,
    _In_ ComponentCrossReference* ccrs)
{
    CONTRACTL
    {
        NOTHROW;
        GC_NOTRIGGER;
        PRECONDITION(g_GCBridgeActive && "Must be called during GC suspension");
    }
    CONTRACTL_END;
    
    // Implementation...
}

Clear function documentation improves code readability, facilitates maintenance, and helps other developers understand code execution requirements without having to trace through all callers. Even when existing code lacks proper documentation, always document new functions completely to establish better practices over time.


Optimize hot paths

Identify and optimize frequently executed code paths to improve performance. Hot paths have a significant impact on overall application performance.

Key strategies include:

  1. Use inline attributes for small functions: Add #[inline] to small functions called in performance-critical sections:
    #[doc(hidden)]
    #[inline]  // Added to improve inlining in hot paths
    pub fn has_budget_remaining() -> bool {
     // Function body
    }
    
  2. Implement early returns: Avoid unnecessary computation when a quick result is possible:
    pub fn poll_next_many(/* params */) -> Poll<usize> {
     if limit == 0 || self.entries.is_empty() {
         return Poll::Ready(0);  // Early return avoids unnecessary work
     }
     // Remaining logic
    }
    
  3. Reduce lock contention: Store frequently accessed constant data outside of locks:
    // Instead of obtaining a lock to read a constant value
    fn get_shard_size(&self) -> u32 {
     // Store this as a field instead of reading through a lock
     self.shard_count  // Direct field access instead of lock.read().len()
    }
    
  4. Minimize atomic operations: Evaluate whether atomic operations in hot paths can be avoided or optimized.

  5. Avoid generic code bloat: Extract non-generic operations into separate functions to prevent monomorphization bloat, especially in frequently used code:
    // Instead of using map with generic logic
    impl::spawn_child_with(&mut self.std, with)  // Direct function call
    

Each optimization may seem small individually, but they can significantly improve performance when applied to code that executes thousands or millions of times.


Add comprehensive test coverage

When adding functionality or fixing bugs, always add new test functions rather than modifying existing ones to preserve test coverage. Ensure comprehensive testing by including edge cases, error conditions, and assertions for all public functions. Use meaningful, non-default values in tests to improve sensitivity to regressions.

Key practices:

Example:

// Good: Adding new test function with comprehensive coverage
fn test_new_feature_success_case() {
    result := my_function(42) // Use meaningful non-zero value
    assert result == expected_value
}

fn test_new_feature_error_case() {
    if _ := my_function(-1) { 
        assert false 
    } else { 
        assert true 
    }
}

// Avoid: Modifying existing test functions or using only default values

This approach maintains existing test coverage while ensuring new functionality is thoroughly validated, making code reviews easier and preventing regressions.


Extract complex logical expressions

Complex logical expressions should be extracted into well-named variables or functions to improve code readability and maintainability. This applies to:

Example - Before:

const classOrInterfaceDeclaration = declaration.parent?.kind === SyntaxKind.Constructor && getSyntacticModifierFlags(declaration) & ModifierFlags.AccessibilityModifier ? declaration.parent.parent : declaration.parent;

Example - After:

const isConstructorParamWithAccessModifier = declaration.parent?.kind === SyntaxKind.Constructor && 
    getSyntacticModifierFlags(declaration) & ModifierFlags.AccessibilityModifier;
const classOrInterfaceDeclaration = isConstructorParamWithAccessModifier ? declaration.parent.parent : declaration.parent;

The extracted variable name should clearly describe the condition’s purpose. For frequently used conditions, consider extracting them into helper functions that can be reused across the codebase.


Choose efficient data structures

Select data structures and algorithms based on performance characteristics and actual usage patterns rather than convenience or familiarity. Consider memory efficiency, computational complexity, and scaling behavior when making implementation choices.

Key principles:

Example of efficient set implementation:

// Inefficient - stores redundant data
struct BadSet[T] {
mut:
    main_set map[T]T
}

// Efficient - minimal memory usage
struct GoodSet[T] {
mut:
    main_set map[T]bool
}

fn (g GoodSet[T]) elements() []T {
    return g.main_set.keys() // Use builtin method instead of manual iteration
}

Example of algorithm selection for duplicate removal:

// Inefficient for large datasets - O(n²) complexity
fn remove_duplicates_slow[T](arr []T) []T {
    mut results := []T{}
    for val in arr {
        if val !in results { // Linear search each time
            results << val
        }
    }
    return results
}

// Efficient - O(n) complexity
fn remove_duplicates_fast[T](arr []T) []T {
    mut seen := map[T]bool{}
    mut results := []T{}
    for val in arr {
        if !seen[val] {
            seen[val] = true
            results << val
        }
    }
    return results
}

Deterministic lock management

Always ensure locks are acquired and released in a deterministic manner in concurrent code. Use defer statements immediately after lock acquisition to guarantee release along all code paths, and acquire locks before accessing the protected resources to prevent race conditions.

Example of proper lock usage:

pub fn someOperation(self: *SomeStruct) void {
    self.mutex.lock();
    defer self.mutex.unlock();
    
    // If reference counting is involved, also defer the deref
    defer self.deref();
    
    // Access protected resources safely here...
    // All code paths will automatically release the lock
}

Incorrect pattern that can lead to race conditions:

// AVOID: Accessing protected data before acquiring the lock
var item = self.shared_map.get(key); // Race condition!
self.lock.lock();
// ... operations with item ...
self.lock.unlock();

Correct approach:

// CORRECT: Acquire lock first, then access protected data
self.lock.lock();
defer self.lock.unlock();
var item = self.shared_map.get(key); // Safe access
// ... operations with item ...

This pattern eliminates duplicate unlock calls along different code paths, prevents deadlocks, and ensures thread safety when accessing shared resources.


Optimize database interactions

When working with database operations, prioritize efficiency by avoiding redundant query executions. Instead of executing statements multiple times to gather different pieces of information (like metadata or column types), cache or collect all necessary data during the initial execution.

For example, when working with SQLite prepared statements and needing column types:

// Instead of this:
sqlite3_reset(stmt);
sqlite3_step(stmt);
// Now get column types...

// Do this:
// During initial execution:
if (sqlite3_step(stmt) == SQLITE_ROW) {
  // Store column types while processing the result
  for (int i = 0; i < columnCount; i++) {
    columnTypes[i] = sqlite3_column_type(stmt, i);
  }
  // Continue with normal row processing...
}

This approach is especially important for potentially expensive queries, as redundant executions can significantly impact performance. Additionally, when working with database APIs, be mindful of version-specific constants and methods (like SQLITE_TEXT vs. SQLITE3_TEXT), particularly in codebases that might interact with multiple versions of the same database system.


Validate buffer boundaries

When calling functions that process buffers, especially external C functions, always provide explicit buffer size parameters to prevent buffer overflow vulnerabilities. Buffer overflows are a common security vulnerability that can lead to memory corruption, unauthorized data access, and even remote code execution.

Example (incorrect):

const res = Bun__writeHTTPDate(buffer, timestampMs);

Example (secure):

const res = Bun__writeHTTPDate(buffer, buffer.len, timestampMs);

This is particularly critical for foreign function interface (FFI) calls where the called function may not implement its own buffer boundary checks. Always verify the expected parameters for external functions and ensure buffer lengths are explicitly passed to maintain security boundaries.


minimize memory allocations

Identify and eliminate unnecessary memory allocations in performance-critical code paths. This includes pre-allocating collections when the size is known, using static strings for common values, and avoiding intermediate data structures.

Key strategies:

Example from HTTP method handling:

// Instead of always allocating:
fn method_slow(method: &http::Method) -> String {
    method.to_string()  // Always allocates
}

// Use static strings for common cases:
fn method_fast(method: &http::Method) -> Cow<'static, str> {
    match *method {
        Method::GET => Cow::Borrowed("GET"),
        Method::POST => Cow::Borrowed("POST"),
        // ... other common methods
        _ => Cow::Owned(method.to_string()),
    }
}

This optimization is particularly important in hot code paths where even small allocations can compound into significant performance overhead. Always measure the impact, as the complexity trade-off should be justified by measurable performance gains.


Use backticks for identifiers

Wrap all code identifiers, method names, interface names, class names, and API references in JSDoc comments with backticks (`) for proper monospacing and improved readability.

This includes:

Example:

/**
 * The `EventListenerObject` interface represents an object that can handle events
 * dispatched by an `EventTarget` object.
 *
 * This interface provides an alternative to using a function as an event listener.
 * When implementing an object with this interface, the `handleEvent()` method
 * will be called when the event is triggered.
 */
interface EventListenerObject {
  handleEvent(evt: Event): void;
}

Instead of:

/**
 * The EventListenerObject interface represents an object that can handle events
 * dispatched by an EventTarget object.
 *
 * When implementing an object with this interface, the handleEvent() method
 * will be called when the event is triggered.
 */

This formatting convention ensures consistent documentation styling, improves code readability in generated documentation, and follows standard JSDoc best practices for technical documentation.


Judicious move semantics

Apply C++ move semantics and lambda modifiers only when necessary. The mutable keyword should only be used in lambdas when you need to modify captured variables, including when using move operations on them:

// Correct: mutable required for WTFMove(message)
context->postImmediateCppTask([protectedThis = Ref { *this }, message = WTFMove(message)](ScriptExecutionContext& ctx) mutable {
    // Using WTFMove(message) inside the lambda
});

// Incorrect: unnecessary mutable
context->postImmediateCppTask([protectedThis = Ref { *this }, message](ScriptExecutionContext& ctx) mutable {
    // No modification of captured variables
});

Similarly, avoid redundant moves on function objects unless there’s a specific rvalue ref-qualified overload of operator() you intend to call:

// Correct: Direct invocation
completionCallback();

// Unnecessary: redundant move
WTFMove(completionCallback)();

Using move operations judiciously improves code clarity and helps avoid subtle bugs related to object ownership.


Validate network inputs

Network code must validate all inputs and handle error conditions properly to prevent security vulnerabilities and reliability issues. This includes:

  1. Reset state between repeated network operations - especially in event loops where state changes with each iteration
  2. Use safe type conversions with explicit error handling
  3. Check buffer boundaries and protocol state

Example for select loops:

while (true) {
    // Reset state at beginning of each iteration
    FD_ZERO(&read_set);
    FD_SET(kqueue_fd, &read_set);
    for (size_t i = 0; i < fds_len; i++) {
        FD_SET(fds[i], &read_set);
    }
    
    int rv = select(max_fd + 1, &read_set, NULL, NULL, NULL);
    // Handle errors...
}

Example for type conversions in protocol handling:

// Use safe conversion with error handling
llhttp_type_t type = static_cast<llhttp_type_t>(typeValue.toNumber(globalObject));
RETURN_IF_EXCEPTION(scope, {});

Failing to properly validate network inputs can lead to subtle bugs like missed events in event loops, crashed servers due to unexpected input formats, or even security vulnerabilities that could be exploited by malicious actors.


Defensive error handling

Implement defensive checks when managing error state to prevent overwriting existing errors and add safeguards even when theoretically unnecessary. This approach helps avoid subtle bugs and makes code more robust against future modifications.

Key practices:

Example from the codebase:

// Before: Risk of overwriting existing error
if self.readMore() {
    goto try_skip
} else {
    err = SyntaxError{e, self.s, types.ParsingError(-s), ""}
    self.setErr(err)
    return
}

// After: Defensive check prevents overwriting
if self.readMore() {
    goto try_skip
}
if self.err == nil {
    self.setErr(SyntaxError{e, self.s, types.ParsingError(-s), ""})
}
return self.err

This defensive approach prevents losing important error context and makes the code more maintainable as it evolves.


Semantic over generic names

Choose specific, descriptive names that clearly convey purpose over generic or abbreviated identifiers. Names should be self-documenting and unambiguous about their role.

Key guidelines:

Example:

// Problematic - generic, unclear names
private int num;
private boolean type;
private String content;

// Better - specific, descriptive names
private int componentCount;
private boolean lastInFirstOutOrdering;
private String contentHeaderValue;

This practice improves code readability, reduces the need for additional documentation, and helps prevent misunderstandings during maintenance. When choosing names, consider whether another developer could understand the purpose without additional context.


Follow standard API specifications

Ensure API implementations strictly adhere to published specifications, even when adding features or optimizations. Deviating from standard behavior can create compatibility issues with other implementations (like Node.js) that rely on specification-compliant behavior.

When implementing web APIs:

  1. Refer directly to official specifications (WHATWG, W3C, ECMAScript) rather than copying other implementations
  2. Keep compatibility layers clearly separated from core spec implementation
  3. Document any intentional behavior differences

Example:

// INCORRECT: Adding non-standard behavior directly in core API implementation
void MessagePort::transfer() {
    // This behavior differs from spec - ports shouldn't be "closed" on transfer
    dispatchCloseEvent();
}

// CORRECT: Follow specification behavior
void MessagePort::transfer() {
    detachWithoutClosing(); // Aligns with spec: port is detached but not closed
}

// Alternative for compatibility needs
namespace CompatLayer {
    void handleMessagePortTransfer(MessagePort* port) {
        // Add Node.js specific behavior here if needed
    }
}

Names reveal semantic purpose

Choose names that clearly communicate the semantic purpose and behavior of code elements. Variable and function names should precisely reflect their role, return type, and intended usage.

Key guidelines:

  1. Function names should indicate their behavior and return type
  2. Use distinct names for related but different concepts
  3. Choose specific over generic names
  4. Fix misleading names immediately

Example:

// Poor naming
function isGlobalType(checker: TypeChecker, symbol: Symbol) {
    return checker.resolveName(symbol.name, undefined, SymbolFlags.Type, false);
}

// Better naming - reflects actual behavior
function canResolveTypeGlobally(checker: TypeChecker, typeName: string) {
    return checker.resolveName(typeName, undefined, SymbolFlags.Type, false);
}

// Poor naming - reusing variable
let initializer = getCandidateVariableDeclarationInitializer(declaration);
if (initializer) { ... }
initializer = getDestructuredInitializer(declaration);

// Better naming - distinct purposes
let directInit = getCandidateVariableDeclarationInitializer(declaration);
if (directInit) { ... }
let destructuredInit = getDestructuredInitializer(declaration);

organize code structure

Maintain clean code organization by moving implementation details to appropriate locations, extracting reusable functionality, and keeping related code together. This improves maintainability and prevents bugs from poor encapsulation.

Key practices:

Example of good organization:

// Instead of inline implementation details
pub async fn bundle() -> Result<(), AnyError> {
  // ... lots of esbuild setup code ...
}

// Extract to dedicated module
// bundle/esbuild.rs
pub async fn ensure_esbuild(...) -> Result<PathBuf, AnyError> {
  // esbuild-specific logic here
}

// bundle/mod.rs  
pub async fn bundle() -> Result<(), AnyError> {
  let esbuild_path = esbuild::ensure_esbuild(...).await?;
  // ... main bundling logic ...
}

This approach makes code easier to test, maintain, and understand by grouping related functionality and separating concerns.


Document non-obvious logic

Add clear comments explaining the purpose and reasoning behind complex or non-obvious code logic. Comments should explain ‘why’ certain implementation choices were made or how specific variables and conditions function, rather than just restating what the code does. This is especially important for security-related checks, timing mechanisms, interruption handling, and specialized attribute usage.

For example:

/* Tracks the starting time of the wait loop to calculate the remaining timeout
 * when re-entering the loop after an interruption. */
DWORD start_ticks = GetTickCount();

// OR

/* Skip inlining methods requiring security objects to prevent
 * security context bypass vulnerabilities */
if (target_method->flags & METHOD_ATTRIBUTE_REQSECOBJ) {
    return FALSE;
}

Use utility macros

Use predefined utility macros for common operations instead of repeating manual calculations throughout your code. This improves readability, consistency, and reduces the likelihood of errors in calculations.

For example, instead of manually calculating array sizes:

// Don't do this
if (wcsncmp(path, DevicePathPrefix, sizeof(DevicePathPrefix) / sizeof(WCHAR) - 1) == 0)
    return NULL;

// Do this instead
if (wcsncmp(path, DevicePathPrefix, STRING_SIZE(DevicePathPrefix) - 1) == 0)
    return NULL;

Check for existing utility macros in your project (such as ARRAY_SIZE, STRING_SIZE in util.h) before writing common calculations. This practice ensures consistent implementation across the codebase and makes future maintenance easier by centralizing any changes needed to these calculation patterns.


Use appropriate error types

Functions should use specific, appropriate error handling mechanisms rather than generic or brittle approaches. This includes returning proper error codes when operations fail, using specific error types instead of generic notImplemented errors, and avoiding fragile error detection methods like string matching.

Key practices:

Example of improvement:

// Instead of always returning success:
setBroadcast(_bool: 0 | 1): number {
  this.#listener?.setBroadcast(_bool === 1);
  return 0; // Always success - problematic
}

// Return appropriate error codes:
setBroadcast(_bool: 0 | 1): number {
  try {
    this.#listener?.setBroadcast(_bool === 1);
    return 0;
  } catch {
    return -1; // Proper error indication
  }
}

// Instead of generic errors:
export function setFipsCrypto(_fips: boolean) {
  notImplemented("crypto.setFipsCrypto"); // Generic
}

// Use specific error types:
export function setFipsCrypto(_fips: boolean) {
  throw new Error("FIPS mode is not available"); // Specific
}

Parameterize configuration values

Extract hard-coded configuration values into variables, parameters, or templates to improve reusability and simplify maintenance. When the same value is used in multiple places or might need to change in the future, define it once and reference it throughout your configuration files.

Examples:

  1. For build scripts with multiple parameters: ```yaml

    Instead of:

    • script: make run TARGET_ARCH=arm64 DEPLOY_AND_RUN=false RUNTIME_FLAVOR=CoreCLR STATIC_LINKING=true

Use:

  1. For repeated configuration values: ```yaml

    Define once:

    variables: timeoutPerTestCollection: 180

Reference where needed:

jobParameters: timeoutInMinutes: ${{ variables.timeoutPerTestCollection }}


This practice reduces duplication, centralizes configuration management, and makes future updates more efficient and less error-prone.


---

## remove unnecessary prefixes

<!-- source: denoland/deno | topic: Code Style | language: Css | updated: 2025-05-29 -->

Remove vendor prefixes from CSS properties that have achieved sufficient browser support across modern browsers. Before removing prefixes, verify browser compatibility using resources like MDN documentation to ensure the unprefixed property is well-supported.

This practice improves code readability, reduces maintenance overhead, and eliminates redundant code. Focus on commonly supported properties that no longer require vendor-specific implementations.

Example cleanup:
```css
/* Before - unnecessary prefixes */
*:before {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

pre {
  -moz-tab-size: 2;
  -o-tab-size: 2;
  tab-size: 2;
}

/* After - clean, modern CSS */
*:before {
  box-sizing: border-box;
}

pre {
  tab-size: 2;
}

Network API compatibility

When implementing networking APIs that mirror Node.js functionality, ensure both behavior and error patterns match Node.js exactly. This is critical for maintaining compatibility with the Node.js ecosystem and ensuring that code works consistently across both environments.

Key areas to check for compatibility include:

For example, when validating TLS ciphers, ensure the logic matches Node.js behavior by only throwing when no ciphers match (not when any individual cipher is unsupported):

// INCORRECT - throws if any cipher isn't supported
const requested = options.ciphers.split(":");
for (const r of requested) {
  if (!DEFAULT_CIPHERS_SET.has(r)) {
    throw $ERR_SSL_NO_CIPHER_MATCH();
  }
}

// CORRECT - matches Node.js behavior by only throwing if no ciphers match
const requested = options.ciphers.split(":");
let hasMatch = false;
for (const r of requested) {
  if (DEFAULT_CIPHERS_SET.has(r)) {
    hasMatch = true;
    break;
  }
}
if (!hasMatch) {
  throw $ERR_SSL_NO_CIPHER_MATCH();
}

Always reference the Node.js implementation when implementing networking APIs to ensure consistent behavior across runtime environments.


Thread-safe state transitions

When modifying shared state in multithreaded code, implement proper checks and state transitions to prevent race conditions. This applies to flags, counters, and resource management.

  1. Use atomic operations when checking and modifying shared state
  2. Check state values after atomic operations rather than before
  3. For multi-step processes, track in-flight operations and only perform final state transitions when all operations are complete

Bad:

// Don't check flags without thread safety
if (m_terminationFlags & TerminatedFlag) {
    // Already terminated, skip work
    return;
}
// Race condition: Another thread might have set the flag between check and action

Good:

// Use atomic operations and check the return value
if (atomic_fetch_or(&m_terminationFlags, TerminatedFlag) & TerminatedFlag) {
    // Already terminated, skip work
    return;
}

// For multi-step processes, track completion:
protectedThis->m_messagesInFlight -= 1;
if (protectedThis->m_messagesInFlight == 0)
    protectedThis->close(); // Only close when all messages are processed

Enable configurable instrumentation

Always provide configurable options for performance instrumentation and hardware acceleration in your codebase. These options should be clearly documented and defaulted appropriately for common scenarios.

For hardware optimizations:

// Good example:
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableAVXVNNIINT8, W("EnableAVXVNNIINT8"), 1, "Allows AVXVNNI8+ hardware intrinsics to be disabled")

For performance measurement:

<NestedBuildProperty Include="WasmEnableEventPipe" />
<NestedBuildProperty Include="WasmPerformanceInstrumentation" />

Implementing configurable performance options allows teams to make data-driven optimization decisions and tailor application behavior to specific deployment environments.


Consistent dependency declarations

Ensure dependency declarations in build configuration files use concrete values rather than variables that may not resolve properly at build time. Maintain consistency between related configuration files (like BOM and aggregator POMs) to prevent build failures.

When declaring dependencies in Maven POM files:

  1. Avoid using variables in dependency declarations that rely on runtime detection (like ${os.detected.classifier})
  2. Ensure dependencies are consistently declared across related configuration files
  3. Consider using Maven Enforcer’s requireSameVersions rule for critical dependencies

Example of problematic configuration:

<dependency>
  <groupId>${project.groupId}</groupId>
  <artifactId>${tcnative.artifactId}</artifactId>
  <classifier>${tcnative.classifier}</classifier>
</dependency>

This can result in errors like:

Could not find netty-tcnative-2.0.70.Final-${os.detected.classifier}.jar

Instead, use concrete values or handle platform-specific dependencies using proper Maven features like profiles or separate platform-specific modules.


Document configuration variations

When documenting or implementing configuration options, always include variations needed for different environments and use cases. Ensure that your configuration files, installation guides, and rule definitions cover all common scenarios.

For installation instructions, include platform-specific commands and hardware variations:

# Standard installation
winget install Oven-sh.Bun

# For CPUs without AVX2 instruction set support
winget install Oven-sh.Bun.Baseline

For rule definitions and pattern matching, include all relevant files:

globs: *.ts, *.tsx, *.html, *.css, *.js, *.jsx, package.json

This ensures users can successfully set up and use the system regardless of their specific environment, and automation tools will properly process all configuration files.


Improve code clarity

Write code that clearly expresses intent through explicit patterns, simplified logic, and readable structure. Avoid unnecessary complexity that obscures the code’s purpose.

Key practices:

Example of improvement:

// Before: verbose and nested
pub fn (s Status) is_success() bool {
    if s.status.is_success() {
        return true
    } else {
        return false
    }
}

// After: clear and direct  
pub fn (s Status) is_success() bool {
    return s.status.is_success()
}

This approach makes code easier to read, understand, and maintain by reducing cognitive load and making intentions explicit.


Cross-platform configuration examples

Ensure configuration examples and documentation work across different operating systems and clearly distinguish between required and optional configuration steps. Avoid platform-specific syntax that may not work universally, and explicitly state when configuration steps are optional versus mandatory.

When providing path examples in configuration files, use universally supported formats:

{
  "parser-directories": [
    "~/src",
    "$HOME/dev",
    "/Users/my-name/code"
  ]
}

Use plain ~ instead of ~username syntax, as the latter doesn’t work on all systems. For optional build or setup steps, clearly indicate their optional nature and explain the implications of skipping them:

Optionally, build the WASM library. If you skip this step, then the `tree-sitter web-ui` command will require an internet connection.

This prevents developers from encountering platform-specific failures and helps them make informed decisions about which configuration steps to include in their setup.


Memory barrier pairing

When implementing low-level synchronization mechanisms in multi-threaded code, ensure that memory barriers are correctly paired between reader and writer operations. For each read barrier, implement a corresponding write barrier to maintain memory consistency and prevent race conditions.

For example, in ARM64 assembly:

// Read side
dmb ishld   // Data memory barrier for load operations

// Write side (corresponding barrier needed)
dmb ishst   // Data memory barrier for store operations

Consider whether specialized atomic instructions (like ldar for loads or stlr for stores) might provide the same memory ordering guarantees with potentially better performance in specific scenarios. However, ensure these are implemented at the correct locations in the code to properly maintain the synchronization semantics.


Structure feature flags strategically

Design feature flags to minimize dependency bloat while maximizing flexibility for users. Each optional dependency should be tied to a specific feature flag, allowing users to enable only the functionality they need.

Key practices:

  1. Express dependencies between features explicitly in Cargo.toml
  2. Create granular feature flags for optional dependencies
  3. Use conditional compilation for platform or feature-specific code
  4. Consider feature organization when adding new functionality

For example, instead of requiring a dependency for all users:

# Avoid this approach - forces dependency on all users
rt = ["tokio/rt", "tokio/sync", "futures-util", "hashbrown"]

Use a more targeted approach:

# Better approach - separate optional functionality
rt = ["tokio/rt", "tokio/sync", "futures-util"]
join-map = ["rt", "hashbrown"]

For platform-specific features, use appropriate conditional compilation:

# For platform-specific features
[target.'cfg(all(target_os = "linux", feature = "rt"))'.dependencies]
# Linux-specific dependencies here

When organizing features, aim for a balance between granularity and usability, with a “full” feature that enables everything for convenience.


Preserve backward compatibility

When evolving APIs in minor versions, always maintain backward compatibility to avoid breaking client code. Follow these principles:

  1. Don’t add abstract methods to existing interfaces or abstract classes. Instead, provide default implementations:
// AVOID (breaking change):
public interface EventExecutorGroup {
    long submittedTasks(); // New abstract method breaks implementing classes
}

// BETTER:
public interface EventExecutorGroup {
    // Default implementation preserves compatibility
    default long submittedTasks() {
        return -1; // Indicates metric not supported
    }
}
  1. Implement missing abstract methods when adding them to existing classes:
// AVOID (breaking change):
public abstract String readString(int length, Charset charset);

// BETTER:
public String readString(int length, Charset charset) {
    String string = toString(readerIndex(), length, charset);
    skipBytes(length);
    return string;
}
  1. Deprecate methods before removing them in major versions, with clear migration paths:
@Deprecated
public static ZlibDecoder newZlibDecoder() {
    return newZlibDecoder(0); // Forward to newer method
}

public static ZlibDecoder newZlibDecoder(int maxAllocation) {
    // New implementation with additional parameter
}
  1. Maintain consistent deprecation across related methods, constructors, and classes. When deprecating a method, also deprecate related methods and constructors that would become inconsistent.

Following these principles ensures your API evolves cleanly without disrupting existing users, allowing them to migrate at their own pace.


Simplify configuration flags

Keep configuration flags, feature toggles, and build settings concise and well-organized. Use simpler names where appropriate and consolidate related flags when possible to improve readability and maintainability.

When defining new configuration flags:

Example of simplifying multiple flags:

# Before: Multiple separate flags
- RUSTFLAGS: -Dwarnings --check-cfg=cfg(loom) --check-cfg=cfg(tokio_unstable) --check-cfg=cfg(tokio_taskdump) --check-cfg=cfg(fuzzing)

# After: Consolidated flags
+ RUSTFLAGS: -Dwarnings --check-cfg=cfg(loom, tokio_unstable, tokio_taskdump, fuzzing)

For feature flags and conditional compilation:

# Before: Verbose, redundant naming
- --cfg tokio_unstable_uring

# After: Simplified naming
+ --cfg tokio_uring

This approach makes configuration more maintainable, reduces verbosity, and improves readability, especially as the number of configuration options grows over time.


Preserve pointer authentication

When implementing Pointer Authentication (PAC) for security, maintain signed pointers throughout their entire lifecycle to prevent potential security vulnerabilities. Avoid unnecessarily stripping PAC signatures from pointers that will be stored and later reused. This preserves the security guarantees that PAC is designed to provide.

For example, when storing a return address:

// AVOID: Stripping signature before storage creates a security hole
m_pvHJRetAddr = PacStripPtr(m_pvHJRetAddr);

// BETTER: Store the signed pointer to maintain protection
m_pvHJRetAddr = originalSignedPointer;
// Only strip when absolutely necessary for processing
void* strippedForProcessing = PacStripPtr(m_pvHJRetAddr);

This approach ensures that any attempt to manipulate the stored address would fail authentication when the pointer is eventually used, significantly reducing the attack surface against return-oriented programming (ROP) attacks. When you do need to strip the signature for processing, limit the scope of the unsigned pointer and avoid storing it in a longer-lived variable or memory location.


explicit null checks

Always verify that pointers and function return values are not null before dereferencing or using them. This prevents crashes and undefined behavior, especially when working with C functions or manual memory management.

Key practices:

Example from discussions:

// Bad: No null check for C function return
display := C.XOpenDisplay(0)
// Immediate use without verification

// Good: Check for null return
display := C.XOpenDisplay(0)
if display == unsafe { nil } {
    return error('Failed to open display')
}
defer { C.XCloseDisplay(display) }

This practice is essential for robust code that interfaces with C libraries or manages pointers manually.


Use descriptive identifiers

Choose names that clearly communicate the purpose, functionality, and usage context of variables, methods, and types. Avoid ambiguous or overly generic names that require additional context to understand.

When naming:

Example from codebase:

// Instead of unclear property access:
if (this[kStreamBaseField]![_readCancel]) {

// Use descriptive method name:
if (this[kStreamBaseField]!.readWithCancelHandle()) {

Good naming reduces the need for comments and makes code self-documenting, improving maintainability and reducing cognitive load for other developers.


Enable header validation

Always enable HTTP header validation to prevent request/response splitting vulnerabilities. These attacks can occur when untrusted data containing CRLF sequences is inserted into HTTP headers, allowing attackers to inject additional headers or even response body content.

When creating HTTP headers in Netty, avoid disabling the validation parameter:

// INSECURE: Disabled header validation
HttpHeaders inHeaders = new DefaultHttpHeaders(false);

// SECURE: Keep validation enabled (default)
HttpHeaders inHeaders = new DefaultHttpHeaders(); 
// or explicitly
HttpHeaders inHeaders = new DefaultHttpHeaders(true);

Even in test code, prefer to use valid headers rather than disabling validation. If you absolutely must test with invalid headers, isolate this code and clearly document the security implications with comments.

Request/response splitting attacks can lead to cache poisoning, XSS, and session fixation. Modern browsers and servers have some protections against these attacks, but proper header validation remains an important security defense-in-depth measure.


Verify cryptographic function behavior

When implementing cryptographic algorithms, always verify the exact behavior and return values of security-critical functions. Misinterpreting how functions signal success or equality can lead to severe security vulnerabilities.

In particular:

Example of a potential error in a security check:

// INCORRECT: Misinterpreting constantTimeMemcmp which returns 0 for equality
if (derivedKey->size() != expectedOutputSize || !constantTimeMemcmp(derivedKey->span(), zeros)) {
    // Handle insecure all-zeros key case
}

// CORRECT: Properly checking for equality with constantTimeMemcmp
if (derivedKey->size() != expectedOutputSize || constantTimeMemcmp(derivedKey->span(), zeros) == 0) {
    // Handle insecure all-zeros key case
}

Security-critical checks must be implemented correctly the first time - cryptographic vulnerabilities can be subtle and devastating.


Optimize algorithmic complexity

Always consider the time and space complexity implications of your code. Choose data structures and algorithms that minimize computational overhead and memory usage for your specific use cases.

Watch for hidden complexity issues:

  1. Avoid nested iterations that create O(n²) behavior

    // Poor: Iterates through all buffers on each call, potentially O(n²) in a loop
    let n = bufs.iter().map(|b| b.len()).sum::<usize>().min(MAX_BUF);
       
    // Better: Calculate incrementally inside a loop to maintain O(n) complexity
    let mut remaining = MAX_BUF;
    let mut total = 0;
    for buf in bufs {
        let to_copy = buf.len().min(remaining);
        total += to_copy;
        remaining -= to_copy;
        if remaining == 0 {
            break;
        }
    }
    
  2. Choose efficient operations over expensive ones

    // Poor: Using power operation which is more expensive
    let max_number = 2u64.saturating_pow((8 * length_field_len - 1) as u32);
       
    // Better: Using bit shift which is much faster
    let max_number = match 1.checked_shl(8 * length_field_len) {
        Some(shl) => shl - 1,
        None => u64::MAX,
    };
    
  3. Design for fairness when consuming from multiple sources

    // When polling multiple streams, implement rotation strategies to ensure 
    // fair processing and prevent starvation:
    let mut added = 0;
    let mut start = thread_rng_n(entries.len() as u32) as usize;
       
    while added < limit {
        match self.poll_one(cx, start) {
            Poll::Ready(Some((idx, val))) => {
                added += 1;
                // Move the start index to ensure fair rotation
                start = idx.wrapping_add(1) % entries.len();
                // Process val...
            }
            _ => break,
        }
    }
    
  4. Use iterators over index-based access when appropriate

    // Poor: Using index-based access in a loop
    let expiration_time = (0..wheel_count)
        .filter_map(|id| wheel.get_sharded_wheel_mut(id).next_expiration_time())
        .min();
       
    // Better: Using iterator methods directly on the collection
    let expiration_time = wheels.iter_mut()
        .filter_map(|wheel| wheel.next_expiration_time())
        .min();
    
  5. Avoid code duplication that leads to excessive monomorphization

    // Poor: Duplicating implementation for each function call type
    pub fn with_func1(cmd: &mut Cmd, with: impl Fn(&mut Cmd) -> Result<Child>) -> Result<Child> {
        // Duplicated implementation
    }
       
    // Better: Extract common logic to avoid recompiling the same code
    pub fn with_func(cmd: &mut Cmd, with: impl Fn(&mut Cmd) -> Result<Child>) -> Result<Child> {
        handle_common(&mut with(cmd)?)
    }
       
    fn handle_common(child: &mut Child) -> Result<Child> {
        // Common implementation that won't be duplicated
    }
    

By paying attention to these efficiency concerns, you’ll produce code that scales better and uses resources more efficiently.


Use Option methods idiomatically

When dealing with Optional values, prefer Rust’s built-in Option methods over manual null checks. This makes code more concise, self-documenting, and less error-prone by leveraging Rust’s type system to enforce null safety at compile time.

For optional value checking:

// Instead of:
if self.processing_scheduled_tasks_started_at.is_some() {
    let busy_duration = self.processing_scheduled_tasks_started_at.unwrap().elapsed();
    // Use busy_duration...
}

// Use:
if let Some(processing_scheduled_tasks_started_at) = self.processing_scheduled_tasks_started_at {
    let busy_duration = processing_scheduled_tasks_started_at.elapsed();
    // Use busy_duration...
}

For lazy initialization:

// Instead of:
if me.entry.is_none() {
    let entry = TimerEntry::new(me.handle, deadline);
    me.entry.as_mut().set(Some(entry));
}

// Use:
let entry = me.entry.get_or_insert_with(|| TimerEntry::new(me.handle, deadline));

For error handling with Option:

// Instead of:
let n = match u32::try_from(n) {
    Ok(n) => n,
    Err(_) => return None,
};

// Use:
let n = u32::try_from(n).ok()?;

Write focused single-purpose tests

Break down large test cases into smaller, focused tests that each verify a single feature or behavior. Each test should have a clear purpose that is evident from its name and structure. This improves test maintainability, readability, and makes failures easier to debug.

Instead of combining multiple test cases:

#[test]
fn test_channel_behavior() {
    let (tx, rx) = channel();
    // Test multiple behaviors...
    assert!(rx.is_empty());
    tx.send(1).unwrap();
    assert!(!rx.is_empty());
    drop(tx);
    assert!(rx.is_closed());
}

Break it into focused tests:

#[test]
fn is_empty_returns_true_initially() {
    let (_, rx) = channel();
    assert!(rx.is_empty());
}

#[test]
fn is_empty_returns_false_after_send() {
    let (tx, rx) = channel();
    tx.send(1).unwrap();
    assert!(!rx.is_empty());
}

#[test]
fn is_closed_returns_true_after_sender_drop() {
    let (tx, rx) = channel();
    drop(tx);
    assert!(rx.is_closed());
}

Key benefits:


Export environment variables once

When writing shell scripts, set and export all environment variables at the top of the script rather than modifying them repeatedly throughout the script. This improves readability, maintainability, and prevents inconsistent environments between commands.

For tools like Node.js or npm, prefer using local installations over globally installed versions by explicitly setting paths to include local tool directories:

# Instead of:
NODEPATH="$(../$NODE -p 'require("path").resolve("..")')"
PATH="$NODEPATH:$PATH" ../$NODE cli.js install --ignore-scripts
PATH="$NODEPATH:$PATH" ../$NODE test/run.js

# Do this:
NODEPATH="$(../$NODE -p 'require("path").resolve("..")')"
export PATH="$NODEPATH:$PATH"
../$NODE cli.js install --ignore-scripts
../$NODE test/run.js

# Or even better, if appropriate:
export PATH="$(../$NODE -p 'require("path").resolve("..")'):$PATH"
../$NODE cli.js install --ignore-scripts
../$NODE test/run.js

This approach ensures consistent access to required tools across the entire script and makes changes easier to implement when needed.


Configurable over hardcoded

Make configuration parameters configurable rather than hardcoding values, especially for limits, sizes, and thresholds. Provide reasonable defaults but allow users to override through:

  1. Constructor parameters for instance-specific configuration
  2. System properties for application-wide defaults
  3. Public accessor methods for runtime feature detection

For related configuration parameters, design APIs that ensure they are set cohesively to prevent invalid states:

// Prefer this:
public IoUringIoHandlerConfig setSize(int ringSize, int cqSize) {
    // validate interdependent parameters together
    return this;
}

// Over separate methods that could create invalid configurations:
public IoUringIoHandlerConfig setRingSize(int ringSize) { ... }
public IoUringIoHandlerConfig setCqSize(int cqSize) { ... }

When exposing configuration capabilities, make feature detection methods public to help users adapt to different environments:

if (IoUring.isRecvMultishotEnabled()) {
    // Use optimized configuration
}

Size-related parameters should be derived from existing configurations when reasonable rather than using arbitrary hardcoded values.


prefer safe optional returns

When designing APIs and handling potentially missing or unavailable values, prefer returning optional types (Option, Result<T, E>) over operations that can panic or fail unsafely. This promotes defensive programming and null safety.

Key practices:

Example from the discussions:

// Instead of this (can panic if plugin changes):
_ => unreachable!(),

// Prefer this (safe fallback):
_ => None,

// For platform-specific values:
// Instead of: Result<(ResourceId, IpAddr, IpAddr, Fd), NetError>
// Use: Result<(ResourceId, IpAddr, IpAddr, Option<Fd>), NetError>

// Handle errors instead of panicking:
// Instead of: parsed_source.specifier().to_file_path().unwrap()
// Use proper error handling with Result types

This approach makes code more robust, prevents runtime panics, and clearly communicates when values might be absent through the type system.


Add comprehensive test coverage

Ensure that all functionality, especially complex or quirky features, has corresponding unit tests. When adding new features or modifying existing code, proactively identify areas that lack test coverage and add appropriate tests.

This is particularly important for:

For example, when adding flag parsing functionality:

#[test]
fn test_clean_command_parsing() {
  // Test basic clean command
  let mut flags = Flags::default();
  let matches = /* create test matches */;
  clean_parse(&mut flags, &matches);
  assert_eq!(flags.subcommand, DenoSubcommand::Clean);
}

#[test] 
fn test_clean_command_with_options() {
  // Test clean command with various options
  // ...
}

Or for utility functions:

#[test]
fn test_url_to_uri_conversion() {
  // Test various URL formats
  assert_eq!(url_to_uri(&url).unwrap(), expected_uri);
}

Don’t assume that functionality is “too simple” to test - utility functions, parsing logic, and similar features across a codebase should all have comprehensive test coverage to prevent regressions and ensure correctness.


Choose appropriate algorithms

When implementing functionality, carefully evaluate different algorithmic approaches and data structures to choose the most appropriate solution. Consider factors like performance requirements, correctness, maintainability, and whether existing libraries can be leveraged instead of custom implementations.

Key considerations:

Example from the codebase:

// Instead of custom version parsing:
struct VersionParts {
  major: u64,
  minor: u64, 
  patch: u64,
  pre: Option<String>,
}

// Consider using existing library:
// Should we be using `deno_semver::Version` here?
use deno_semver::Version;

This approach reduces bugs, improves maintainability, and often provides better performance than ad-hoc implementations.


Document public APIs

All public-facing APIs must be thoroughly documented with clear javadocs. This includes:

  1. Classes and interfaces: When creating or changing a class/interface to public visibility, add comprehensive documentation explaining its purpose and usage.

  2. Methods and constructors: Document each public method and constructor, including:
    • Method purpose
    • Parameter descriptions and constraints
    • Return value meaning
    • Any exceptions that may be thrown
  3. Deprecated functionality: Always add @deprecated tags with explanations of what alternatives users should use instead.

Example of proper documentation:

/**
 * Decodes DNS response messages into {@link DnsResponse} objects.
 * <p>
 * This decoder supports both UDP and TCP transport protocols for DNS messages.
 * When using TCP, DNS messages are prefixed with a 2-byte length field.
 *
 * @param <A> The type of address used by the decoder (e.g., {@link java.net.InetSocketAddress})
 */
public abstract class DnsResponseDecoder<A extends SocketAddress> {

    /**
     * Decodes a DNS response message with the specified maximum allocation limit.
     *
     * @param maxAllocation The maximum allowed memory allocation per message in bytes.
     *                     A value of 0 means no limit.
     * @return A {@link DnsDecoder} instance with the specified allocation limit
     * @throws IllegalArgumentException if maxAllocation is negative
     */
    public static DnsDecoder newDnsDecoder(int maxAllocation) {
        // implementation
    }
    
    /**
     * @deprecated Use {@link #newDnsDecoder(int)} instead with an appropriate allocation limit
     */
    @Deprecated
    public static DnsDecoder newDnsDecoder() {
        return newDnsDecoder(0);
    }
}

Remember that clear documentation helps maintainers understand code intent, improves API usability for consumers, and prevents future bugs from misunderstandings about component behavior.


Document configuration changes

When modifying configuration files (tsconfig.json, environment configs, build settings, etc.), always provide clear explanations for why the changes are necessary, what benefits they provide, and any potential impacts. Configuration changes can significantly affect build processes, development workflows, and application behavior, so reviewers and future maintainers need to understand the reasoning behind modifications.

Include explanations either in:

Example from TypeScript configuration:

{
  "compilerOptions": {
    // Enable composite mode for faster incremental builds with tsc --build
    "composite": true,
    // Ensure each file can be transpiled independently for bundlers like esbuild
    "isolatedModules": true
  },
  "include": [
    "src/**/*",
    // Include lib directory to ensure web-tree-sitter.d.ts is type-checked during builds
    "lib/**/*.ts"
  ]
}

This practice helps prevent confusion during code reviews and provides valuable context for future configuration maintenance.


Document network APIs comprehensively

Network APIs and interfaces should include comprehensive documentation with clear descriptions, practical examples, and proper configuration guidance. This is especially important for complex protocols like WebSockets, HTTPS, and specialized network transports.

When documenting network APIs:

Example of comprehensive network API documentation:

/**
 * Returns the extensions selected by the server, if any.
 *
 * WebSocket extensions add optional features negotiated during the handshake via
 * the `Sec-WebSocket-Extensions` header.
 *
 * At the time of writing, there are two registered extensions:
 * - `permessage-deflate`: Enables per-message compression using DEFLATE
 * - `bbf-usp-protocol`: Used by the Broadband Forum's User Services Platform
 *
 * Example:
 * ```ts
 * const ws = new WebSocket("ws://localhost:8080");
 * console.log(ws.extensions); // e.g., "permessage-deflate"
 * ```
 */
readonly extensions: string;

This approach helps developers understand not just how to use network APIs, but also the underlying protocols and proper configuration patterns.


Granular feature flags

Feature flags should be designed with granularity to ensure dependencies are only required when absolutely necessary. When adding functionality that requires additional dependencies, create separate features rather than adding those dependencies to existing features.

Key principles:

  1. Make dependencies optional whenever possible
  2. Create dedicated features for functionality requiring specific dependencies
  3. Consider feature dependencies carefully to avoid unnecessary inclusions
  4. Disable default features of dependencies when only specific functionality is needed

Example:

# GOOD: Granular feature with minimal dependencies
[features]
rt = ["tokio/rt", "tokio/sync", "futures-util"]
join-map = ["rt", "hashbrown"]  # Separate feature for hashbrown dependency

# BAD: Requiring hashbrown for all rt users
[features]
rt = ["tokio/rt", "tokio/sync", "futures-util", "hashbrown"]

This approach keeps the dependency tree minimal for users who don’t need specific functionality, improving compile times and reducing potential version conflicts. When considering target-specific configurations, ensure dependencies are properly scoped to the relevant target and features (e.g., #[cfg(all(target_os = "linux", feature = "rt"))]).


Cache expensive computed values

Cache frequently accessed or computed values to avoid redundant calculations and property lookups. This applies to:

  1. Loop invariant values
  2. Expensive computations
  3. Repeated property access
  4. Function call results

Example - Before:

while (index < path.length) {
    // path.length accessed on every iteration
    if (path.indexOf(separator, index) !== -1) {
        // indexOf called multiple times
    }
}

Example - After:

const pathLength = path.length; // Cache loop invariant
const separatorIndex = path.indexOf(separator, index); // Cache computation
while (index < pathLength) {
    if (separatorIndex !== -1) {
        // Use cached values
    }
}

This optimization is particularly important in performance-critical paths and loops. When implementing, consider:

The performance impact can be significant, especially when the cached values are used frequently or the computations are expensive.


Use standard API interfaces

Always prefer established API interfaces and patterns over custom or alternative approaches. This ensures compatibility, maintainability, and follows expected conventions.

For module imports, use standard ESM syntax instead of dynamic loading:

// Preferred
import { assert } from "node:assert";

// Avoid
const assert = process.getBuiltinModule("node:assert");

For server interfaces, follow the established contract structure:

// Preferred
export default {
  fetch(req: Request) {
    return new Response("Hello from declarative server");
  },
  onListen(info) {
    console.log(info);
  }
} satisfies Deno.ServeDefaultExport;

// Avoid
export const fetch = (req: Request) => {
  return new Response("Hello from declarative server!");
};

This approach ensures your code works with existing tooling, follows documented patterns, and reduces the risk of breaking changes when alternative methods are deprecated.


optimize memory usage patterns

Focus on reducing memory footprint and improving cache efficiency through careful data structure design and function parameter optimization. Consider using smaller data types when the value range permits, and design function interfaces to minimize memory overhead.

Key strategies include:

Example: Instead of using Array(TSQuantifier) which may use 4 bytes per element, consider Array(uint8_t) and cast to TSQuantifier when reading, reducing memory usage by 75% when the enum values fit in a byte. Similarly, prefer passing buffer parameters directly rather than relying on global transfer buffers to improve function interface efficiency.


avoid tooling workarounds

Avoid code patterns that require workarounds for tooling limitations or create maintenance burdens. This includes using contextual keywords as identifiers that cause formatter edge cases, and relying on @ts-ignore comments to suppress type checking.

Instead of working around tooling issues, prefer patterns that work naturally with the development environment:

For example, instead of:

// Workaround: rename "from" to avoid formatter issues
const renameForDefaultExport = ["from"];

// @ts-ignore Undocumented function
someUndocumentedFunction();

Prefer:

// Use clear, non-conflicting names
const renameForDefaultExport = ["fromKeyword"];

// Properly type or restructure instead of ignoring
someDocumentedFunction();

This approach reduces technical debt, improves code maintainability, and prevents future issues when tooling is updated.


Optimize algorithmic efficiency

Pay careful attention to operations inside loops and recursive functions to avoid unexpected algorithmic complexity. Be particularly vigilant about:

  1. Hidden O(n²) operations: Avoid operations that iterate over entire collections inside loops, as they can degrade performance significantly.
// Poor performance: iterates through all buffers on each call
let n = bufs.iter().map(|b| b.len()).sum::<usize>().min(MAX_BUF);

// Better approach: avoid recomputing the total length repeatedly
let mut total = 0;
for buf in bufs {
    total += buf.len();
    if total >= MAX_BUF {
        total = MAX_BUF;
        break;
    }
}
  1. Prefer efficient bit operations: Use shifts, masks, and other bit-level operations instead of more expensive calculations when possible.
// Expensive calculation using power
let max_number = 2u64.saturating_pow((8 * length_field_len - 1) as u32);
max_number + (max_number - 1);

// More efficient using bit shift
let max_number = match 1.checked_shl(8 * length_field_len) {
    Some(shl) => shl - 1,
    None => u64::MAX,
}
  1. Reduce monomorphization bloat: Extract type-independent logic into separate functions to avoid code duplication across different type instantiations.
// Separate logic into non-generic helper function
pub(crate) fn spawn_child_with(
    cmd: &mut StdCommand,
    with: impl Fn(&mut StdCommand) -> io::Result<StdChild>,
) -> io::Result<SpawnedChild> {
    spawn_child(&mut with(cmd)?)
}

fn spawn_child(cmd: &mut StdChild) -> io::Result<SpawnedChild> {
    // Common implementation that won't be duplicated
}
  1. Use specialized methods: Many standard library types offer specialized methods that are more efficient than general-purpose approaches.
// Less efficient with multiple operations
if now > timeout.checked_add(Duration::from_millis(5)).unwrap_or_else(Instant::far_future) {
    // Handle case
}

// More efficient using a specialized method
if now.saturating_duration_since(timeout) > Duration::from_millis(5) {
    // Handle case
}

These optimizations matter most in hot code paths, libraries meant for wide adoption, or when handling large data structures.


Minimize unnecessary work

Optimize performance by reducing the amount of computation performed, especially on data that won’t appear in the final result. Apply these strategies:

1) Filter early: Filter collections before performing expensive transformations like sorting

// Suboptimal: Sorts all elements, then removes private ones
functions.sortBy(KmFunction::name)
functions.removeIf { it.visibility.isPrivate }

// Optimized: Removes private elements first, then sorts only what's needed
functions.removeIf { it.visibility.isPrivate }
functions.sortBy(KmFunction::name)

2) Short-circuit common cases: Add early returns for special cases like empty collections or single elements

public fun <T> Array<out Array<out T>>.flatten(): List<T> {
    if (isEmpty()) return emptyList() // Early return for common case
    // Regular processing...
}

3) Cache expensive results: Use memoization for operations that may be called repeatedly with the same input

private val containsCache = mutableMapOf<IrDeclaration, Boolean>()

override fun containsDeclaration(declaration: IrDeclaration): Boolean = 
    containsCache.getOrPut(declaration) {
        // Expensive computation here
    }

4) Optimize for expected usage patterns: Special-case handle common scenarios based on benchmarks

// Optimization for common no-argument functions
if (parameters.isEmpty()) {
    return reflectionCall {
        caller.call(if (isSuspend) arrayOf(continuationArgument) else emptyArray()) as R
    }
}

Always verify your optimizations with benchmarks to ensure they provide measurable benefits in real-world scenarios.


Memory ordering needs barriers

Ensure proper memory ordering in concurrent code by using appropriate memory barriers and atomic operations based on the access pattern. When implementing release-store semantics, place the store fence before the actual store to prevent instruction reordering:

// INCORRECT - barrier after store
value.store(newValue);
storeFence();  // Too late!

// CORRECT - barrier before store
storeFence();  // Prevents reordering of previous stores
value.store(newValue);

Key guidelines:

This approach prevents subtle race conditions while maintaining performance in concurrent systems.


comprehensive test verification

Write tests that comprehensively verify functionality by covering related scenarios and testing complete outputs rather than partial matches. This approach makes tests more resilient to code changes and ensures thorough validation.

When testing a feature, consider testing related functionality that users might invoke in similar contexts. For example, if testing deno add --npm, also test deno install and related command variations.

Additionally, prefer testing complete outputs over partial matches using wildcards. Instead of testing only fragments, verify the full output to catch unintended changes:

// Less resilient - partial output testing
"output": "[WILDCARD]Found 1 problem"

// More resilient - complete output testing  
"output": "[WILDCARD]Found 1 problem\nChecked 1 file"

This ensures tests catch when fixes or messages are moved, modified, or when output format changes unexpectedly.


Simplify control flow

Streamline code by simplifying control flow structures to improve readability. Eliminate unnecessary nesting and verbosity by applying these guidelines:

  1. Remove redundant else blocks after return, break, continue, or throw statements: ```java // Prefer this: if (condition) { return value; } return otherValue;

// Over this: if (condition) { return value; } else { return otherValue; }


2. Use early returns to reduce nesting levels:
```java
// Prefer this:
if (condition1) {
    // Handle special case
    return;
}
// Handle normal case

// Over this:
if (condition1) {
    // Handle special case
} else {
    // Handle normal case
}
  1. Use concise conditional expressions for simple assignments: ```java // Prefer this: String scheme = ctx.pipeline().get(SslHandler.class) == null ? “http” : “https”;

// Over this: String scheme = “http”; if(ctx.channel().pipeline().get(SslHandler.class) != null) { scheme = “https”; }


4. Follow consistent loop patterns used throughout the codebase:
```java
// Use this pattern for polling loops:
for (;;) {
    Object msg = queue.poll();
    if (msg == null) {
        break;
    }
    pipeline.fireChannelRead(msg);
}

// Instead of while or other variations

Flexible consistent API patterns

Design APIs with flexibility and consistency by leveraging established patterns and avoiding unnecessary constraints. Accept generic type bounds instead of concrete types to provide more flexibility to users and simplify usage.

Be flexible with input types:

// Less flexible - requires exact String type
pub fn name(&mut self, name: String) -> &mut Self {
    // ...
}

// More flexible - accepts any type that can be converted to String
pub fn name<S: Into<String>>(&mut self, name: S) -> &mut Self {
    // ...
}

Follow established patterns in your codebase to ensure consistency across similar APIs. When you need to design a new component, look for similar existing components as inspiration, avoiding unnecessary reinvention. For instance, if other stream types provide a specific set of methods, your new stream type should follow similar patterns.

Avoid arbitrary restrictions that don’t align with similar methods. For example, if related methods allow zero values, a new method should also allow zero values unless there’s a compelling reason not to:

// Inconsistent - restricts n to be > 0 when other methods don't
pub fn detach(&mut self, n: usize) -> Result<SemaphorePermit<'_>, Error> {
    if n == 0 || n >= self.permits {
        return Err(Error::InvalidValue);
    }
    // ...
}

// Consistent - follows the same patterns as similar methods
pub fn detach(&mut self, n: usize) -> Result<SemaphorePermit<'_>, Error> {
    if n > self.permits {
        return Err(Error::InvalidValue);
    }
    // ...
}

Choose names that clearly communicate behavior and purpose. Method names like spawn_aborting might suggest immediate abortion rather than creating something that aborts on drop. Consider alternatives like spawn_with_abort_handle or make it a constructor method on a type that better explains its purpose.


avoid redundant observability data

When implementing observability features like tracing and monitoring, avoid exposing redundant information that can be inferred from existing data, and use appropriate abstraction levels rather than exposing internal implementation details through public APIs.

For tracing spans, don’t set status descriptions when the information can be derived from other attributes:

// Avoid redundant message when status code is sufficient
if (res.status >= 400) {
  span.setAttribute("error.type", String(res.status));
  span.setStatus({
    code: 2, // Error
    // Don't set message - can be inferred from http.response.status_code
  });
}

For internal observability data like file descriptors, use private symbols or internal mechanisms rather than exposing them through public APIs:

// Use internal symbols instead of public API exposure
const fd = conn[INTERNAL_FD_SYMBOL]; // Good
// Rather than: conn.fd (public API exposure)

This approach maintains clean public interfaces while still providing necessary observability data through appropriate channels.


Manage async operation lifecycle

When working with async operations, carefully manage execution context and resource references across await boundaries to prevent context corruption and resource leaks.

For execution context, avoid patterns where context enters/exits span async boundaries, as context may not be properly restored after await points. Instead, structure code to contain async operations within the context scope:

// Problematic - context lost across await
if (TRACING_ENABLED) {
  span = builtinTracer().startSpan(this.method, { kind: 2 });
  context = enterSpan(span);
  // await operations here lose context
}

// Better - use IIFE to contain async operations
const old = getAsyncContext();
try {
  setAsyncContext('inside operation');
  return (async () => {
    await asyncOperation();
    // context preserved here
  })();
} finally {
  setAsyncContext(old);
}

For resource management, distinguish between ongoing and future async operations when managing references. Use unref/ref patterns to handle current operations without affecting future ones:

// Unref ongoing reads but not future reads
if (this.unref) {
  this.unref();  // Clear current operation references
  this.ref();    // Re-establish for future operations
}

This prevents resource leaks while maintaining proper reference counting for subsequent async operations.


null checks before operations

Always check for null or undefined values before performing operations on objects, accessing properties, or calling methods. This prevents runtime errors that occur when attempting to operate on null/undefined values.

When working with potentially nullable objects, add explicit null checks before accessing properties or calling methods:

// Before - can throw if response is null
if (typeof response === "object" && ReflectHas(response, "then")) {
  // ...
}

// After - safe with null check
if (response !== null && typeof response === "object" && ReflectHas(response, "then")) {
  // ...
}

Similarly, check for property existence before using them:

// Check if optional properties exist before use
if (span) {
  span.recordException(err);
  if (err.name) {  // Check err.name exists before using
    span.setAttribute("error.type", err.name);
  }
}

This pattern is especially important when calling methods like Reflect.has(), Object.keys(), or accessing properties on objects that might be null or undefined. The small overhead of these checks prevents difficult-to-debug runtime errors.


Effective API samples

Create clear, comprehensive, and properly structured code samples to document API usage. Follow these principles:

  1. Organize samples properly:
    • Place samples after doc blocks
    • For specialized variants, include the main sample first, then add specialized versions:
      sample("samples.collections.Collections.Elements.find")
      specialFor(CharSequences) {
        sample("samples.text.Strings.find")
      }
      
  2. Create focused examples:
    • Use separate samples for different overloads of the same function
    • Each sample should clearly demonstrate a specific API feature ```kotlin @Sample fun substring() { // Basic substring usage val str = “abcde” assertPrints(str.substring(0), “abcde”) assertPrints(str.substring(1), “bcde”) }

    @Sample fun substringWithRange() { // Overload with range val str = “abcde” assertPrints(str.substring(0, 3), “abc”) assertPrints(str.substring(0, 0), “”) } ```

  3. Include comprehensive examples:
    • Demonstrate different parameter combinations
    • Show edge cases and common usage patterns
    • Add explanatory comments for assertions and edge cases
      @Sample
      fun lastIndexOf() {
        val inputString = "Never ever give up"
        val toFind = "ever"
             
        // Basic usage from start
        assertPrints(inputString.lastIndexOf(toFind), "6")
        // With specific start position
        assertPrints(inputString.lastIndexOf(toFind, 5), "6")
        // Start position after all occurrences
        assertFails { inputString.lastIndexOf(toFind, 10) } // No occurrence after position 10
      }
      
  4. Use standard formatting:
    • Use assertPrints() which converts to readable documentation output
      // This:
      assertPrints(value, "stringRepresentation")
      // Converts to:
      println(value) // stringRepresentation
      
  5. Ensure samples are properly referenced:
    • Add @sample tags to all relevant function variants, including expect/actual declarations
    • For generated code, update samples by running appropriate generation commands

Test edge cases

Ensure tests verify both basic functionality and edge cases. Tests that only cover the happy path can miss critical bugs in boundary conditions and special scenarios.

For each feature:

  1. Identify edge cases (empty inputs, null values, boundary values)
  2. Test all API functions and variations
  3. Place assertions immediately after the code being tested

Example:

@Sample
fun contains() {
    // Basic functionality
    val string = "Kotlin 1.4.0"
    assertPrints(string.contains("K"), "true")
    assertPrints(string.contains("k"), "false")
    
    // Edge cases
    assertPrints("".contains(""), "true") // Empty receiver and parameter
    assertPrints("Kotlin".contains(""), "true") // Empty parameter
    assertPrints("".contains("Kotlin"), "false") // Empty receiver
    assertPrints("Kotlin".contains("Kotlin"), "true") // Identical strings
    assertPrints("Kotlin 2.0.0".contains("Kotlin"), "true") // Receiver contains parameter
    assertPrints("Kotlin".contains("Kotlin 2.0.0"), "false") // Parameter contains receiver
}

Include specific tests for error conditions using explicit assertions rather than try/catch blocks:

// Incorrect: Test passes even if cast doesn't fail
try {
    BNativeHeir as A.Companion
} catch (e: Exception) {
    assertTrue(e is ClassCastException)
}

// Correct: Test only passes if cast fails with expected exception
assertFailsWith<ClassCastException> {
    BNativeHeir as A.Companion
}

Comprehensive testing prevents code from “rotting” and ensures reliability across all usage scenarios.


Use branch prediction

Optimize performance-critical algorithms by using branch prediction hints to guide the CPU. Add UNLIKELY macros for error conditions, boundary checks, or exceptional cases that rarely evaluate to true, and LIKELY for common execution paths. This helps the CPU’s branch predictor make better decisions, reducing pipeline stalls and improving execution speed in hot loops and frequently called functions.

Example:

// Less optimized:
if (number_num < lower_num || number_num > upper_num) {
    // Handle out-of-range case
}

// Optimized with branch prediction:
if (UNLIKELY(number_num < lower_num || number_num > upper_num)) {
    // Handle out-of-range case
}

This technique is especially important in performance-critical algorithms where the same conditional is evaluated repeatedly and the outcome is predictable in most cases.


function documentation standards

All public functions and methods must be documented with comments that v doc can understand. Documentation should start with the function name and clearly explain the function’s behavior and purpose. For static methods, explicitly identify them as such (e.g., “MethodName static method returns…”).

Comments should be informative and provide meaningful context rather than simply repeating variable or function names. Avoid comments that just expand on names without adding value - it’s better to have no comment than one that merely restates obvious information.

Example of proper function documentation:

// get_queryset returns a list of QuerySet objects from the database query
pub fn (db &DB) get_queryset(query string) ![]QuerySet {

// Time.new static method returns a time struct with the calculated Unix time
pub fn Time.new() Time {

For complex code sections, add explanatory comments that clarify the purpose and reasoning, especially when the logic is not immediately obvious from reading the code.


Optimize build configurations

When configuring CMake builds, carefully select compiler and linker flags that optimize for performance while maintaining cross-platform compatibility. Performance-oriented flags can significantly impact runtime speed, binary size, and resource utilization, but must be applied conditionally based on the target platform and compiler.

Key practices:

Example of conditional linker optimization:

target_link_options(yoga PRIVATE
    # Discard unused sections
    $<$<CONFIG:RELEASE>:$<$<CXX_COMPILER_ID:Clang,GNU>:-Wl,--gc-sections>>
    $<$<CONFIG:RELEASE>:$<$<CXX_COMPILER_ID:AppleClang>:-Wl,-dead_strip>>)

This approach ensures optimal performance across different build environments while avoiding platform-specific build failures.


Optimize memory allocation

Be deliberate about memory allocation patterns to improve performance. Implement these practices:

  1. Pre-allocate collections when the size is known:
    // Less efficient - may require multiple reallocations
    let mut output = Vec::new();
       
    // More efficient - single allocation of correct size
    let mut output = Vec::with_capacity(self.len());
    
  2. Avoid unnecessary buffer clearing:
    // Less efficient - discards existing content
    buffer.clear();
    buffer.extend(new_items);
       
    // More efficient - preserves existing content when appropriate
    buffer.extend(new_items);
    
  3. Use compact memory representations when appropriate:
    // Less memory-efficient
    name: Option<Vec<u8>>,
    name_demangled: Option<String>,
       
    // More memory-efficient
    name: Option<Box<[u8]>>,
    name_demangled: Option<Box<str>>,
    
  4. Defer allocation until needed:
    // Less efficient - always reserves space
    buffer.reserve(BLOCK_CAP);
       
    // More efficient - only reserves when necessary
    if buffer.len() == buffer.capacity() {
        buffer.reserve(BLOCK_CAP);
    }
    
  5. Be mindful of struct size and field initialization: Only store fields directly in structs when they’re always needed. Consider storing rarely used fields behind indirection (e.g., in an Option or Box) or restructuring to avoid initializing fields that aren’t always required.

These practices reduce memory pressure, improve cache locality, and minimize the overhead of memory management operations.


Secure unsafe code

When working with unsafe code, follow these practices to minimize security vulnerabilities:

  1. Minimize scope: Limit unsafe blocks to only the operations that require them.
    // BAD: Overly broad unsafe block
    unsafe {
      let tail_block = &mut *tail;
      if tail_block.is_closed() { ... }
    }
       
    // GOOD: Minimal scope
    let tail_block = unsafe { &mut *tail };
    if tail_block.is_closed() { ... }
    
  2. Document safety: Add a // SAFETY: comment above each unsafe block explaining why the operation is safe.
    // SAFETY: The pointer is guaranteed to be valid because it comes from an Arc
    // that we have exclusive access to via get_mut()
    unsafe { Arc::get_mut(&mut arc).unwrap_unchecked() }
    
  3. Isolate operations: Use separate unsafe blocks for each unsafe operation.
    // BAD: Multiple unsafe operations in one block
    unsafe {
      let fd = syscall(SYS_pidfd_open, pid, PIDFD_NONBLOCK);
      if fd == -1 {
        let errno = *__errno_location();
        // ...
      }
    }
       
    // GOOD: Separate unsafe blocks
    let fd = unsafe { syscall(SYS_pidfd_open, pid, PIDFD_NONBLOCK) };
    if fd == -1 {
      let errno = unsafe { *__errno_location() };
      // ...
    }
    
  4. Encapsulate requirements: Mark functions that expose unsafe requirements as unsafe themselves.
    // BAD: Function with hidden unsafe requirements
    pub fn read_from(&mut self, inner: &mut T) { ... }
       
    // GOOD: Properly marked function
    pub unsafe fn read_from(&mut self, inner: &mut T) { ... }
    

Following these practices helps prevent memory corruption vulnerabilities and makes unsafe code easier to audit and maintain.


Minimize unsafe code

When writing code that requires unsafe operations, follow these critical security practices:

  1. Minimize the scope of unsafe blocks to only the specific operations that require them
  2. Document each unsafe block with a // SAFETY: comment explaining why the operation is safe
  3. Use separate unsafe blocks for distinct unsafe operations rather than one large block

These practices reduce the risk of memory safety issues and make code easier to audit for security vulnerabilities.

Example:

// BAD: Large unsafe block with multiple operations
unsafe {
    let block = self.head.as_ref();
    let tail_block = &mut *tail;
    // More code...
}

// GOOD: Minimal scope with documentation
// SAFETY: The tail pointer is guaranteed to be valid because...
let tail_block = unsafe { &mut *tail };

// More code with safe operations...

By limiting the scope of unsafe code, you make it easier to verify its correctness and maintain memory safety guarantees.


Empty vs nil distinction

Always distinguish between nil and empty values when handling nullable types, as they carry different semantic meanings and can affect program behavior. Nil represents the absence of a value, while empty represents a zero-length but initialized value.

This distinction is particularly critical in data serialization/deserialization, where maintaining compatibility with standard library behavior is essential. For slices, maps, and other reference types, ensure your code handles both states appropriately.

Example:

// Good: Properly distinguish between nil and empty slice
if slice == nil {
    // Handle nil case - no slice allocated
    return handleNilSlice()
} else if len(slice) == 0 {
    // Handle empty case - slice allocated but no elements
    return handleEmptySlice()
}

// Good: Use appropriate zero values
// For empty slice, use zerobase pointer (not nil) to match standard library
self.Emit("MOVQ", jit.Imm(_Zero_Base), jit.Ptr(_VP, 0))

This practice prevents subtle bugs, maintains type information, and ensures consistent behavior across different execution paths.


Graceful error handling

Prioritize graceful error handling over panicking by providing fallbacks and propagating rich context. When operations can fail:

  1. For non-critical failures, use fallbacks instead of unwrap(): ```rust // Instead of this: let pos = std.stream_position().unwrap();

// Prefer this: let pos = std.stream_position().unwrap_or(0);


2. For functions that may panic with assertions, add `#[track_caller]` to improve error diagnostics:
```rust
#[track_caller]
pub fn global_queue_interval(&mut self, val: u32) -> &mut Self {
    assert!(val > 0, "global_queue_interval must be greater than 0");
    // ...
}
  1. When exposing errors, implement the full std::error::Error trait including the source() method to maintain the error chain.

  2. In documentation examples, demonstrate proper error handling rather than ignoring or silencing errors: ```rust // Instead of ignoring errors: let _ = compress_data(reader).await;

// Show proper error handling: compress_data(reader).await?;


5. Consider providing configuration options for users to handle certain error conditions differently when appropriate.

---

## validate configuration schemas

<!-- source: denoland/deno | topic: Configurations | language: Json | updated: 2025-02-23 -->

Configuration schemas should be actively validated, well-documented, and kept up-to-date through automated testing. Use appropriate schema types (enums vs strings) based on whether values are constrained, provide comprehensive descriptions that include examples and supported formats, and implement automated tests to ensure schemas remain current with code changes.

For example, instead of a generic string type:
```json
"items": {
  "type": "string"
}

Use descriptive schemas with proper validation:

"plugins": {
  "type": "array", 
  "description": "UNSTABLE: List of plugins to load. These can be paths, npm or jsr specifiers",
  "items": {
    "oneOf": [
      {"type": "string", "format": "uri"},
      {"enum": ["known-plugin-1", "known-plugin-2"]}
    ]
  }
}

Add automated tests that verify schema accuracy against actual implementation to prevent drift between documentation and behavior.


Socket configuration guidance

When implementing networking APIs, always clearly document socket modes, configuration options, and platform-specific behaviors. Be explicit about blocking versus non-blocking mode implications, required flags, and ensure consistent API design across related components.

For socket modes, provide explicit warnings about incorrect configurations:

/// Create a new listener from a standard library socket.
///
/// Warning: Passing a listener in blocking mode is erroneous, and the
/// behavior in that case may change in the future. For example, it could panic.
pub fn from_std(socket: std::net::TcpListener) -> io::Result<TcpListener> {
    // Implementation...
}

When exposing low-level socket options, document flag requirements and constraints:

/// Create a new AsyncFd with the provided raw epoll flags for registration.
///
/// These flags replace any epoll flags would normally set when registering the fd.
/// Note that `EPOLLONESHOT` must not be used, and `EPOLLET` must be set.
///
/// **Note**: This is an [unstable API][unstable]. The public API of this may 
/// break in 1.x releases.
#[cfg(all(target_os = "linux", tokio_unstable))]
pub fn with_epoll_flags(inner: T, flags: u32) -> io::Result<Self>

For platform-specific features, include appropriate conditional compilation and clear handling:

// Properly handle platform-specific socket behaviors
#[cfg(any(target_os = "linux", target_os = "android"))]
let addr = {
    let os_str_bytes = path.as_ref().as_os_str().as_bytes();
    if os_str_bytes.starts_with(b"\0") {
        StdSocketAddr::from_abstract_name(os_str_bytes)?
    } else {
        StdSocketAddr::from_pathname(path)?
    }
};

Maintain consistent APIs when adding socket configuration methods, carefully handling type conversions when needed:

/// Sets the size of the UDP send buffer on this socket.
///
/// On most operating systems, this sets the `SO_SNDBUF` socket option.
pub fn set_send_buffer_size(&self, size: u32) -> io::Result<()> {
    self.to_socket().set_send_buffer_size(size as usize)
}

comprehensive test coverage

Ensure tests cover both happy path scenarios and edge cases, including error conditions and boundary behaviors. Always wrap test code in proper test functions to leverage framework benefits like sanitizers and proper test isolation.

When writing tests, consider potential failure modes and edge cases that could cause crashes or unexpected behavior. For iterative operations, test what happens on subsequent iterations. For resource-intensive operations, ensure proper cleanup and error handling.

Example:

Deno.test("[node/sqlite] StatementSync#iterate edge cases", () => {
  const db = new DatabaseSync(":memory:");
  const stmt = db.prepare("SELECT 1 UNION ALL SELECT 2");
  
  // Test normal iteration
  const result1 = [];
  for (const row of stmt.iterate()) {
    result1.push(row);
  }
  
  // Test second iteration (edge case)
  const result2 = [];
  for (const row of stmt.iterate()) {
    result2.push(row);
  }
  
  assertEquals(result1, result2); // Verify consistent behavior
});

Always prefer Deno.test() wrappers over standalone code to benefit from sanitizers, proper error handling, and test isolation.


Protect network buffer lifecycle

When handling network buffers in protocol implementations, ensure proper lifecycle management to prevent memory leaks and data corruption. Key practices:

  1. Convert mutable data to immutable form before async operations: ```java // WRONG ctx.fireUserEventTriggered(evt); event.userEvent = String.valueOf(evt); // evt may be modified/released

// RIGHT String eventStr = String.valueOf(evt); ctx.fireUserEventTriggered(evt); event.userEvent = eventStr;


2. Use buffer slicing and reference counting for partial data:
```java
// WRONG
byte[] partialData = new byte[5];
System.arraycopy(data, 0, partialData, 0, 5);

// RIGHT
ByteBuf chunk = ctx.alloc().buffer().writeBytes(data);
ByteBuf partial = chunk.retainedSlice(0, 5);
// ... use partial ...
partial.release();
chunk.release();
  1. Clear buffer arrays after submission to prevent stale references:
    // After buffer submission
    iovArray.clear(); // Clear references that are no longer needed
    

This guidance is especially important in asynchronous networking code where buffers may be accessed across different threads or event loop iterations.


Optimize critical loops

When implementing algorithms with nested loops or recursive operations, carefully analyze the computational complexity and optimize the critical path. Pay attention to loop ordering, early termination conditions, and unnecessary recomputation.

In path normalization algorithms (discussion 111-112), avoid quadratic behavior by using tight single-pass loops instead of repeated string operations:

// Before: Potentially quadratic with repeated string operations
function getNormalizedAbsolutePath(path: string) {
  // Repeatedly finds separators with indexOf
  const sepIndex = path.indexOf(directorySeparator, index + 1);
  const altSepIndex = path.indexOf(altDirectorySeparator, index + 1);
  // ...
}

// After: Linear complexity with a single pass
function getNormalizedAbsolutePath(path: string) {
  let index = 0;
  while (index < path.length) {
    const ch = path.charCodeAt(index);
    // Process each character once with early termination
    if (isAnyDirectorySeparator(ch)) {
      // Handle separator
    }
    index++;
  }
}

When working with array comparisons (discussions 110, 144), consider the computational complexity of your algorithm:

  1. Avoid nested loops when a single pass will suffice
  2. Use early termination when a condition can’t possibly be met
  3. Structure data to match access patterns (discussion 67-68)
  4. When ordering matters, ensure your algorithm preserves the intended behavior

For recursive algorithms, apply similar principles to prevent stack overflows and excessive computation.


benchmark performance assumptions

Always validate performance assumptions with concrete benchmarks rather than making optimization decisions based on intuition. When considering performance trade-offs between different implementation approaches, write targeted benchmarks to measure the actual impact.

For example, when debating between using arrays vs multiple function arguments, benchmark both approaches:

// Don't assume - measure the difference
// Option 1: Array approach
return respond(id, [{}, null]);

// Option 2: Multiple arguments  
return respond(id, {}, null);

The benchmark revealed that “adding another arg is about 15% slower than the array version”, leading to a data-driven decision to keep the array approach.

Similarly, when choosing between async and sync operations, measure the performance impact in your specific context rather than following general patterns. What works for browsers may not be optimal for your runtime environment.

This approach prevents premature optimization, ensures changes actually improve performance, and helps avoid performance regressions disguised as improvements.


Structure API doc blocks

Each public API documentation block should follow a consistent structure:

  1. Start with a single-line summary that concisely describes the item
  2. Add an empty line after the summary
  3. Follow with detailed documentation paragraphs
  4. Use empty lines between sections (paragraphs, code blocks, headers)
  5. Format Rust types using backticks (e.g., [String])

Example:

/// Receives the next value from the channel.
///
/// This method returns `None` if the channel has been closed and there are
/// no remaining messages in the channel's queue. The channel is closed when
/// all senders have been dropped.
///
/// # Examples
///
/// ```
/// use tokio::sync::mpsc;
///
/// #[tokio::main]
/// async fn main() {
///     let (tx, mut rx) = mpsc::channel(100);
///     assert!(rx.recv().await.is_none());
/// }
/// ```
pub async fn recv(&mut self) -> Option<T> {
    // Implementation
}

This structure improves readability and ensures documentation is both scannable and detailed when needed. The single-line summary is particularly important as it appears in module documentation and IDE tooltips.


descriptive naming patterns

Use descriptive names that clearly indicate the expected format, convention, or constraints. This applies to template variables, configuration keys, and validation patterns. Names should communicate not just what something is, but how it should be formatted or what rules it follows.

For template variables, include format hints in the name:

{
  "description": "CAMEL_PARSER_NAME grammar for tree-sitter"
}

For validation patterns, ensure they accommodate all valid naming conventions:

{
  "pattern": "^(source|text)(\\.[\\w\\-]+)+$"
}

This approach reduces ambiguity and helps developers understand naming requirements without consulting additional documentation.


Use null validation utilities

Consistently use utility methods like ObjectUtil.checkNotNull() or Objects.requireNonNull() to validate that parameters are not null. When assigning parameters to instance variables, combine the null check with the assignment for cleaner, more maintainable code:

// Instead of:
public DohRecordEncoder(InetSocketAddress dohServer, boolean useHttpPost, String uri) {
    if (dohServer == null) {
        throw new NullPointerException("dohServer");
    }
    this.dohServer = dohServer;
    this.useHttpPost = useHttpPost;
    if (uri == null) {
        throw new NullPointerException("uri");
    }
    this.uri = uri;
}

// Do this:
public DohRecordEncoder(InetSocketAddress dohServer, boolean useHttpPost, String uri) {
    this.dohServer = ObjectUtil.checkNotNull(dohServer, "dohServer");
    this.useHttpPost = useHttpPost;
    this.uri = ObjectUtil.checkNotNull(uri, "uri");
}

This approach not only prevents NullPointerExceptions but also provides clear error messages, making debugging easier. For method parameters that should never be null, perform the check at the beginning of the method. When initializing components in a class, add appropriate null checks to the initialization or configuration methods rather than adding conditional null checks throughout the code.


Network API design consistency

When designing networking APIs, maintain consistency with existing interfaces while ensuring proper cross-platform compatibility. Follow these key principles:

  1. Type consistency: Use consistent types across related APIs. If existing APIs use specific types (like u32 for buffer sizes), maintain this pattern even if underlying libraries use different types.
// Good - matches existing TcpSocket API pattern
pub fn set_send_buffer_size(&self, size: u32) -> io::Result<()> {
    self.to_socket().set_send_buffer_size(size as usize)
}
  1. Platform-specific handling: Explicitly handle platform-specific features with clear conditional compilation and documentation.
#[cfg(any(target_os = "linux", target_os = "android"))]
let addr = {
    let os_str_bytes = path.as_ref().as_os_str().as_bytes();
    if os_str_bytes.starts_with(b"\0") {
        StdSocketAddr::from_abstract_name(os_str_bytes)?
    } else {
        StdSocketAddr::from_pathname(path)?
    }
};
  1. Abstraction boundaries: Consider whether low-level system calls should be exposed directly or via higher-level abstractions. When bypassing abstractions (like Mio), document the implications and ensure future compatibility.

  2. Document constraints: When exposing low-level features like epoll flags, clearly document requirements and add debug assertions.

/// Create a new AsyncFd with the provided raw epoll flags for registration.
///
/// These flags replace any epoll flags would normally set when registering the fd.
/// Note that `EPOLLONESHOT` must not be used, and `EPOLLET` must be set.
  1. Implementation correctness: For functions that check resource states like terminals, avoid implementations that can produce incorrect results during ongoing operations.
// Good - direct access ensures correct result even during I/O operations
pub fn is_terminal(&self) -> bool {
    std::io::stderr().is_terminal()
}

By following these principles, you’ll create networking APIs that are consistent, reliable across platforms, and easier for users to understand and use correctly.


Release resources consistently

Always ensure resources are properly released, especially in exception paths. Use try-finally blocks to guarantee cleanup of buffers, streams, and other resources even when errors occur.

Common mistakes include:

  1. Forgetting to release resources in error paths
  2. Not handling promises in cleanup methods
  3. Failing to close resources before throwing exceptions

Example of problematic code:

public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
    ByteBuf content = ctx.alloc().buffer();
    dohQueryEncoder.encode(ctx, (DnsQuery) msg, content);
    
    HttpRequest request = createRequest(content);
    // If an exception occurs here, both content and msg will leak
    super.write(ctx, request, promise);
}

Better implementation:

public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
    DnsQuery query = (DnsQuery) msg;
    ByteBuf content = ctx.alloc().buffer();
    try {
        dohQueryEncoder.encode(ctx, query, content);
        HttpRequest request = createRequest(content);
        ctx.write(request, promise);
    } finally {
        content.release();
        query.release();
    }
}

Also ensure proper cleanup in lifecycle methods like handlerRemoved() and doClose() to prevent leaks, and when throwing exceptions, release any allocated resources first:

if (!IoUring.isRegisterBufferRingSupported()) {
    // Close ringBuffer before throwing to ensure we release all memory on failure
    ringBuffer.close();
    throw new UnsupportedOperationException("io_uring_register_buffer_ring is not supported");
}

When handling error conditions, prefer specific exceptions with clear messages:

// Bad
if (encoderFactory == null) {
    throw new Error();
}

// Good
if (encoderFactory == null) {
    throw new IllegalStateException("Couldn't find CompressionEncoderFactory: " + targetContentEncoding);
}

Runtime configurable defaults

Prefer runtime-configurable values over hardcoded constants to allow users to customize behavior without recompilation. Use environment variables with os.getenv_opt() for runtime configuration instead of compile-time constants with $d(), and consider environment variables instead of complex CLI parsing.

Why this matters:

How to apply:

// Instead of hardcoded constants:
const indexexpr_cutoff = 10

// Use runtime-configurable defaults:
const indexexpr_cutoff = os.getenv_opt('VET_INDEXEXPR_CUTOFF') or { '10' }.int()

// For buffer sizes and similar values:
const buff_size = int($d('gg_text_buff_size', 2048))

// Instead of complex CLI parsing for tools:
// Use environment variables like VDIFF_TOOL, VTMP_DIR, etc.

This approach allows users to customize behavior with simple commands like VET_INDEXEXPR_CUTOFF=99 v vet . without requiring recompilation or complex flag combinations.


Check feature compatibility

When using kernel-specific networking features like io_uring, always implement runtime detection of feature support before enabling them. This ensures your code remains compatible across different kernel versions while taking advantage of newer optimizations when available.

For Linux kernel features, verify the minimum required version and implement conditional feature activation. This prevents runtime errors (like EINVAL) on systems with older kernels that don’t support specific features.

Example implementation:

struct io_uring_params p;
memset(&p, 0, sizeof(p));

// Check for feature support before enabling
#ifdef IORING_SETUP_SUBMIT_ALL
    // Introduced in kernel 5.18, don't blindly enable
    if (kernel_supports_feature(FEATURE_IORING_SETUP_SUBMIT_ALL)) {
        p.flags |= IORING_SETUP_SUBMIT_ALL;
    }
#endif

#ifdef IORING_SETUP_R_DISABLED
    // Introduced in kernel 6.1, check before using
    if (kernel_supports_feature(FEATURE_IORING_SETUP_R_DISABLED)) {
        p.flags |= IORING_SETUP_R_DISABLED;
    }
#endif

Documentation should clearly state which kernel versions are required for specific features. Consider exposing feature detection capabilities to higher-level code so callers can make informed decisions about available functionality.


API documentation synchronization

Ensure that all API documentation, including code examples and integration guides, accurately reflects the current API state. When API changes occur (such as import/export modifications, new entry points, or version compatibility updates), corresponding documentation must be updated immediately to prevent developer confusion and integration errors.

Key areas to verify:

Example of outdated documentation that needs correction:

// Outdated - no longer works
import Parser from 'web-tree-sitter';

// Current - matches actual API
import { Parser } from 'web-tree-sitter';
// Also document available variants
import { Parser } from 'web-tree-sitter/debug';

This practice prevents developers from encountering runtime errors due to mismatched documentation and ensures smooth API adoption.


Ensure semantic naming clarity

Names should clearly convey their semantic purpose and avoid conflicts that reduce code readability. This applies to imports, types, variables, and methods.

Key principles:

  1. Avoid naming conflicts: When importing classes or types, choose names that don’t conflict with local variables or other imports
  2. Use semantically distinct names: Different concepts should have clearly distinguishable names, especially for related but different types
  3. Prioritize clarity over brevity: Choose descriptive names that make the code’s intent obvious

Examples:

Import naming to avoid conflicts:

// Problematic - naming conflict
import Parser from 'web-tree-sitter';
const Parser: typeof Parser = await import('..').then(m => m.default);

// Better - clear, distinct names
import TSParser from 'web-tree-sitter';
const Parser: typeof TSParser = await import('..').then(m => m.default);

Type naming for semantic clarity:

// Problematic - same interface for different concepts
interface QueryResult {
  pattern: number;
  captures: { name: string; node: SyntaxNode }[];
}

// Better - distinct names for different concepts
interface QueryMatch {
  pattern: number;
  captures: QueryCapture[];
}

interface QueryCapture {
  name: string;
  node: SyntaxNode;
}

This prevents confusion and makes the codebase more maintainable by ensuring each name has a clear, unambiguous meaning.


Conditional compilation guards

Always use appropriate preprocessor directives to guard platform-specific, version-dependent, or feature-specific code. Ensure that conditional compilation checks accurately reflect the actual availability of features and APIs, not just version numbers or single configuration flags.

When gating functionality:

Example of proper conditional compilation:

#ifdef TREE_SITTER_FEATURE_WASM
// WASM-specific code that requires __builtin_wasm_memory_size
#endif

#if PY_MINOR_VERSION >= 13 && !defined(Py_GIL_DISABLED)
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
#endif

#elif !defined(__wasi__)
// Platform-specific implementation
#else
// WASI fallback or noop implementation
#endif

This prevents compilation errors across different environments and ensures code portability while maintaining feature availability where supported.


Avoid breaking API changes

When modifying existing public APIs, always maintain backward compatibility to avoid breaking existing users. Breaking changes include altering function signatures, removing public functions, or changing function visibility from public to private.

Instead of making breaking changes:

For example, when refactoring a public function:

// Instead of changing the signature (breaking change):
// pub fn new_digest(absorption_rate int, hash_size int, suffix u8) !&Digest

// Keep the original public function:
pub fn new_digest(absorption_rate int, hash_size int) !&Digest {
    return new_digest_with_suffix(absorption_rate, hash_size, default_suffix)
}

// Add the new functionality as a separate function:
pub fn new_digest_with_suffix(absorption_rate int, hash_size int, suffix u8) !&Digest {
    // implementation
}

When removing public functions, keep them as wrappers that call the new internal implementation. This ensures existing code continues to work while allowing internal refactoring and improvements.


Optimize CI workflow syntax

Write cleaner and more maintainable CI/CD workflows by following established syntax patterns and best practices. Use GitHub Actions’ built-in features like working-directory instead of manual directory changes, employ proper shell quoting and efficient commands, and prefer single-line commands when appropriate.

Key practices:

Example improvements:

# Instead of:
- name: Build WASM Library
  run: |
    cd lib/binding_web
    npm ci
    npm run build:debug

# Use:
- name: Build WASM Library
  working-directory: lib/binding_web
  run: npm ci && npm run build:debug

# Instead of:
- run: |
    echo "DOCKER_CMD=docker run --rm -v /home/runner:/home/runner -w . $CROSS_IMAGE" >> $GITHUB_ENV

# Use:
- run: echo "DOCKER_CMD=docker run --rm -v /home/runner:/home/runner -w . $CROSS_IMAGE" >> $GITHUB_ENV

These optimizations improve readability, reduce potential errors, and make workflows more maintainable while following GitHub Actions conventions.


Consistent message terminology

Use clear, consistent terminology in all error messages and user-facing text. Avoid technical jargon that might confuse users, and maintain consistency in language patterns across the codebase:

  1. Use explicit wording instead of technical jargon
    • Prefer: “Enforce that mutable properties cannot satisfy ‘readonly’ requirements in assignments”
    • Avoid: “Ensure ‘readonly’ properties remain read-only in type relationships”
  2. Maintain consistent language patterns
    • Use full forms instead of contractions (“are not” instead of “aren’t”)
    • Example:
      // Preferred
      "Default imports are not allowed in a deferred import."
           
      // Avoid
      "Default imports aren't allowed for deferred imports."
      

Consistent terminology improves readability and maintains a professional style throughout the codebase.


Document cryptographic requirements

Security-critical functions, especially those involving cryptographic operations, must include clear and accurate documentation about their security requirements and assumptions. This is essential for preventing misuse that could lead to vulnerabilities.

When documenting cryptographic functions:

Example from ECDSA key generation:

// new_key_from_seed creates a new private key from the seed bytes.
//
// Notes on the seed:
// You should make sure the seed bytes come from a cryptographically secure random generator,

Poor documentation of cryptographic requirements can lead developers to make incorrect assumptions about security properties, potentially introducing vulnerabilities through improper usage of otherwise secure cryptographic primitives.


explicit cryptographic parameters

Always explicitly specify security-critical parameters in cryptographic operations rather than relying on default values. This prevents vulnerabilities that could arise from misunderstood defaults or future changes to default behavior.

When working with cryptographic APIs, be explicit about hash algorithms, key sizes, padding schemes, and other security-relevant configurations. This makes the security intent clear and protects against breaking changes to library defaults.

Example of what to avoid:

// Unclear what hash algorithm is being used
signature := pvkey.sign(message_tobe_signed)!

Example of preferred approach:

// Explicitly specify the hash configuration
signature := pvkey.sign(message_tobe_signed, hash_config: .with_recommended_hash)!

This practice is especially important when there’s uncertainty about what the default behavior actually is, as defaults in security libraries can change between versions or may not be what developers expect.


use -prod for performance

Always use the -prod compiler flag when building performance-critical code or running benchmarks. The -prod flag automatically enables essential optimization settings including -O3 and -flto (Link Time Optimization), eliminating the need to manually specify these common performance flags.

This approach ensures consistent optimization across different build scenarios and reduces the likelihood of forgetting important performance flags. For additional architecture-specific optimizations, you can combine -prod with targeted flags:

# For performance-critical applications
v -cc gcc -prod -cflags "-std=c17 -march=native -mtune=native" .

# For benchmarking
v -prod run bench/bench.v

Using -prod as the foundation provides a reliable baseline for performance optimization while allowing for additional customization when needed.


Organize code logically

Group related code elements together with a consistent and logical structure. Place stable fields and functionality first, followed by conditional or unstable features.

For struct definitions:

#[derive(Debug, Default)]
pub(crate) struct WorkerMetrics {
    // Stable fields first
    busy_duration_total: AtomicU64,
    
    // Conditional fields after stable ones
    #[cfg(tokio_unstable)]
    park_count: AtomicU64,
    
    #[cfg(tokio_unstable)]
    mean_poll_time: AtomicU64,
    
    // ...more fields
}

For implementation blocks:

impl MetricsBatch {
    // Regular methods first
    pub(crate) fn submit(&mut self, worker: &WorkerMetrics) {
        worker.busy_duration_total.store(self.busy_duration_total, Relaxed);
        
        // Call separate method for unstable features
        self.submit_unstable(worker);
    }
    
    // Unstable methods grouped together at the bottom
    cfg_unstable_metrics! {
        fn submit_unstable(&mut self, worker: &WorkerMetrics) {
            // Implementation for unstable features
        }
    }
}

Keep implementation blocks manageable by splitting large code blocks into separate files, especially within macros where formatting tools don’t work well. Consider exposing single-item modules as direct exports:

// Instead of this:
pub mod abort_on_drop;

// Do this:
mod abort_on_drop;
pub use abort_on_drop::AbortOnDropHandle;

When public types would clutter documentation, organize them into logical submodules.


Document null safety assumptions

When writing code that handles potentially null, undefined, or uninitialized values, always document safety assumptions with clear comments. This is especially important for unsafe blocks that manipulate raw pointers, uninitialized memory, or perform type conversions.

Good safety comments should:

  1. Explain why the operation is safe
  2. Document preconditions that must be met
  3. Clarify the expected state of variables
  4. Mention any invariants being maintained

Example:

// BAD: Missing safety explanation
unsafe fn read_from<T: Read>(&mut self, rd: &mut T, max_buf_size: usize) -> io::Result<usize> {
    let buf = &mut self.buf.spare_capacity_mut()[..max_buf_size];
    let buf = unsafe { &mut *(buf as *mut [MaybeUninit<u8>] as *mut [u8]) };
    let res = rd.read(buf);
    // ...
}

// GOOD: Clear safety documentation
/// Safety: `rd` must not read from the buffer passed to `read` and
/// must correctly report the length of the written portion of the buffer.
unsafe fn read_from<T: Read>(&mut self, rd: &mut T, max_buf_size: usize) -> io::Result<usize> {
    // SAFETY: The memory may be uninitialized, but `rd.read` will only write to the buffer.
    let buf = &mut self.buf.spare_capacity_mut()[..max_buf_size];
    let buf = unsafe { &mut *(buf as *mut [MaybeUninit<u8>] as *mut [u8]) };
    let res = rd.read(buf);
    // ...
}

When performing pointer casts or transmutes, be especially explicit about lifetime and ownership guarantees:

// GOOD: Clear pointer casting documentation
let inner: *mut InnerFuture<'static, T> = &mut self.0;
let inner: *mut InnerFuture<'_, T> = inner.cast();
// SAFETY: The future must not exist after the type `T` becomes invalid.
// This casts away the type-level lifetime check, but the inner future 
// never moves out of this structure, so it won't live longer than `T`.
let inner = unsafe { &mut *inner };

Proper documentation of safety assumptions helps prevent subtle bugs, assists future maintainers, and makes code auditing more effective.


Strategic configuration exclusions

When configuring build exclusions in package manifests or configuration files, be strategic and minimal. Only exclude files that cause actual build issues (like non-source files that generate compilation warnings), while preserving important files such as licenses and directories that may be relevant for future features. Modern tooling often handles file filtering automatically, so explicit exclusion lists may be unnecessary.

For example, in Package.swift:

.target(name: "TreeSitter",
        path: "lib",
        exclude: [
          // Only exclude files that cause build warnings
          "src/unicode/ICU_SHA",
          "src/unicode/README.md", 
          "src/unicode/LICENSE",
          // Don't exclude "src/wasm" - may be needed for future support
        ],

Before adding exclusions, verify they solve actual build problems rather than preemptively excluding files that might seem irrelevant. Consider whether newer versions of your build tools can handle the filtering automatically.


Use descriptive identifiers

Choose identifiers that clearly communicate their purpose, content, or role rather than using generic or abbreviated names. Names should be self-documenting and reduce the need to reference documentation or implementation details to understand what they represent.

Apply this principle to:

Examples of improvements:

// Before: Generic field name
.supertypes = ts_supertypes,

// After: Specific field name indicating content type  
.supertype_symbols = ts_supertype_symbols,

// Before: Vague error name
ReservedWordSet,

// After: Descriptive error name with context
InvalidReservedWordSet,

// Before: Generic lifetime parameter
QueryMatches<'a, 'tree: 'a, 'b: 'a, T: TextProvider<'b>>

// After: Descriptive lifetime parameter
QueryMatches<'a, 'tree: 'a, 'text_provider: 'a, T: TextProvider<'text_provider>>

// Before: Ambiguous field name
pub expected: String,

// After: Clear field name indicating purpose
pub expected_capture_name: String,

This approach improves code readability and reduces cognitive load for developers who need to understand the codebase quickly.


Provide clear error context

Always provide meaningful, specific error messages that help users understand what went wrong and why. Use descriptive language that indicates what was expected versus what was encountered. Leverage error context tools like with_context() to add relevant information about the operation that failed, and use debug formatting for error display to show complete error chains.

Key practices:

Example:

// Instead of generic error
return Err(anyhow!("Invalid rule"));

// Provide specific context
return Err(ParseGrammarError::UnexpectedRule)?;

// Add operation context
fs::read_to_string(&location)
    .with_context(|| format!("failed to read {}", location.to_string_lossy()))?;

// Use debug format for complete error information
eprintln!("{:?}", err);

This approach makes debugging significantly easier by providing actionable information about what failed and why, rather than forcing developers to guess or dig through code to understand error conditions.


Optimize CI job structure

Structure your CI workflows to maximize performance and clarity. Each job should have a single, clear responsibility with these guidelines:

  1. One toolchain per job: Keep jobs focused with a single Rust toolchain version per job. Multiple toolchains in one job create confusion about which version is being used for each command.

    # Don't do this:
    - name: Install Rust stable
      uses: dtolnay/rust-toolchain@stable
      with:
          toolchain: ${{ env.rust_stable }}
    - name: Install Rust nightly
      uses: dtolnay/rust-toolchain@stable
      with:
          toolchain: ${{ env.rust_nightly }}
    

    Instead, create separate jobs for different toolchains or requirements.

  2. Split long-running tasks: Divide lengthy operations into separate jobs that can run in parallel. When a job begins taking too much time (like Miri tests), split it to enable faster feedback cycles and better resource utilization.

  3. Use efficient testing tools: Employ optimized testing tools like cargo-nextest to significantly reduce execution time. For example, replacing standard test runners with nextest can reduce CI runtime by 40% or more, as seen with Miri jobs (37 minutes → 21 minutes).

These practices will result in more maintainable CI configurations, faster feedback for developers, and clearer error identification when builds fail.


Optimize job structure

Structure CI jobs for clarity, parallelism, and efficiency. Each job should have a single, well-defined purpose to prevent confusion about which tools and versions are being used.

Key guidelines:

For example, instead of:

jobs:
  test-all:
    steps:
      - uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: stable
      - uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: nightly
      - name: Run multiple test suites
        run: |
          cargo test
          cargo miri test

Prefer:

jobs:
  test-stable:
    steps:
      - uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: stable
      - name: Run tests
        run: cargo test
        
  test-miri:
    steps:
      - uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: nightly
          components: miri
      - uses: taiki-e/install-action@v2
        with:
          tool: cargo-nextest
      - name: Run miri tests
        run: cargo miri nextest run

This approach avoids confusion about which toolchain is being used for each command and allows jobs to run in parallel, significantly improving pipeline efficiency. Tests that were taking 37 minutes can be reduced to 21 minutes by using optimized tools like cargo-nextest.


optimize algorithms by characteristics

When implementing algorithms, make optimization decisions based on the specific characteristics of your data types and usage patterns rather than using generic approaches. Consider factors like type semantics, memory layout, and processing requirements to choose the most appropriate algorithmic strategy.

For type handling, select operations that preserve type semantics - for example, when processing int vs uint64, use type-specific operations to avoid incorrect processing:

func OP_int() Op {
    switch _INT_SIZE {
    case 32:
        return OP_i32
    case 64:
        return OP_i64
    default:
        panic("unsupported int size")
    }
}
// Add CompatOp to distinguish int from uint64 processing
p.Add(ir.OP_int(), ir.OP_i)

For memory management, tailor initialization strategies based on data characteristics - scan vs noscan types may require different clearing approaches:

// Clear memory for noscan types when makeslice semantics require initialization
if et.PtrData == 0 {
    // Clear [oldLen:newLen] to avoid dirty data for skipped types
}

For compilation algorithms, optimize based on code complexity - simple operations like pointer dereferencing can be fully inlined rather than using generic recursion:

// Inline simple pointer operations instead of increasing recursion depth
for et.Kind() == reflect.Ptr {
    // Handle pointer-specific interfaces before dereferencing
    if pt.Implements(jsonUnmarshalerType) {
        // Handle directly without recursion
        return
    }
    et = pt.Elem()
}

This approach improves both performance and correctness by matching algorithmic choices to the specific requirements and constraints of your data.


API pattern consistency

When designing new API functions, maintain consistent patterns across the codebase and avoid creating precedents that lead to function proliferation or inconsistent interfaces. Consider how the design will scale to similar use cases and whether it aligns with existing API conventions.

For example, instead of adding separate count functions for each data type:

// Avoid this pattern - leads to function proliferation
uint32_t ts_language_supertype_count(const TSLanguage *self);
uint32_t ts_language_field_count(const TSLanguage *self);
uint32_t ts_language_symbol_count(const TSLanguage *self);

// Prefer this pattern - consistent with existing APIs
const TSSymbol *ts_language_supertypes(const TSLanguage *self, uint32_t *length);

Similarly, when deciding between separate namespaces versus unified approaches, consider the actual usage patterns and whether the separation provides meaningful benefits to API consumers. Balance API simplicity with practical usage needs, and document the reasoning behind design decisions to maintain consistency in future additions.


measure performance implications

When making design decisions that could impact performance, evaluate resource implications and provide concrete measurements rather than assumptions. Consider memory usage, binary size, and allocation patterns in your choices.

For API design, prefer memory-efficient data structures when they provide equivalent functionality. For example, use symbol IDs instead of strings when the IDs serve the same purpose but consume less memory and reduce binary size.

When concerned about performance costs, benchmark the actual impact:

// Instead of assuming new/delete is slow, measure it
$ for x in $(echo "1 2 3 4 5"); do time ./out/Test/tests >/dev/null; done
real    0m19.423s  // Before optimization
real    0m20.394s  // After change - minimal impact

Always validate performance assumptions with data, especially for frequently called code paths or resource-constrained environments like WebAssembly.


Numeric API completeness

When designing APIs that handle numeric values, ensure comprehensive support for different integer types (Int64, Uint64) based on range requirements and use case needs. Consider practical constraints such as migration costs and legacy system compatibility when deciding between unified or separate configuration options.

For configuration APIs, provide separate options when legacy compatibility is crucial:

type Config struct {
    // Uint64 into strings on Marshal
    Uint64ToString bool
    // Int64 into strings on Marshal (separate option for migration compatibility)
    Int64ToString bool
}

For data access APIs, provide complete numeric type coverage:

// Int64 casts the node to int64 value
func (self *Node) Int64() (int64, error) { ... }
// Uint64 casts the node to uint64 value (needed for full range support)
func (self *Node) Uint64() (uint64, error) { ... }

This approach ensures APIs can handle the full spectrum of numeric requirements while accommodating real-world migration and compatibility constraints.


Fast deterministic tests

Avoid using real sleeps or delays in tests as they significantly slow down the test suite and can introduce flakiness. Instead, use simulated time with the start_paused parameter for time-dependent tests:

// Instead of this:
#[tokio::test]
async fn slow_test() {
    // This will actually wait 500ms, making tests slow
    tokio::time::sleep(Duration::from_millis(500)).await;
    // test logic...
}

// Do this:
#[tokio::test(start_paused = true)]
async fn fast_test() {
    // This will execute immediately with simulated time
    tokio::time::sleep(Duration::from_millis(500)).await;
    // test logic...
}

For tests that need to respond to events or could potentially hang (like waiting for signals), consider:

  1. Using channels instead of sleeps for synchronization
  2. Setting appropriate timeouts to ensure tests fail clearly rather than hanging indefinitely
  3. Choosing timeout values that are large enough to prevent flakiness but still allow tests to fail fast

With hundreds of tests in the codebase, even small performance improvements per test can significantly reduce the overall test execution time.


verify configuration completeness

Always verify that configuration files completely and accurately specify their requirements. This includes ensuring all related files are included and using appropriate minimum versions or glob patterns.

For package configurations, use glob patterns to include all related files rather than listing them individually:

"files": [
  "dist/binaries/**",
  "dist/src/**", 
  "src/**",
  "load.*"
]

For framework configurations, specify the minimum required version that supports your needs:

"frameworks": {
  "netstandard1.1": {}
}

Before finalizing configuration changes, double-check that all necessary artifacts, dependencies, and version requirements are properly captured to avoid missing components or compatibility issues.


Verify algorithm correctness

Ensure algorithms produce expected results by validating data flow and checking that all execution paths return meaningful values rather than undefined or incorrect results. Pay special attention to conditional logic that filters or processes data, and verify that functions receive the necessary arguments to perform their intended operations.

For example, when implementing filtering logic, ensure all condition branches are properly handled:

// Verify complex conditional logic covers all cases
((typeof listener.options === "boolean" &&
  listener.options === options.capture) ||
  (typeof listener.options === "object" &&
    listener.options.capture === options.capture)) &&
listener.callback === callback

Also validate that functions receive required data to avoid undefined results:

// Ensure functions get necessary arguments for proper execution
function sniffImage(input) {
  // Pass required Uint8Array to algorithm
  return imageTypePatternMatchingAlgorithm(input);
}

Before merging, trace through algorithm execution paths to confirm they produce the intended outputs and handle edge cases appropriately.


Clear technical writing

Ensure technical documentation uses clear, grammatically correct language with consistent formatting when explaining naming conventions and code structure. This includes proper capitalization, precise word choice, consistent code formatting with backticks, and clear sentence structure.

Key practices:

Example of good technical writing:

Modules names in .v files must match the name of their directory.

A .v file `./abc/source.v` must start with `module abc`. All .v files in this directory belong to the same module `abc`. They should also start with `module abc`.

Clear technical writing helps developers understand naming conventions and reduces confusion when implementing code structure requirements.


Complete technical documentation

When documenting technical features, APIs, or data structures, provide comprehensive coverage that includes related functionality and detailed explanations rather than minimal inline comments.

For complex technical concepts, prefer detailed prose explanations that can accommodate full context and examples. When documenting one feature, ensure related features are also covered to provide complete understanding.

For example, instead of:

typedef struct {
  uint32_t row;    // zero-based
  uint32_t column; // zero-based, measured in bytes

Prefer comprehensive prose documentation:

In a point, rows and columns are zero-based. The `row` field represents the number of newlines before a given position, while `column` represents the number of bytes between the position and beginning of the line.

Similarly, when documenting predicates like #any-eq?, also document related predicates like #any-not-eq? to provide complete coverage of the feature set. This approach ensures developers have all necessary information in one place and reduces the need to search for related functionality elsewhere.


Secure resource loading

Always validate and securely load external resources like libraries, configuration files, and modules to prevent tampering and hijacking attacks. When implementing security features that depend on system components:

  1. Use absolute paths rather than relative paths when loading system libraries or resources
  2. Verify that critical components are loaded from trusted locations
  3. Implement appropriate fallback mechanisms for environments that may not support certain security features
  4. Consider platform compatibility and minimum version requirements for security APIs

Example:

// Secure approach - use absolute paths and verify library existence
HMODULE security_module = LoadLibraryExA(
    "C:\\Windows\\System32\\wldp.dll",  // Use absolute path
    NULL, 
    LOAD_LIBRARY_SEARCH_SYSTEM32);      // Restrict search to system directory

// Check if module is available before using its functions
if (security_module != NULL) {
  // Feature is supported, load function pointers
  pfnSecurityFunction = GetProcAddress(security_module, "SecurityFunction");
  if (pfnSecurityFunction != NULL) {
    // Use security feature
  } else {
    // Handle missing function with appropriate fallback
  }
} else {
  // Module not available, implement secure fallback behavior
}

This approach helps prevent attackers from exploiting search path vulnerabilities to load malicious libraries or resources, which could lead to code execution or privilege escalation attacks.


Extract complex inline logic

When functions contain complex inline logic or duplicated code, extract this logic into separate functions or shared utilities to improve readability and maintainability. Complex inline code makes functions harder to understand and test, while duplication creates synchronization issues and increases the likelihood of bugs.

For complex inline logic, create dedicated functions:

// Instead of complex inline logic:
function mapToCallback(context, callback, onError) {
  return async function (req) {
    const asyncContext = getAsyncContext();
    setAsyncContext(context.asyncContext);
    try {
      // ... complex logic here ...
    } finally {
      // ... cleanup logic ...
    }
  };
}

// Extract into a separate function:
function mapToCallback(context, callback, onError) {
  return async function (req) {
    return handleRequestWithContext(req, context, callback, onError);
  };
}

For duplicated code between similar implementations (like sync/async versions), consider:

This approach reduces cognitive load, makes code easier to test, and prevents bugs that arise from maintaining multiple copies of similar logic.


Clarify API documentation

API documentation should provide clear, unambiguous explanations of function behavior, return values, and edge cases. Avoid vague or obscure wording that leaves developers guessing about implementation details.

For return values, explicitly state the conditions that lead to each possible return value rather than using generic phrases. For complex or non-obvious functionality, include practical examples that demonstrate real-world usage scenarios.

Example of unclear documentation:

/**
 * Set the range of bytes or (row, column) positions in which the query
 * will be executed.
 *
 * If the provided range was set, return `true`. Otherwise, return `false`.
 */

Improved version:

/**
 * Set the range of bytes or (row, column) positions in which the query
 * will be executed.
 *
 * This will return false if the start byte/point is greater than the end 
 * byte/point, otherwise it will return true.
 */

For obscure functions, add examples showing practical use cases:

/**
 * Get a child of 'from_parent' which is a parent to the given node.
 * The parent may be indirect.
 *
 * Example: This can be used to efficiently find a path from a root node
 * to traverse up the syntax tree within a specific subtree.
 */

Clear documentation benefits both immediate development and automated tooling like language bindings generation.


validate inputs early

Functions should validate input parameters at the beginning and return appropriate error indicators (like false, null, or error codes) rather than proceeding with invalid data. This prevents downstream errors and provides clear feedback to callers about invalid usage.

Additionally, ensure error states are properly scoped to avoid misleading results when using shared resources or global state. Error status should accurately reflect the state of the specific operation or object being queried.

Example of early input validation with error return:

bool ts_query_cursor_set_byte_range(
  TSQueryCursor *self,
  uint32_t start_byte,
  uint32_t end_byte
) {
  if (end_byte == 0) {
    end_byte = UINT32_MAX;
  } else if (start_byte > end_byte) {
    return false;  // Early validation with clear error signal
  }
  // ... proceed with valid inputs
}

This approach makes error conditions explicit and prevents functions from operating on invalid data, leading to more predictable and debuggable code.


validate algorithm boundaries

Always validate boundary conditions and termination criteria in algorithms to prevent infinite loops, out-of-bounds access, and incorrect behavior. This includes checking loop bounds against variable type limits, validating range parameters, and ensuring proper termination conditions.

Key practices:

Example from loop bounds checking:

// Problem: infinite loop if count > UINT16_MAX
for (TSSymbol i = 0; i < count; i++) { ... }

// Solution: add explicit bounds check
for (TSSymbol i = 0; i < count && i < UINT16_MAX; i++) { ... }

Example from range validation:

// Problem: incorrect logic for range exclusion
if (end_byte <= start_byte && point_lte(end_point, start_point)) { ... }

// Solution: use OR for exclusion checks
bool node_precedes_range = (
  ts_node_end_byte(node) <= self->start_byte ||
  point_lte(ts_node_end_point(node), self->start_point)
);

Proper boundary validation prevents algorithmic failures and improves both correctness and performance by avoiding unnecessary computation on invalid inputs.


Keep code clearly organized

Maintain code readability and organization by extracting focused, well-named functions and using appropriate scoping. Break down complex logic into smaller, focused functions and utilize extension functions when appropriate to improve code clarity.

Key guidelines:

Example - Before:

fun isValidFloat(s: String): Boolean {
    var start = 0
    var end = s.length - 1
    while (start <= end && s[start].code <= 0x20) start++
    if (start > end) return false
    while (end > start && s[end].code <= 0x20) end--
    if (s[start] == '+' || s[start] == '-') start++
    if (start > end) return false
    // ... more complex logic
}

After:

fun isValidFloat(s: String): Boolean {
    val (start, end) = s.findContentBounds() ?: return false
    val (newStart, hasSign) = s.parseSign(start) 
    if (newStart > end) return false
    // ... more focused logic
}

private fun String.findContentBounds(): Pair<Int, Int>? {
    var start = 0
    var end = length - 1
    while (start <= end && this[start].code <= 0x20) start++
    if (start > end) return null
    while (end > start && this[end].code <= 0x20) end--
    return start to end
}

private fun String.parseSign(start: Int): Pair<Int, Boolean> {
    return when (this[start]) {
        '+', '-' -> (start + 1) to true
        else -> start to false
    }
}

Module resolution hierarchy

When configuring TypeScript projects, establish a clear understanding of module and type resolution hierarchies, especially when using different package managers like npm or Yarn’s Plug’n’Play (PnP).

For module resolution configuration:

  1. Use specialized resolution logic for PnP environments rather than fallback approaches to avoid resolution corruptions:
    // For PnP environments, use direct resolution instead of fallbacks
    const searchResult = isPnpAvailable()
     ? tryLoadModuleUsingPnpResolution(Extensions.DtsOnly, typeName, location, moduleState)
     : loadModuleFromNearestNodeModulesDirectory(Extensions.DtsOnly, typeName, location, moduleState);
    
  2. Maintain a consistent resolution priority hierarchy: paths > baseUrl > typeRoots. This order respects specificity, with exact matches taking precedence over general directory searches.

  3. For path validation with package.json imports/exports that use wildcards, ensure appropriate validation flags are set:
    vpath.validate(path, vpath.ValidationFlags.Absolute | vpath.ValidationFlags.AllowWildcard);
    
  4. When working with workspaces that use PnP, be aware that dependencies with peer dependencies are “virtualized” to unique paths that may require special handling in project references.

These practices help avoid resolution conflicts and ensure consistent behavior across different development environments and package manager configurations.


optimize memory layout

Prioritize memory-efficient data structures and algorithms by favoring stack allocation over heap allocation, utilizing bit packing for compact storage, and applying proper bit masking for data integrity. When designing iterators or containers, consider whether operations can avoid dynamic allocation - most backtracking scenarios use empty vectors that don’t require heap allocation. For packed data structures, use bit masking to ensure only valid bits are stored and prevent data corruption.

Example of proper bit masking:

// Instead of direct assignment
flags_.direction = static_cast<uint8_t>(direction);

// Use masking to ensure only valid bits
flags_.direction = static_cast<uint8_t>(direction) & 0x03;

For memory layout optimization, combine related fields to utilize alignment padding:

// Before: wastes alignment bits
bool flag1 : 1;
bool flag2 : 1; 
uint32_t generation = 0;  // 32 bits but alignment wastes space

// After: pack into available bits
bool flag1 : 1;
bool flag2 : 1;
uint8_t generation = 0;  // Fits in remaining alignment space

Always validate that algorithmic optimizations maintain correctness - performance improvements should not compromise the fundamental behavior of the algorithm.


Consistent type algorithms

Implement consistent algorithms for type compatibility and comparison across different data structures. When developing type checking logic, ensure similar operations (like assignment compatibility, intersection, or mapping) behave predictably regardless of the underlying type structure.

For example, when handling tuple types versus object types:

// Ensure consistent behavior between these patterns
// Rest parameter tuple compatibility
type RestTuple = (x: string, ...args: [string] | [number, boolean]) => void;
const handler = (a: string, b: string | number, c?: boolean) => {};
// Should be assignable with consistent rules

// Tuple intersection handling
type A = [number, number] & [string, string];
// Should be handled as position-wise intersection: [number & string, number & string]

// Object vs tuple mapped type behavior
type MappedObj<T> = { [K in keyof T]: T[K] };
type MappedTuple<T extends any[]> = { [K in keyof T]: T[K] };
// Should follow consistent inference patterns

Pay special attention to:

  1. Ensuring type compatibility algorithms handle tuples and objects with equivalent logic
  2. Applying the same principles when intersecting different data structures
  3. Implementing safeguards against circular references that can cause inconsistent state or crashes
  4. Caching intermediate results properly to avoid recomputing complex type relationships

This consistency leads to more predictable type system behavior and fewer edge cases for developers to navigate.


Test diverse configurations

Configure test suites to run under multiple specialized environments to catch issues that might not appear in standard test runs. This includes testing with different compiler configurations, using specialized testing tools, and properly preserving environment variables when adding test-specific flags.

Example:

# In CI workflow
- name: Test with panic=abort
  run: |
    RUSTFLAGS="$RUSTFLAGS -C panic=abort -Zpanic-abort-tests" cargo test --workspace --all-features

- name: Test with memory safety analyzer
  run: |
    cargo miri test --features full --lib --tests --no-fail-fast
  env:
    MIRIFLAGS: -Zmiri-disable-isolation -Zmiri-strict-provenance

When adding new test environments, ensure you don’t overwrite existing environment variables (append instead) and consider the maturity of experimental features when selecting testing configurations.


Test production configurations too

Include testing configurations that mirror production environments to catch issues that might only manifest in release builds. For example, testing with panic=abort can reveal issues that wouldn’t appear when testing with the default panic=unwind setting. Similarly, when using specialized testing tools like Miri, configure the appropriate flags to ensure comprehensive validation under realistic conditions.

Example:

- name: test all --all-features panic=abort
  run: |
    RUSTFLAGS="$RUSTFLAGS -C panic=abort -Zpanic-abort-tests" cargo nextest run --workspace --all-features --tests

When adding new test configurations, always preserve existing environment variables by appending to them rather than replacing them entirely, which ensures that other important configurations remain intact.


target-specific CMake configurations

Use target-specific CMake commands instead of global ones to ensure proper scoping and avoid polluting the global build environment. This improves maintainability and prevents unintended side effects when building multiple targets.

Replace global configuration commands with their target-specific equivalents:

Example:

# Avoid global settings
add_definitions(-D_POSIX_C_SOURCE=200112L -D_DEFAULT_SOURCE)
set(CMAKE_C_FLAGS "-O3 -Wall -Wextra -Wshadow")

# Prefer target-specific settings
target_compile_definitions(tree-sitter PRIVATE _POSIX_C_SOURCE=200112L _DEFAULT_SOURCE)
target_compile_options(tree-sitter PRIVATE -O3 -Wall -Wextra -Wshadow -Wno-unused-parameter -pedantic)

This approach ensures that configuration settings only apply to the intended targets and makes the build system more modular and predictable.


CMake custom command design

When implementing CMake build automation for code generation, carefully choose between add_custom_command and add_custom_target based on your execution requirements. Use add_custom_command with explicit OUTPUT and DEPENDS for files that should be automatically generated when missing or when dependencies change. Add add_custom_target only when you need manual invocation capability in addition to automatic dependency resolution.

Always specify clear OUTPUT, DEPENDS, WORKING_DIRECTORY, and COMMENT parameters to make the build process transparent and debuggable. Test that your custom commands work both automatically (when dependencies change) and can be validated independently.

Example:

# Automatic generation when src/parser.c is missing or grammar.json changes
add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/parser.c"
                   DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/grammar.json"
                   COMMAND "${TREE_SITTER_CLI}" generate src/grammar.json
                            --abi=${TREE_SITTER_ABI_VERSION}
                   WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
                   COMMENT "Generating parser.c")

# Optional: Add target for manual invocation
add_custom_target(generate DEPENDS src/parser.c)

Document the purpose and usage of each custom target to avoid confusion about when automatic vs manual execution occurs.


Use semantic identifiers

Choose semantically appropriate identifiers and types that clearly represent their purpose. This includes using the correct data type (e.g., boolean for flags instead of integers) and ensuring proper spelling of all identifiers.

For boolean flags:

// Not recommended
int reboot_default = 0;  // Using integer for a boolean flag

// Recommended
bool reboot_default = false;  // Clear semantic meaning

For function and variable names:

Using semantically appropriate identifiers improves code readability, reduces bugs, and makes maintenance easier by clearly expressing intent.


Use defensive null checks

When working with properties or methods that could potentially be null, use Kotlin’s null safety features defensively even if you believe the value should never be null. This prevents runtime exceptions when assumptions change or when interacting with Java/third-party code.

Instead of direct access that assumes non-null values:

// Risky: Assumes extensionReceiverParameter, type, and classFqName are all non-null
if (it.owner.extensionReceiverParameter.type.classFqName == receiver) {
    // ...
}

Use safe call chains and provide fallback values:

// Safe: Handles potential nulls gracefully
return classOrNull?.let { 
    it.signature?.asPublic()?.let { sig -> 
        sig.packageFqName == packageName && sig.declarationFqName.matches(typeNameReg)
    }
} ?: false

// Another example with safe call chains
if (it.owner.extensionReceiverParameter?.type?.classFqName == receiver) {
    // ...
}

This approach is especially important when:

Remember that source locations, error reporting systems, and other infrastructure often assume non-null values. Adding defensive checks prevents crashes even when the underlying problem may be elsewhere.


Use absolute paths

When specifying file paths in configuration files (like ESLint or TypeScript configs), use absolute paths rather than relative paths to avoid path resolution issues. Tools may interpret relative paths differently based on their internal working directory, leading to unexpected behavior.

Example:

// Problematic - using relative paths
parserOptions: {
  projectService: true,
  defaultProject: "./scripts/tsconfig.json",
}

// Better - using absolute paths
parserOptions: {
  tsconfigRootDir: __dirname,
  projectService: {
    defaultProject: path.join(__dirname, "scripts", "tsconfig.json"),
  }
}

This practice prevents issues like the one observed where a tool internally calls getParsedCommandLineOfConfigFile with a relative path, but then sets the current working directory incorrectly, causing the wrong file to be loaded.


Use semantic naming

Choose names that clearly communicate the purpose, meaning, and scope of variables, functions, constants, and files. Names should be self-documenting and immediately convey their role to other developers.

For constants, use descriptive names that explain what they represent:

// Instead of unclear naming
const APIKind = apiKind

// Use descriptive enum-style naming
type APIKind uint64
const (
    UseSonicJson = iota
    UseStdJson
)

For function parameters, ensure names accurately reflect their semantic meaning rather than just their type. For file names, avoid unnecessary specificity when broader scope is appropriate (e.g., loader_windows.go instead of loader_windows_amd64.go when architecture constraint isn’t needed).

The goal is to make code self-documenting through meaningful names that reduce the need for additional comments or context to understand their purpose.


Prefer descriptive errors

When handling errors in your code, always provide detailed context in error messages to aid debugging. Use Kotlin’s standard error handling functions instead of directly throwing exceptions or using non-null assertions.

  1. Use error() function with descriptive messages instead of throwing exceptions directly: ```kotlin // Bad if (companion.isCompanion == false) { throw AssertionError() // Unhelpful message }

// Good if (companion.isCompanion == false) { error(“Expected $companion to be a companion object”) }


2. When reporting errors from caught exceptions, preserve cause information:
```kotlin
// Bad
catch (e: IllegalStateException) {
    reportError(e.message!!)
    throw CompilationErrorException()
}

// Good
catch (e: IllegalStateException) {
    reportError("${e.message}\nCaused by: ${e.cause?.javaClass?.name}: ${e.cause?.message}")
    throw CompilationErrorException()
}
  1. Use null-safe operators with descriptive error messages instead of non-null assertions: ```kotlin // Bad val fieldName = getterCall.symbol.owner.name.getFieldName()!!

// Good val fieldName = getterCall.symbol.owner.name.getFieldName() ?: error(“Expected getter call to have a field name”)


4. Include relevant context in assertion messages:
```kotlin
// Bad
assert(companion.isCompanion)

// Good
assert(companion.isCompanion) { "Expected $companion to be a companion object" }

By following these practices, you’ll make your code more maintainable and debugging much easier when errors inevitably occur.


Simplify conditional logic

Improve code readability by simplifying complex conditional expressions and control flow structures. Factor out repeated boolean expressions from nested conditions, use early returns instead of result variables when possible, and consolidate related conditional blocks.

Key practices:

Example of factoring out boolean expressions:

// Instead of:
if ((!is_empty && ts_node_end_byte(node) <= self->start_byte) ||
    (!is_empty && point_lte(ts_node_end_point(node), self->start_point)))

// Use:
if (!is_empty && (
    ts_node_end_byte(node) <= self->start_byte ||
    point_lte(ts_node_end_point(node), self->start_point)))

Example of consolidating conditionals:

// Instead of separate error checks:
if (e == PARENT_DONE) {
  cleanup();
  return TSQueryErrorSyntax;
}
if (e) {
  cleanup();
  return e;
}

// Use unified approach:
if (e) {
  cleanup();
  if (e == PARENT_DONE) e = TSQueryErrorSyntax;
  return e;
}

Follow naming conventions

Choose names that follow established API conventions and guidelines to create a consistent, intuitive codebase:

  1. For conversions or views:
    • Use as_* for cheap, reference-based conversions
      // Prefer this
      fn as_socket(&self) -> socket2::SockRef<'_> {
        socket2::SockRef::from(self)
      }
      // Instead of
      fn to_socket(&self) -> socket2::SockRef<'_>
      
  2. For clarity through qualified names:
    • Prefer context-specific names over generic ones
      // Prefer this
      pub fn sender_strong_count(&self) -> usize
      // Instead of
      pub fn strong_count(&self) -> usize
      
    • Use semantic descriptors over technical ones
      // Prefer this
      pub fn notify_one_last_in(&self)
      // Instead of
      pub fn notify_one_lifo(&self)
      
  3. When using plurals in parameters:
    • Make method names reflect plurality
      // Prefer this
      pub async fn copy_bidirectional_with_sizes<A, B>
      // Instead of
      pub async fn copy_bidirectional_with_size<A, B>
      
  4. Avoid naming conflicts:
    • Don’t add methods with the same name as trait implementations when your type implements Deref
    • For similar functionality, use qualified names
      // Prefer this
      pub fn clone_inner(&'static self) -> T
      // Instead of
      pub fn clone(&'static self) -> T  // Confusing with Clone trait
      

Even when verbosity increases, prioritize clarity and prevention of API confusion. AbortOnDropHandle may be verbose, but it clearly communicates the type’s behavior.


Prefer explicit over concise

Choose explicit and unambiguous names over concise but unclear ones. When a method, type, or variable has a specific behavior or purpose, the name should clearly communicate that, even if it results in longer names.

For example:

While conciseness has value, clarity and explicitness should take precedence when there’s potential for ambiguity or confusion. This principle applies to all identifiers including variables, methods, functions, types, and modules.


Decompose complex algorithms

When implementing algorithms, break down complex methods that handle multiple concerns into smaller, more focused methods. This improves maintainability, makes edge cases easier to handle, and allows for more flexible reuse of algorithm components.

For example, instead of having a single method that handles multiple responsibilities:

static gboolean
get_common_simd_info (MonoClass *vector_klass, MonoMethodSignature *csignature, 
                      MonoTypeEnum *atype, int *vector_size, int *arg_size, int *scalar_arg)
{
    // Complex logic handling multiple concerns:
    // 1. Getting size information
    // 2. Determining element type
    // 3. Finding scalar arguments
    // ...
}

Break it into focused methods with clear responsibilities:

static gboolean
get_common_simd_info (MonoClass *klass, MonoTypeEnum *atype, 
                      int *klass_size, int *arg_size)
{
    // Focus only on getting class size and element type information
}

static int 
get_common_simd_scalar_arg (MonoMethodSignature *csignature)
{
    // Focus only on finding scalar arguments
}

This approach makes algorithms more adaptable to changing requirements, such as supporting additional intrinsics or handling different types of operations. It also simplifies testing and debugging by isolating specific functionality into well-defined methods with clearer purposes.


When designing APIs with related method pairs (such as send/receive, input/output, or request/response), ensure their signatures and parameter structures mirror each other for consistency and developer ergonomics.

Related API methods should have symmetric interfaces that make their relationship clear and predictable. This reduces cognitive load and prevents confusion about how data flows between paired operations.

Example of inconsistent API:

// Inconsistent - send takes separate parameters, callback receives combined object
comm.send(data, buffers);
comm.onMessage(({data, buffers}) => { ... });

Example of consistent API:

// Consistent - both use the same parameter structure
comm.send(data, buffers);
comm.onMessage((data, buffers) => { ... });

This principle applies to any paired operations where data structure or parameter patterns should logically correspond, ensuring developers can easily understand and predict the API behavior based on one method when using its counterpart.


Copy external string inputs

When storing string pointers from external sources (like command-line arguments), always validate the input and create managed copies to prevent null references and lifetime issues. This practice ensures that your stored references remain valid throughout your program’s execution and prevents potential crashes from null or invalid pointers.

Follow these steps when handling external string inputs:

  1. Verify the pointer is valid (check boundary conditions)
  2. Ensure the string isn’t empty when needed
  3. Create a copy with reasonable size limits for persistent storage
// Unsafe approach:
kotlin::programName = argv[0]; // May cause crashes if argc=0 or lifetime issues later

// Safe approach:
if (argc > 0 && argv[0][0] != '\0') {
  kotlin::programName = strndup(argv[0], 4096); // Creates bounded copy with independent lifetime
}

This approach prevents crashes from invalid pointers, protects against potential buffer issues by limiting string length, and eliminates lifetime concerns by managing your own copy of the data.


optimize dependency configurations

When configuring dependencies in package manifests, prioritize efficiency and maintainability by avoiding redundant dependencies, using flexible versioning, and explicitly managing features. Before adding new dependencies, check if existing ones already provide the required functionality. Use version ranges (like “^1.0”) instead of exact pins to allow compatible updates while maintaining stability. When configuring features, disable defaults when not needed and explicitly specify required features for better control.

Example from Cargo.toml:

# Good: Use existing dependency instead of adding new one
dirs = "3.0"  # Already provides home_dir functionality

# Good: Flexible versioning for compatibility  
cc = "^1.0"

# Good: Explicit feature management
regex = { version = "1.10.4", default-features = false, features = ["perf", "unicode"] }

This approach reduces dependency bloat, improves build reliability, and makes version management more predictable across different environments.


Use modern test infrastructure

Always add new tests to the current recommended test infrastructure rather than legacy systems that are being phased out. This reduces technical debt and ensures tests remain maintainable as the codebase evolves.

When adding a new test:

  1. Check if there’s an ongoing migration effort for test infrastructure
  2. Target the new recommended infrastructure
  3. Follow project-specific guidelines for test generation

Example:

// Instead of adding to legacy build.gradle:
// standaloneTest("new_feature") {
//     source = "runtime/new_feature/test.kt"
// }

// Add a proper test class to the new infrastructure:
// e.g., in native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/NewFeatureTest.kt
class NewFeatureTest : AbstractNativeTest() {
    @Test
    fun testNewFeature() {
        // Test implementation
    }
}

For some test types, you may need to run generation tasks after adding new test data files.


maintain backward compatibility

When modifying existing APIs, preserve original parameter types and return signatures to avoid breaking client code. Even when internal implementations change or new functionality is added, the public interface should remain stable for existing consumers.

For example, when extending a Logger to support multiple outputs, maintain the original single-writer constructor:

// Keep original API intact
func New(out io.Writer, prefix string, flag int) *Logger {
    // Internal implementation can adapt to new multi-writer design
}

// Add new functionality separately if needed
func NewMultiWriter(outs []io.Writer, prefix string, flag int) *Logger {
    // New API for enhanced functionality
}

Similarly, when changing return types, ensure the new type is compatible with existing usage patterns or maintain the original signature alongside new variants. This approach protects existing integrations while allowing API evolution.


Code block formatting standards

When documenting code examples and shell commands in project documentation, follow these formatting standards to ensure consistency and clarity:

  1. Use appropriate language specifiers:
    • Use shell rather than bash for shell commands that work in any shell environment
    • cargo install --locked cargo-docs-rs
      
  2. Separate commands from their output:
    • Place commands and their outputs in separate code blocks
    • Label output blocks with text to distinguish them from executable commands
    • cd tokio
      cargo fuzz list
      
      fuzz_linked_list
      
  3. Include safety flags in installation commands:
    • Always use --locked with installation commands to prevent dependency issues
    • cargo install --locked cargo-spellcheck
      
  4. Format spellcheck exceptions properly:
    • Enclose code-related terms in backticks when they’re flagged by spellcheck
    • Add non-code terms to the dictionary file (spellcheck.dic)
    • Remember to update the word count in the dictionary file header

These practices improve documentation readability and help users distinguish between what they should type and what they should expect to see as output.


Clear command documentation

When documenting shell commands in technical documentation, use the shell language identifier instead of bash as commands are typically relevant to any shell. Separate commands and their output into different code blocks to make it clearer what users should actually input. This improves readability and prevents users from accidentally copying output text as if it were commands.

For example, instead of:

$ cd tokio
$ cargo fuzz list
fuzz_linked_list

Use:

cd tokio
cargo fuzz list
fuzz_linked_list

When documenting tool installation commands, include the --locked flag to protect users from dependency issues:

cargo install --locked cargo-docs-rs

This ensures developers can reproduce the exact same environment for development tools.


Write explicit concrete tests

Tests should be written explicitly with concrete examples and clear assertions rather than being generated programmatically or hidden in utility code. This improves test readability, maintainability, and debugging capabilities.

Key principles:

Example of preferred approach:

// Instead of generated tests in loops
#[test]
fn test_consecutive_zero_or_modifiers() {
    // Prefer explicit test cases
    let query1 = Query::new(language, "(comment)*** @capture").unwrap();
    let query2 = Query::new(language, "(comment)??? @capture").unwrap();
    
    // With specific assertions about expected behavior
    assert_eq!(matches1.len(), 3);
    assert_eq!(matches2.len(), 1);
}

// Add assertions to doc tests
//! let tree = parser.parse(code, None).unwrap();
//! assert!(!tree.root_node().has_error());

This approach makes tests easier to understand, debug, and maintain while ensuring that test behavior is predictable and well-documented.


Memory ordering needs justification

When using atomic operations, explicitly justify the choice of memory ordering. Each use of a memory ordering should be documented with a clear explanation of why that specific ordering is sufficient and safe.

Key guidelines:

Example:

impl<T> Clone for Sender<T> {
    fn clone(&self) -> Self {
        // Relaxed is sufficient for incrementing the reference count
        // since no synchronization is needed - the sender is already
        // guaranteed to be valid when Clone is called
        self.shared.ref_count.fetch_add(1, Relaxed);
        Self { shared: self.shared.clone() }
    }
}

impl<T> Drop for Sender<T> {
    fn drop(&mut self) {
        // AcqRel ordering required for reference count decrement
        // to synchronize with other threads that may be checking
        // if this is the last sender
        if self.shared.ref_count.fetch_sub(1, AcqRel) == 1 {
            self.shared.close();
        }
    }
}

Names express clear intent

Choose names that clearly express intent and follow established conventions. Prefer explicit, descriptive names over abbreviations or ambiguous terms. Align with platform-specific naming patterns and maintain consistency with existing codebase conventions.

Key guidelines:

Example:

// Incorrect
enum class WalkAlgorithm {
    BFS,  // Abbreviated
    DFS   // Abbreviated
}

// Correct
enum class WalkAlgorithm {
    BREADTH_FIRST,  // Explicit
    DEPTH_FIRST    // Explicit
}

Design extensible stable APIs

When designing public APIs, prioritize extensibility while maintaining backward compatibility and implementation hiding. This ensures APIs can evolve without breaking existing clients while allowing for future enhancements.

Key principles:

  1. Never change visibility levels of public API elements
  2. Use flexible extension mechanisms instead of fixed enums
  3. Keep implementation details in separate packages
  4. Design clear extension points for third-party implementations

Example:

// Instead of enum-based priority
enum class Priority { LOW, NORMAL, HIGH } // Difficult to extend

// Use comparable class
class Priority(val value: Int) : Comparable<Priority> {
    companion object {
        val LOW = Priority(0)
        val NORMAL = Priority(1000)
        val HIGH = Priority(2000)
    }
    
    override fun compareTo(other: Priority): Int = 
        value.compareTo(other.value)
}

// This allows third parties to insert custom priorities
val CUSTOM = Priority(1500) // Between NORMAL and HIGH

This approach:


Configure socket blocking behavior

Always explicitly configure socket blocking behavior when creating TCP connections, and provide compile-time flags for backwards compatibility when changing default behaviors.

When establishing TCP connections, don’t rely on implicit socket blocking settings. Instead, explicitly set the blocking mode after connection creation. When changing default socket behavior, use compile-time conditional compilation to allow users to opt into the previous behavior if needed.

Example implementation:

mut conn := &TcpConn{
    sock: s
    read_timeout: net.tcp_default_read_timeout
    write_timeout: net.tcp_default_write_timeout
}
$if !net_nonblocking_sockets ? {
    conn.set_blocking(true)!
}

This pattern ensures that:

Apply this approach consistently across all TCP connection creation points including dial_tcp(), dial_tcp_with_bind(), and TcpListener.accept().


Use semantic naming

Choose semantic, logical names that describe purpose and intent rather than physical characteristics or implementation details. This improves code maintainability, internationalization support, and clarity.

For CSS properties, prefer logical properties over directional ones:

// Instead of physical directions
'margin-left', 'margin-right'

// Use logical directions  
'margin-inline-start', 'margin-inline-end'
'inset-inline-start', 'inset-inline-end'

For API parameters and types, use precise, descriptive names that clearly communicate expected values:

// Instead of generic types
setMargin(edge: Edge, margin: number | string): void

// Use specific, semantic types
setMargin(edge: Edge, margin: number | 'auto' | `${number}%`): void

This approach creates more robust, internationally-friendly code that better expresses developer intent and reduces ambiguity about expected values or behavior.


avoid eval() function

The eval() function executes arbitrary JavaScript code from strings, creating significant security vulnerabilities including code injection attacks. This is especially dangerous when processing external data like API responses, user input, or browser logs that could contain malicious code.

Use safer alternatives for common use cases:

Example of the security issue:

// Dangerous - can execute arbitrary code
const result = eval(logs[0].message.replace(/^[^"]*/, ''));

// Safe - only parses JSON data
const result = JSON.parse(logs[0].message.replace(/^[^"]*/, ''));

Modern linters and security scanners typically flag eval() usage. If eval() is absolutely necessary, ensure the input is thoroughly validated and sanitized, though this approach is strongly discouraged.


Use benchmarked thresholds

Base performance-critical constants, limits, and thresholds on empirical benchmarking rather than arbitrary values. When implementing optimizations that involve numeric parameters—such as buffer size limits, inlining costs, or caching thresholds—conduct systematic benchmarking to determine optimal values and document the rationale.

For memory management decisions, establish limits that balance performance gains with resource efficiency:

func cacheEncodeState(e *encodeState) {
    // Threshold determined through benchmarking to balance 
    // memory efficiency vs. performance gains
    if e.Buffer.Cap() > 32768 {
        return // Don't cache large buffers
    }
    // ... cache the state
}

const (
    // 57 was benchmarked to provide most benefit with no bad surprises
    inlineExtraCallCost = 57
    // These values were benchmarked to provide most benefit
    inlineBigForCost = 105
)

When creating benchmarks, separate different scenarios to get granular performance data rather than combining multiple cases. This enables more precise optimization decisions and helps identify the specific conditions where performance improvements matter most.


prevent off-by-one errors

When implementing algorithms that involve spacing, gaps, or iterative calculations, carefully verify loop bounds and edge cases to prevent off-by-one errors. These errors commonly occur when calculating spacing between N items (which requires N-1 gaps, not N gaps) or when applying operations to boundary elements.

Key areas to scrutinize:

Example from gap calculation:

// Wrong: adds gap for all children (N gaps for N items)
for (int i = 0; i < childCount; i++) {
    mainDim += childSize + betweenMainDim;
}

// Correct: adds gap only between children (N-1 gaps for N items)  
const bool isLastChild = i == childCount - 1;
if (isLastChild) {
    betweenMainDim -= gap; // Remove gap for last item
}

Always validate your algorithm with boundary cases: single item, empty collection, and maximum expected size. Consider whether conditional checks like if (lineCount > 1) are truly necessary or artifacts of avoiding edge case bugs.


Enhance error message clarity

Error messages should be both specific about what went wrong and provide contextual information to help developers locate and fix the issue. Even in performance-critical or low-level APIs, basic validation with clear error messages is essential because “there’s no easy way for the developer to get feedback on failures” otherwise.

When validation fails, provide specific details about the invalid input and acceptable ranges or formats. Additionally, include contextual information such as stack traces to help developers identify the source of the error.

Example of good error messaging:

// Specific error with details about what's wrong and what's expected
throw new RangeError(`The status provided (${status}) is not equal to 101 and outside the range [200, 599].`);

// Adding contextual information to warnings
console.warn(
  "Prototype access via __proto__ attempted; __proto__ is not implemented in Deno due to security reasons. Use Object.setPrototypeOf instead.",
  new Error().stack
);

This approach balances performance considerations with developer experience by providing minimal but meaningful validation and clear guidance on how to resolve issues.


Consider operation time complexity

When implementing operations that manipulate collections or perform repeated actions, carefully consider the time complexity implications. Avoid operations that could result in unexpected quadratic or worse complexity. Pay special attention to:

  1. Collection modifications that shift elements
  2. Nested loops or repeated operations on growing datasets
  3. Data structure choice based on access patterns

Example of problematic implementation:

// BAD: O(n²) complexity
fun <E> ArrayList<E>.addAll(index: Int, elements: Collection<E>) {
    var i = index
    elements.forEach { element ->
        array.asDynamic().splice(i, 0, element) // Shifts array on each insert
        i++
    }
}

// BETTER: O(n) complexity
fun <E> ArrayList<E>.addAll(index: Int, elements: Collection<E>) {
    // Single array modification with all elements
    array.asDynamic().splice(index, 0, *elements.toTypedArray())
}

Choose data structures based on your specific use case:


Respect environment overrides

Build systems and configuration scripts must respect standard environment variables and provide proper override mechanisms. This ensures flexibility for users with different build environments, cross-compilation needs, and custom toolchain requirements.

Always use the ?= operator in Makefiles to set defaults while allowing environment overrides, and use override += to append mandatory flags:

# Allow environment override with sensible defaults
CFLAGS ?= -O3 -Wall -Wextra
CC ?= clang
# Append mandatory flags that cannot be overridden
override CFLAGS += -std=gnu11 -fPIC -Ilib/include

For configuration detection, provide compiler flag overrides as escape hatches:

// Allow compile-time override while providing automatic detection
#if !defined(TS_BIG_ENDIAN)
#if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#define TS_BIG_ENDIAN 1
#else  
#define TS_BIG_ENDIAN 0
#endif
#endif

Never hardcode or remove the ability to override critical build variables like CC, CFLAGS, CXXFLAGS, or LDFLAGS. Users may need to specify custom compilers, cross-compilation toolchains, or additional flags for their specific build environments. This principle applies to all build systems including Makefiles, CMake, and custom build scripts.


Function documentation standards

Function documentation comments must follow Go conventions by starting with the function name, and all parameters should have clear explanations of their purpose and current functionality.

In Go, documentation comments for functions should begin with the function name followed by a description of what it does. Additionally, when functions have parameters that may not be immediately clear, especially those with evolving functionality, include comments that explain their current purpose.

Example of proper function documentation:

// WithCompileRecursiveDepth sets the depth of recursive compile for decoder and encoder.
func WithCompileRecursiveDepth(depth int) CompileOption {
    // implementation
}

// OnObjectBegin handles the beginning of a JSON object value with a
// suggested capacity that can be used to make your custom object container.
// Currently, capacity primarily indicates whether this is an empty node.
func OnObjectBegin(capacity int) error {
    // implementation  
}

This ensures that developers can quickly understand function behavior and parameter usage, while also documenting current limitations or evolving functionality for future reference.


validate memory bounds

Always validate array and string bounds before accessing memory to prevent out-of-bounds access and potential crashes. When working with strings or arrays, especially those with known length information, check indices against the actual length before dereferencing pointers.

Key practices:

Example from the codebase:

// Before accessing pos[i], always check bounds
if (i >= src->len) {
    return ERR_INVAL;  // Handle out-of-bounds case
}

// In string comparison, use length-bounded operations
static int _strcmp(const char *p, const char *q, size_t max_len) {
    size_t i = 0;
    while (i < max_len && *p && *q && *p == *q) {
        p++; q++; i++;
    }
    // Safe comparison within bounds
}

This prevents accessing invalid memory addresses that could lead to undefined behavior, crashes, or security vulnerabilities.


Consistent semantic naming

Maintain consistent naming conventions throughout the codebase and use semantically clear identifiers that clearly indicate their purpose and behavior. All functions, variables, and other identifiers should follow the same naming style (preferably snake_case for C code) and have descriptive names that make their functionality obvious.

Key principles:

  1. Consistency: Use the same naming convention across all code. Don’t mix camelCase and snake_case within the same project.
  2. Semantic clarity: Choose names that clearly indicate what the function does and what it returns, avoiding generic terms.
  3. Global application: Apply naming standards consistently across the entire codebase.

Example improvements:

// Before: Mixed styles and unclear names
bool isSpace(char a);
bool isInteger(char a); 
int charToNum(char c);
bool compare(MapPair lhs, MapPair rhs);

// After: Consistent snake_case and clear semantics
bool is_space(char a);
bool is_integer(char a);
int char_to_num(char c);
bool less_than(MapPair lhs, MapPair rhs);

This ensures code readability and maintainability by eliminating confusion about naming patterns and making function purposes immediately clear to other developers.


bounds checking first

Always validate array and buffer bounds before accessing elements to prevent out-of-bounds access and potential security vulnerabilities. This is critical in algorithms that iterate through data structures or perform string operations.

The pattern should be: check bounds first, then access content. Never assume data is within bounds without explicit validation.

Example of incorrect approach:

// Dangerous - no bounds check
while(is_space(pos[i])) {
    i++;
}

Example of correct approach:

// Safe - bounds check before content check  
while(!is_overflow(i, srclen) && is_space(pos[i])) {
    i++;
}

In string comparison algorithms, ensure you don’t continue comparing beyond the shorter string’s length. When the compared portions are equal, the longer string should be considered greater without accessing potentially invalid memory locations.

This principle applies to all array-based algorithms including parsing, sorting, searching, and string manipulation operations.


consistent code formatting

Maintain consistent indentation and brace alignment throughout the codebase to improve readability and code organization. Use 4-space indentation consistently across all files and align closing braces with their corresponding opening statements.

Key formatting requirements:

Example of proper formatting:

while(pos[i] !='\0'){
    if(k==arr->cap){
        *p = i+1;
        return ERR_RECURSE_MAX;
    }
    while(is_space(pos[i])){
        i++;             
    }
}

Consistent formatting makes code easier to read, debug, and maintain. It also helps team members quickly understand code structure and reduces cognitive load when reviewing or modifying code.


Meaningful comment practices

Comments should explain the reasoning behind code decisions rather than restating what the code obviously does. Focus on the “why” rather than the “what” to provide value that isn’t immediately apparent from reading the code itself.

For placement, longer explanatory comments should be written on separate lines above the relevant code block. API documentation and function descriptions should be positioned above the function declaration, not inline or scattered throughout the implementation.

Example of poor commenting:

while(isSpace(pos[i])){    // If there is a space before the beginning, eat the space first 
    i++;                           
}
if(pos[i] != '['){         // If the first one is not a left bracket, returning it directly is illegal
    *p = i+1;              // P points to the first position after the error 
    arr->len = 0;
    return ERR_INVAL;
}

Example of improved commenting:

// Skip leading whitespace to handle malformed input gracefully
while(isSpace(pos[i])){                                  
    i++;                           
}

// Array format must start with '[' - reject invalid syntax early
if(pos[i] != '['){
    *p = i+1;
    arr->len = 0;
    return ERR_INVAL;
}

For API functions, place comprehensive documentation above the function:

// Parses a JSON-like array string into GoIntSlice structure
// Returns error code on invalid format, updates position pointer
long decode_u64_array(const GoString* src, long* p, GoIntSlice* arr){
    // implementation...
}

Keep configuration versions current

Regularly review and update version specifications in configuration files to align with current standards and internal practices. When updating versions, consider both the benefits of newer features and potential compatibility impacts.

Configuration files should specify reasonably current versions of tools, languages, and frameworks rather than outdated minimums. However, version bumps should be planned carefully, especially for major version changes that might affect compatibility.

Ensure consistency across different build systems and package managers. If updating one configuration file, check related configurations to maintain alignment.

Example from Package.swift:

// Consider updating from older versions
swift-tools-version:5.3  // → swift-tools-version:5.8
cxxLanguageStandard: .cxx14  // → .cxx17 (when appropriate)

// Also check related configurations like CocoaPods
// to maintain consistency across build systems

Before updating, evaluate the trade-offs between staying current and maintaining stability, especially in widely-used libraries where breaking changes can impact many users.


Improve code readability

Enhance code clarity and maintainability by applying several readability techniques: extract repeated expressions into well-named variables, simplify complex boolean logic, use proper constant declarations, and remove redundant code that sets default values.

Key practices:

Example of extracting repeated expressions:

// Before
child->getLeadingPosition(mainAxis, node->getLayout().measuredDimensions[dim[mainAxis]])
child->getLeadingMargin(mainAxis, node->getLayout().measuredDimensions[dim[mainAxis]])

// After  
const auto mainAxisDim = node->getLayout().measuredDimensions[dim[mainAxis]];
child->getLeadingPosition(mainAxis, mainAxisDim)
child->getLeadingMargin(mainAxis, mainAxisDim)

Preserve API compatibility first

When modifying existing APIs, maintain backwards compatibility by adding new overloads rather than directly changing existing signatures. Mark old signatures as deprecated when introducing new patterns, but keep them functional until a major version change.

Example: Instead of breaking change:

// Before
function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): RenameLocation[];

// Don't directly modify to:
function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, preferences: UserPreferences): RenameLocation[];

Add deprecation with overload:

// Do this instead:
function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, preferences: UserPreferences): RenameLocation[];
/** @deprecated Pass `providePrefixAndSuffixTextForRename` as part of a `UserPreferences` object. */
function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): RenameLocation[];

This approach:

  1. Prevents breaking changes for existing consumers
  2. Provides clear migration path through deprecation notices
  3. Allows gradual adoption of new patterns
  4. Maintains API stability while enabling evolution

wrap errors properly

When creating error messages that include information from underlying errors, use fmt.Errorf with the %w verb instead of string concatenation with err.Error(). This preserves the error chain, enabling proper error unwrapping and better debugging capabilities.

String concatenation breaks the error chain and prevents tools and code from accessing the original error:

// Bad: breaks error chain
return nil, errors.New("x509: failed to serialize extensions attribute: " + err.Error())

// Good: preserves error chain
return nil, fmt.Errorf("x509: failed to serialize extensions attribute: %w", err)

The wrapped error can then be unwrapped using errors.Unwrap() or checked with errors.Is() and errors.As(). Consider documenting when your functions return errors that implement Unwrap() []error method to make the unwrapping behavior explicit to callers.


Standardize build configurations

Maintain consistent and standardized build configurations across the project to improve maintainability and reduce errors:

  1. Centralize dependency management - Use shared dependency declarations rather than hardcoding versions in individual module build files. This ensures consistency across the project and makes version updates simpler.

    // Instead of:
    testImplementation("com.google.code.gson:gson:2.8.9")
       
    // Prefer using centralized dependency management:
    testImplementation(commonDependency("com.google.code.gson:gson"))
    
  2. Avoid duplicating configurations - Don’t repeat configuration code that’s already defined in parent or root projects. Reference or inherit from common configurations instead.

  3. Prefer Kotlin DSL - For new modules, use .gradle.kts (Kotlin) scripts rather than .gradle (Groovy) scripts to benefit from type safety, better IDE support, and consistency with the broader codebase.

By following these practices, you’ll reduce configuration drift, make updates more manageable, and maintain a more consistent build environment.


standardize build configurations

Ensure build configurations are consistently propagated through all build steps and output directories follow standardized patterns. This prevents configuration mismatches that can cause deployment issues and makes CI/CD pipelines more reliable.

Key practices:

Example from CMake integration:

<Exec Command="cmake -S . -B build -DCMAKE_INSTALL_PREFIX=binnative -DCMAKE_BUILD_TYPE='$(Configuration)' &amp;&amp; cmake --build build --target install --config $(Configuration)" />

Example for consistent output directories:

<OutDir>bin\$(PlatformTarget)\$(Configuration)\</OutDir>

This standardization ensures that debug/release configurations are properly handled across the entire build pipeline and that all artifacts end up in predictable locations for packaging and deployment.


Use appropriate CI toolchains

Ensure CI/CD workflows use technology-specific setup actions and execute commands in the correct working directories. Avoid using generic or unrelated setup actions that install unnecessary toolchains, as this increases build time and complexity. Always specify the appropriate working directory for technology-specific commands to ensure they execute in the correct context.

For example, replace generic setup actions with technology-specific ones:

# Instead of using setup-js for C# builds
- name: Setup
  uses: ./.github/actions/setup-js

# Use C#-specific setup
- name: Setup
  uses: ./.github/actions/setup-cs

And ensure commands run in the correct directory:

- name: Restore Workloads
  run: dotnet workload restore
  working-directory: csharp

This practice improves build reliability, reduces unnecessary dependencies, and makes CI configuration more maintainable and understandable.


Measure optimization trade-offs

Always measure and document the impact of performance optimizations before implementing them. When making optimization decisions, quantify the benefits (size reduction, speed improvement) against the costs (build time, code complexity, maintainability).

Key practices:

Example from compiler optimizations:

# Measured impact: 10kb size reduction
-fno-exceptions -fno-rtti  # Disables C++ features for size savings
-flto                      # Link-time optimization for performance (2x build time)

Example from memory optimization:

// Before: 12 bytes overhead per node (4 + 8 bytes)
struct YGNode {
    uint32_t gDepth = 0;        // 4 bytes per node
    YGNodeRef pRoot = nullptr;  // 8 bytes per node
};

// After: Pass values through function parameters instead
void calculateLayout(YGNode* node, uint32_t depth, uint32_t generation);

This approach ensures optimizations provide real value and helps teams make informed decisions about performance trade-offs.


prevent prototype pollution

When implementing security measures around JavaScript’s __proto__ property, disable the setter to prevent prototype pollution attacks while carefully considering whether getter access is needed for compatibility. Prototype pollution occurs when attackers can modify Object.prototype, potentially affecting all objects in the application.

Use Object.defineProperty to disable the setter while optionally preserving getter functionality:

// Disables setting `__proto__` and emits a warning instead, for security reasons.
Object.defineProperty(Object.prototype, "__proto__", {
  get: Object.prototype.__proto__, // Keep getter if needed for compatibility
  set: function() {
    console.warn("Setting __proto__ is disabled for security reasons");
  }
});

Consider the compatibility impact on dependencies that may rely on __proto__ functionality. In environments where no user code executes (like TypeScript compilation), completely removing __proto__ access may be appropriate. For runtime environments, emitting warnings helps identify problematic dependencies while maintaining security.


automate frequent releases

Implement automated release workflows to publish updates frequently and consistently across all distribution channels. Manual release processes create bottlenecks that force consumers to pin dependencies to specific commit SHAs instead of using stable releases.

Set up CI/CD pipelines that automatically publish to all relevant package managers (crates.io, NPM, GitHub releases) after each merged PR or batch of changes. This reduces maintenance overhead and ensures consumers can rely on regular releases rather than tracking development commits.

Example automation approach:

# .github/workflows/release.yml
on:
  push:
    branches: [main]
jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Publish to crates.io
        run: cargo publish
      - name: Publish Node.js bindings to NPM
        run: npm publish
      - name: Create GitHub release with artifacts
        run: gh release create v${{ env.VERSION }}

Frequent automated releases eliminate the need for consumers to pin to commit SHAs and ensure that fixes and improvements reach users promptly without requiring manual intervention from maintainers.


Use proper network constants

When writing network-related code, always use named constants from system packages instead of magic numbers, and ensure complete protocol implementation. This includes using proper constants for network operations (like windows.IfOperStatusUp instead of 0x01), calculating buffer sizes correctly with system functions (like syscall.CmsgSpace(4) for file descriptor passing), and setting absolute deadlines with time.Now().Add() rather than relative durations.

Additionally, avoid making assumptions about network infrastructure - for example, don’t assume req.TLS != nil indicates HTTPS when TLS termination might occur at a load balancer. Always implement complete test scenarios that actually exercise the network paths being tested.

Example of proper constant usage:

// Bad: magic number
if aa.OperStatus != 0x01 {
    continue
}

// Good: named constant  
if aa.OperStatus != windows.IfOperStatusUp {
    continue
}

// Bad: hardcoded buffer size
oob := make([]byte, 32)

// Good: calculated buffer size
oob := make([]byte, syscall.CmsgSpace(4))

This approach makes network code more maintainable, portable, and less prone to subtle bugs related to protocol assumptions or system-specific values.


Enforce style in CI

Configure automated formatting tools in CI/CD pipelines to enforce code style standards rather than silently fix violations. Use validation flags that cause the build to fail when formatting issues are detected, and ensure all commands run non-interactively.

For installation commands, always include flags to avoid user prompts:

run: sudo apt-get install -y clang-format-${{ inputs.version }}

For formatting validation, use flags that check without modifying files and exit with error codes:

run: npx --yes google-java-format --set-exit-if-changed --dry-run --glob=java/**/*.java

This approach catches style violations early in the development process and maintains consistent code formatting across the entire codebase by making compliance mandatory rather than optional.


Evaluate synchronization necessity

Before implementing thread safety mechanisms like atomic operations or mutexes for global variables, critically assess whether perfect synchronization is actually required for program correctness. Consider the performance cost of synchronization against the importance of data accuracy.

Many global variables, especially counters or flags, may not require strict synchronization if approximate or eventually consistent values are sufficient for the use case. For example, instance counters used only for testing or debugging may not justify the synchronization overhead.

Example of unnecessary synchronization:

// Before: Adding atomic for test-only counter
std::atomic<int32_t> gNodeInstanceCount(0);  // Causes bus overhead

// After: Conditional compilation or accepting approximate values
#ifdef YOGA_TESTING
int32_t gNodeInstanceCount = 0;  // Only precise in single-threaded tests
#endif

Example of questioning atomic necessity:

// Before: Automatic atomic usage
std::atomic<uint8_t> gCurrentGenerationCount{0};

// Consider: Does increment accuracy matter?
// If the purpose is just to invalidate caches and trigger recalculations,
// occasional missed increments may be acceptable and avoid synchronization costs
uint8_t gCurrentGenerationCount = 0;  // Simple increment, accepts race conditions

Key evaluation criteria:

  1. Is perfect accuracy required for correctness?
  2. What is the performance impact of synchronization?
  3. Can the system tolerate approximate or eventually consistent values?
  4. Are there alternative designs that avoid shared state entirely?

This approach prevents over-engineering thread safety solutions and maintains better performance in concurrent systems.


Design familiar APIs

Design APIs that align with platform conventions and user expectations rather than creating novel patterns. APIs should feel natural to developers already familiar with the target platform’s idioms and established libraries.

When designing public interfaces, prioritize consistency with existing platform patterns over internal implementation convenience. For example, if your platform typically uses individual properties for layout values, follow that pattern even if it creates a larger API surface:

// Preferred: Matches UIKit conventions
@property (nonatomic) CGFloat paddingLeft;
@property (nonatomic) CGFloat paddingTop;
@property (nonatomic) CGFloat paddingStart; // RTL support

// Rather than novel approaches that break familiar patterns
- (void)setPadding:(CGFloat)padding forEdge:(YGEdge)edge;

Additionally, keep internal implementation details private. Helper functions and utilities should not be exposed in public headers just because they’re convenient for internal use:

// Wrong: Internal helpers in public API
template<typename T, typename... A>
T* YGAllocate(A&&... arguments) { /* internal helper */ }

// Right: Keep internal helpers in private headers

Make APIs explicit and unambiguous by requiring all necessary parameters rather than providing multiple variants. This forces developers to think about important decisions like units, reduces API surface area, and prevents ambiguous usage patterns.


Maintain consistent formatting

Ensure all code follows the established project formatting standards consistently across the codebase. This includes adhering to specific indentation rules, import statement formatting, and other style conventions defined for the project. When contributing code, always match the existing formatting patterns rather than introducing inconsistencies.

For example, if the project uses four-space indentation and single-quote import packages:

//go:build !amd64

package sonic

import (
    'reflect'  // single quote import
)

func example() {
    // four space indentation
    if condition {
        doSomething()
    }
}

Additionally, remove unused or debug code entirely rather than leaving it commented out, as this keeps the codebase clean and maintainable. Consider using automated formatting tools like gofmt to ensure consistency and reduce manual formatting errors.


Minimize not-null assertions

Avoid using not-null assertions (!!) when safer alternatives exist. Instead:

  1. Use safe calls (?.) when accessing properties or methods on nullable references
  2. Use the elvis operator (?:) to provide default values
  3. Implement early returns with explicit null checks when appropriate

For example, instead of:

val result = nullableValue!!.doSomething()

Prefer:

// Safe call with elvis operator
val result = nullableValue?.doSomething() ?: defaultValue

// Or early return with null check
if (nullableValue == null) {
    return defaultValue // or handle the null case appropriately
}
val result = nullableValue.doSomething()

This pattern reduces the risk of NullPointerExceptions and makes code more robust. When reviewing code, look for unnecessary not-null assertions that could be replaced with safer constructs, as shown in the UnnecessaryNotNullAssertionFix class. Additionally, follow the pattern seen in the expression typing code where early returns are used when a descriptor is null.


Use meaningful identifiers

Choose identifiers that accurately represent their purpose, semantics, and relationship to the codebase. Names should be self-documenting and consistent with established patterns in the module or API.

Key principles:

Example of good naming:

// Good: Clear ownership semantics
static inline void analysis_state_set__push_by_clone(
  AnalysisStateSet *self,
  AnalysisState *borrowed_item  // Clearly indicates caller retains ownership
) {
  // ...
}

// Good: Consistent API prefix and self-documenting hex value
int ts_language_symbol_type_is_named(const TSLanguage *self, TSSymbol typeId) {
  // Use 0x25A1 instead of 9633 for Unicode box character □
  while (iswspace(lexer->lookahead) || 0x25A1 == lexer->lookahead) {
    // ...
  }
}

Use meaningful prefixed names

Names should be semantically meaningful and properly prefixed to prevent namespace conflicts. In C, enum variants and global identifiers are added to the top-level namespace, so prefix them with their type name even if repetitive. Choose names that reflect domain concepts and purpose rather than technical implementation details. Prioritize clarity over brevity by spelling out words fully.

Examples:

This prevents naming conflicts, improves code readability, and makes the codebase more maintainable by clearly indicating the purpose and scope of each identifier.


Cache expensive computations

Identify and cache the results of expensive computations to avoid redundant calculations, especially in performance-critical code paths. This includes recursive functions, user-defined callbacks, and complex arithmetic operations that may be called multiple times with the same inputs.

When reviewing code, look for:

Example of caching expensive baseline calculations:

// Before: Calling YGBaseline multiple times
if (alignItem == YGAlignBaseline) {
  leadingCrossDim += collectedFlexItemsValues.maxBaselineAscent - YGBaseline(child);
}
// Later in code...
someOtherValue = YGBaseline(child); // Redundant call

// After: Cache the result in child layout
// At algorithm start: child->getLayout().cachedBaseline = YGBaseline(child);
if (alignItem == YGAlignBaseline) {
  leadingCrossDim += collectedFlexItemsValues.maxBaselineAscent - child->getLayout().cachedBaseline;
}

This optimization is particularly important for functions that are recursive, call user-defined callbacks, or are executed in tight loops where performance matters most.


Prevent test resource leaks

Always ensure proper cleanup of resources in tests to prevent memory leaks. When using EmbeddedChannel, call readOutbound() to process all expected buffers and finish() at the end of your test to verify no resources remain and release any remaining buffers. This is particularly important for tests involving data buffers, channels, and I/O operations.

Example:

@Test
public void testBufferHandling() {
    EmbeddedChannel channel = new EmbeddedChannel(new YourHandler());
    
    // Write test data
    channel.writeInbound(Unpooled.wrappedBuffer(testData));
    
    // Read and verify all expected results
    ByteBuf result1 = channel.readInbound();
    assertEquals(expectedData1, result1);
    result1.release();
    
    ByteBuf result2 = channel.readInbound();
    assertEquals(expectedData2, result2);
    result2.release();
    
    // Ensure channel is properly closed and no resources are leaked
    assertFalse(channel.finish());
}

This pattern prevents resource leaks that can accumulate during test runs and ensures that your tests properly validate the complete processing of data.


Centralize platform configurations

Platform-specific code and API usage should be centralized in designated configuration files rather than scattered throughout the codebase. When adding code that might not be available on all supported platforms:

  1. Use feature detection via CMake’s check_symbol_exists or similar mechanisms
  2. Define feature macros in a central configuration file
  3. Use conditional compilation based on these macros
  4. Consider adding polyfills for platforms missing specific APIs

For example, instead of embedding platform checks throughout your code:

// Not recommended: platform-specific code scattered in implementation
void* SystemNative_AlignedAlloc(uintptr_t alignment, uintptr_t size)
{
#if defined(__APPLE__)
  // macOS-specific implementation
#elif defined(__linux__)
  // Linux-specific implementation
#endif
}

// Recommended: Use centralized feature detection
#include "pal_config.h" // Contains centrally defined HAVE_* macros

void* SystemNative_AlignedAlloc(uintptr_t alignment, uintptr_t size)
{
#if HAVE_ALIGNED_ALLOC
  return aligned_alloc(alignment, size);
#elif HAVE_POSIX_MEMALIGN
  void* result = NULL;
  return posix_memalign(&result, alignment, size) == 0 ? result : NULL;
#else
  // Fallback implementation for platforms without native support
  return malloc(size);
#endif
}

This approach improves maintainability, makes configuration audits easier, and centralizes knowledge about platform differences.


Dependency verification configuration

When adding new dependencies to build.gradle.kts files, always update the corresponding verification metadata to prevent build failures. Use the Gradle command ./gradlew --write-verification-metadata md5,sha256 help to generate the necessary metadata, but review the output carefully as it may add more dependencies than required. Consider manually adding only the necessary verification entries if the automated command adds excessive dependencies.

Example workflow:

// 1. Add dependency to build.gradle.kts
dependencies {
    implementation("io.github.java-diff-utils:java-diff-utils:4.10")
}

// 2. Generate verification metadata
// Run: ./gradlew --write-verification-metadata md5,sha256 help

// 3. Review generated changes in verification-metadata.xml and retain only necessary entries
<component group="io.github.java-diff-utils" name="java-diff-utils" version="4.10">
  // Keep only required verification entries
</component>

Document security implementations

Always document non-obvious security implementations, especially authentication mechanisms, with explanatory comments and references to underlying implementation details or documentation. Security-related code should be explicit and clear to prevent misunderstandings that could lead to vulnerabilities.

When implementing credential handling or other security features in ways that might not be immediately obvious to other developers, add comments that explain your design decisions and link to relevant documentation or implementation details.

Example:

// Authentication is implemented following the pattern used in org.eclipse.aether.repository.Authentication
// where all credentials are provided to the builder and consumers decide what to use
// See: org.eclipse.aether.transport.wagon.WagonTransporter#getProxy for implementation details
setAuthentication(
    AuthenticationBuilder().apply {
        with(options) {
            addUsername(username?.let(::tryResolveEnvironmentVariable))
            addPassword(password?.let(::tryResolveEnvironmentVariable))
        }
    }
)

go:build directive syntax

Ensure go:build directives follow correct syntax with no space between “//” and “go”, and use proper logical operators for multiple conditions. Incorrect spacing causes the directive to be ignored by the compiler, potentially including wrong code for target environments.

For multiple platforms, use OR operators (||) between conditions:

//go:build aix || darwin || dragonfly || freebsd || netbsd || openbsd || solaris

For complex conditions, use parentheses and logical operators:

//go:build (js && wasm) || windows

Common mistakes include adding spaces (“// go:build”) or using comma-separated lists without operators. Always verify build constraints are properly recognized by checking compilation behavior across target platforms.


Documentation quality standards

Ensure all documentation comments follow proper formatting conventions and are placed where developers will most likely read them. Documentation should use correct grammar, complete sentences, and end with periods. Additionally, place documentation at the most relevant location - typically at interface definitions rather than implementation details, since developers read interface documentation when implementing methods.

Example of proper formatting:

// ErrTimeout is a fake timeout error.
var ErrTimeout = errors.New("timeout")

Example of proper placement: Place WriteTo documentation at the WriterTo interface definition, not at Copy function implementation, because developers implementing WriteTo will read the interface documentation, not the Copy function documentation.


When logging information about the same operation or context, combine multiple related log statements into a single, comprehensive message rather than using separate log calls. This reduces log noise, improves readability, and can enhance performance by reducing the number of logging function calls.

Instead of multiple separate log statements:

LOG("start_token chars:%lu", self->current_position.chars);
LOG("start_token row:%lu", self->current_point.row);
LOG("start_token column:%lu", self->current_point.column);

Consolidate into a single informative message:

LOG("start_token chars:%lu, row:%lu, column:%lu", 
    self->current_position.chars, 
    self->current_point.row, 
    self->current_point.column);

Additionally, remove unnecessary or accidental logging parameters that don’t provide value, as this simplifies logging macros and reduces maintenance overhead. Focus on logging only the information that is actually useful for debugging or monitoring purposes.


Use conventional descriptive names

Variable names should follow established language conventions and clearly communicate their purpose and context. Avoid abbreviated or cryptic names in favor of descriptive identifiers that make code self-documenting.

Key principles:

Example of improvement:

// Poor naming
r, e := http.Post("http://127.0.0.1/count", "text/plain", strings.NewReader("POST data"))
writeFile := os.NewFile(uintptr(fds[0]), "parent-reads")

// Better naming  
req, err := http.Post("http://127.0.0.1/count", "text/plain", strings.NewReader("POST data"))
writeSocket := os.NewFile(uintptr(fds[0]), "write-socket")

This approach improves code readability, reduces cognitive load for other developers, and aligns with community standards and expectations.


Use configuration property providers

Always use Gradle’s Provider API when accessing project, system, or Gradle properties in your build configuration. This ensures proper handling of configuration cache and allows for dynamic property updates.

Instead of directly accessing properties:

// DON'T
val verbose = (project.hasProperty("kapt.verbose") && 
    project.property("kapt.verbose").toString().toBoolean() == true)

// DO
val verbose = project.providers.gradleProperty("kapt.verbose")
    .map { it.toBoolean() }
    .orElse(false)

// DON'T
val systemProp = System.getProperty("my.property")

// DO
val systemProp = project.providers.systemProperty("my.property")

This approach:

When dealing with file paths or build directory locations, use ProjectLayout:

val layout = project.layout
val outputFile = layout.buildDirectory.file("output/file.txt")

Safe configuration definitions

When defining configuration flags and options, use practices that ensure compatibility across different preprocessors and build environments. For macro-based configuration flags, use integer values (0/1) instead of boolean literals (true/false) to avoid preprocessor compatibility issues. Additionally, consider using runtime configuration mechanisms (like config objects or flags) instead of compile-time options when flexibility is needed.

Example of safer macro definitions:

// Safer - use integer values
#define PRINT_CHANGES 0
#define PRINT_SKIPS 0

// Or use properly defined constants
#define PRINT_CHANGES FALSE  // where FALSE is defined as 0

// Instead of potentially problematic boolean literals
#define PRINT_CHANGES false  // may cause preprocessor issues

For configuration mechanisms, prefer runtime configuration over compile-time when possible:

// Better - runtime configuration via config object
YGConfig config;
config.callMeasureCallbackOnAllNodes = true;

// Instead of compile-time only
#ifdef YOGA_CALL_MEASURE_CALLBACK_ON_ALL_NODES

This approach ensures better portability across different compilers and preprocessors while providing more flexibility for users of your code.


Prefer early returns

When a function can determine an early result based on input validation or special cases, return immediately rather than assigning to a temporary variable and having a single exit point. Early returns reduce nesting, improve readability, and often result in more efficient code by making guard conditions more visible.

// Recommended:
static int convert_prio(const int prio)
{
    if (prio == CPUPRI_INVALID)
        return CPUPRI_INVALID;
    
    // Continue with normal processing
    return prio - 40;
}

// Avoid:
static int convert_prio(int prio)
{
    int cpupri;

    if (prio == CPUPRI_INVALID)
        cpupri = CPUPRI_INVALID;
    else
        cpupri = prio - 40;
        
    return cpupri;
}

Early validation helps prevent unnecessary operations when preconditions aren’t met, and results in flatter code that’s easier to understand and maintain. Using const for parameters that won’t be modified also improves code clarity and can help the compiler optimize.


understand undefined value semantics

Before modifying initialization patterns or removing static variables, investigate the semantic meaning of undefined values and object lifetimes in the existing codebase. What appears to be a memory leak or improper initialization may be intentional design.

Key considerations:

Example of proper investigation:

// Before changing this:
static YGConfigRef defaultConfig = YGConfigNew();  // Not a leak - process lifetime

// Or this:
memset(&(node->getLayout()), 0, sizeof(YGLayout));

// Investigate: Does the constructor initialize differently?
node->getLayout() = {};  // May initialize with YGUndefined instead of 0
// If tests break, understand why before forcing zero values

Always verify that your changes preserve the intended semantics, especially when dealing with undefined states, static lifetimes, or special sentinel values.


explicit code declarations

Always make code declarations explicit and consistent to improve readability and maintainability. This includes specifying all property attributes, using const for immutable parameters, and avoiding misleading naming conventions.

Key practices:

Example of explicit property declaration:

// Good - explicit attributes
@property (nonatomic, readwrite, assign) CGFloat flexGrow;

// Avoid - relying on defaults
@property (nonatomic) CGFloat flexGrow;

Example of consistent const usage:

// Good - const parameters
WIN_EXPORT void YGSetExperimentalFeatureEnabled(const YGConfigRef config,
                                                const YGExperimentalFeature feature,
                                                const bool enabled);

// Avoid - missing const
WIN_EXPORT void YGSetExperimentalFeatureEnabled(YGConfigRef config,
                                                YGExperimentalFeature feature,
                                                bool enabled);

This approach reduces ambiguity, makes code intentions clear, and helps prevent accidental modifications while improving overall code consistency.


Go module configuration

Ensure Go projects use modern module configuration instead of legacy GOPATH setup. Projects should be created outside of GOPATH directory structure, with proper environment variable configuration and module files.

Key requirements:

Example project structure:

~/myproject/
    hello/
        go.mod        # module file
        hello.go      # command source
        stringutil/
            reverse.go # package source

This approach eliminates GOPATH dependency, simplifies project setup, and aligns with modern Go development practices. The configuration ensures compatibility across different Go versions while providing a cleaner development experience.


Add safety checks

Always add appropriate safety checks before operations that could result in undefined behavior, null references, or memory issues. This includes using weak references to prevent retain cycles, verifying exact object types before type-specific operations, and adding conditional checks before calling methods that may return undefined values.

Examples of safety checks to implement:

These patterns prevent crashes, memory leaks, and unexpected behavior by ensuring operations are only performed when it’s safe to do so.


optimize parser development strategy

When developing parsers or grammars, apply strategic optimization by prioritizing commonly used language features and choosing appropriate conflict resolution algorithms based on performance trade-offs.

Focus development effort on the most frequently used language constructs rather than attempting comprehensive coverage initially. As noted in parser development practices: “Most languages have a long-tail of features that don’t get utilized frequently. It is reasonable to prioritize developing 80% of a language and only supporting commonly used elements.”

For handling parsing conflicts, choose resolution strategies based on their computational complexity:

  1. Compile-time optimization: Rearrange grammar rules, specify associativity/precedence - these resolve ambiguities during parser generation with no runtime cost
  2. Runtime resolution: Add explicit conflict handling - this defers ambiguity resolution to parse time, potentially impacting performance

Example conflict resolution approaches:

// Compile-time: Use precedence to resolve operator conflicts
precedence: [
  ['left', '+', '-'],
  ['left', '*', '/'],
]

// Runtime: Allow parser to handle ambiguity dynamically  
conflicts: $ => [
  [$.expression, $.statement]
]

This optimization strategy balances development velocity with parser performance, ensuring efficient resource allocation while maintaining practical functionality for the most common use cases.


Document complex logic

Add clear explanatory comments to complex calculations, platform-specific behavior, or non-obvious code sections. Use NOTE comments to explain the reasoning behind tricky implementations, especially when dealing with framework-specific quirks or mathematical calculations.

This practice improves code maintainability and helps other developers understand the rationale behind complex logic. Comments should explain the “why” rather than the “what”, particularly for code that might seem counterintuitive or handles edge cases.

Example:

// NOTE: The center is offset by the layer.anchorPoint, so we have to take it into account.
view.center = (CGPoint) {
    .x = YGRoundPixelValue(x + (width * view.layer.anchorPoint.x)),
    .y = YGRoundPixelValue(y + (height * view.layer.anchorPoint.y)),
};

// NOTE: We must set only the bounds' size and keep the origin.
// UIScrollView's bounds.origin is not .zero when a contentOffset is set.
view.bounds = (CGRect) {
    .origin = view.bounds.origin,
    .size = {
        .width = YGRoundPixelValue(width),
        .height = YGRoundPixelValue(height),
    },
};

Analyze performance trade-offs

Before implementing convenience features or making architectural decisions, carefully evaluate their performance implications and hidden costs. Consider factors like method call overhead, automatic behavior frequency, and resource utilization patterns.

Key considerations:

Example from layout systems:

// Instead of automatic dirty detection on every layout:
// YGSize newSize = YGMeasureView(node, 0, YGMeasureModeUndefined, 0, YGMeasureModeUndefined);
// Consider the cost: "every leaf node is going to be measured during every single layout call"

// Prefer explicit control when performance matters:
@interface YGLayout ()
@property (nonatomic, assign, readonly) YGNodeRef node; // ivar reduces msgSends
@end

Always benchmark assumptions and consider the cumulative impact of seemingly small optimizations, especially in performance-critical paths like layout and rendering.


Assert null before access

When asserting conditions on potentially null pointers, always check for null first before accessing the pointer’s properties or members. This prevents segmentation faults and makes null expectations explicit in the code.

Instead of writing assertions that could crash on null pointers:

assert(root->ref_count > 0);  // Crashes if root is NULL

Use a combined assertion that checks null first:

assert(root && root->ref_count > 0);  // Safe and explicit

This pattern serves two purposes: it prevents crashes during debugging when assertions are enabled, and it clearly documents that the code expects the pointer to be non-null. When removing null checks, ensure the underlying assumptions about null safety have actually changed and document why the check is no longer needed.


validate algorithmic inputs

Always validate inputs and handle edge cases before performing algorithmic operations, especially when dealing with indices, state transitions, or data structure traversals. Check for boundary conditions, invalid states, and null/undefined values that could cause out-of-bounds access or undefined behavior.

Key practices:

Example from parse table operations:

// Before: Direct access without validation
*state_index = new_state_ids[*state_index];

// After: Validate before accessing
if (*state_index != (ParseStateId)(-1))
  *state_index = new_state_ids[*state_index];

// Also ensure meaningful fields exist
if ((action.type == ParseActionTypeShift && !action.extra) || 
    action.type == ParseActionTypeRecover)
  fn(&action.state_index);

This prevents crashes from invalid indices and ensures algorithms only operate on valid data, making code more robust and maintainable.


Avoid configuration side effects

Configuration properties should behave predictably without hidden side effects that override explicitly set values. When a developer sets a configuration value, the system should respect that value rather than applying additional logic that might change the effective behavior.

Avoid implementing getters that can return different values than what was explicitly set, as this creates confusion and makes the system harder to reason about. If complex logic is needed to determine effective configuration state, consider separating the user-facing configuration from the computed state.

Example of problematic pattern:

- (BOOL)isEnabled
{
  if (!super.isEnabled) {
    return NO;  // Side effect: can return NO even if explicitly set to YES
  }
  // Additional complex logic here...
}

Instead, use clear separation between configuration and computed state:

- (BOOL)isEnabled
{
  return _isEnabled;  // Returns exactly what was set
}

- (BOOL)isIncludedInLayout
{
  return self.isEnabled && [self meetsOtherCriteria];  // Separate computed property
}

This approach makes the configuration behavior transparent and the codebase easier to maintain and debug.


separate formatting from logging

Design logging utility functions to return formatted strings rather than directly performing logging operations. This separation of concerns improves modularity, testability, and allows callers to control when and how logging occurs.

Instead of having utility functions that directly log:

void YGLogAlign(YGLogLevel logLevel, const char * param, YGAlign value){
  char * text = "undefined";
  switch(value){
    case YGAlignAuto: text = "auto"; break;
    case YGAlignCenter: text = "center"; break;
    // ...
  }
  if(param == NULL) {
    YGLog(logLevel, text);  // Direct logging
  }
}

Prefer functions that return formatted strings:

const char* YGAlignToString(YGAlign value) {
  switch(value){
    case YGAlignAuto: return "auto";
    case YGAlignCenter: return "center";
    // ...
    default: return "undefined";
  }
}
// Caller controls logging: YGLog(logLevel, YGAlignToString(value));

This approach reduces coupling, makes the formatting logic reusable in non-logging contexts, and simplifies testing of string conversion logic independently from logging behavior.


Choose meaningful identifiers

All identifiers including parameters, files, functions, and categories should clearly communicate their purpose and role. Avoid generic or ambiguous names that require additional context to understand.

For parameters, use descriptive names that indicate what the parameter represents:

// Poor: generic parameter name
void YGLogAlign(YGLogLevel logLevel, const char * param, YGAlign value)

// Better: descriptive parameter name  
void YGLogAlign(YGLogLevel logLevel, const char * propertyName, YGAlign value)

Maintain consistency between related components - if a file is named YGEnumsPrint.h, the functions should use Print terminology rather than mixing Print and Log.

For categories and interfaces, ensure the name accurately reflects the current functionality. If an interface evolves beyond being “Private” to include public properties needed by tests, update the name accordingly:

// When functionality changes, update the name to match
@interface YGLayout ()  // No longer just private

This approach improves code readability and reduces the cognitive load for developers trying to understand the codebase.


Use descriptive function names

Function names should clearly convey their purpose and behavior, not just their signature or implementation details. Avoid names that could be confused with existing functions that have similar but different behavior.

When naming functions, consider what the function actually accomplishes rather than how it accomplishes it. For example, YGValueToFloat describes the conversion but not the purpose, while YGValueResolve better describes what the function is trying to achieve.

Additionally, be careful when adding functions with similar names to existing ones. If YGNodeMarkDirtyInternal already handles recursion, naming another function YGNodeMarkDirtyRecursive creates confusion about which function to use and their behavioral differences.

Example of improvement:

// Less descriptive - focuses on conversion
static inline float YGValueToFloat(const YGValue unit, const float parentSize)

// More descriptive - focuses on purpose  
static inline float YGValueResolve(const YGValue unit, const float parentSize)

Control structure formatting

Always use braces for control structures (if, for, while, etc.) even for single statements, and maintain consistent spacing around parentheses and braces. This improves code readability and prevents potential bugs when code is modified later.

Use proper spacing with a space after the keyword and before the opening parenthesis, and place the opening brace on the same line with a space before it:

// Good
if (attrs != null) {
    layoutParams = new LayoutParams(context, attrs);
}

// Avoid
if(attrs != null){
    layoutParams = new LayoutParams(context, attrs);
}

// Avoid (missing braces)
if (attrs != null)
    layoutParams = new LayoutParams(context, attrs);

This standard ensures consistent formatting across the codebase and makes code easier to read and maintain.


Explicit undefined state handling

Always use explicit, well-defined representations for undefined, uninitialized, or invalid states instead of magic values or allowing undefined behavior to propagate silently. Create named constants or enum values for undefined states, and make conscious decisions about whether to crash, return defaults, or handle undefined values gracefully.

Key practices:

  1. Use named constants for defaults: Instead of hardcoded values like 0.0f, reference defined constants like YGDefaultFlexGrow to prevent bugs and improve clarity
  2. Create explicit undefined representations: Use static instances like YGValueUndefined rather than raw undefined values or magic numbers
  3. Decide on undefined handling strategy: Choose whether to assert/crash on undefined values (fail-fast) or handle them gracefully, but make this decision explicit
  4. Avoid magic sentinel values: Instead of using -1 or other magic numbers to represent invalid states, consider explicit enum values, though weigh API design implications

Example of good practice:

// Good: Named constant for undefined state
static const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined};
node->style.flexBasis = YGValueUndefined;

// Good: Explicit handling decision
if (YGFloatIsUndefined(baseline)) {
  // Crash fast - undefined baseline indicates a bug
  YGAssert(false, "Baseline function must not return undefined");
}

// Avoid: Magic values
node->style.flexBasis.value = YGUndefined; // Raw undefined
layout->cached_layout.width_measure_mode = (css_measure_mode_t)-1; // Magic -1

This approach prevents bugs by making undefined states visible and intentional, while forcing explicit decisions about how to handle edge cases.


Extract complex conditions

When encountering complex conditional expressions or generic variable references, extract them into clearly named variables or use explicit identifiers to improve code readability and maintainability.

For complex conditions, break them down into descriptive boolean variables:

// Instead of:
childCrossMeasureMode = YGFloatIsUndefined(childCrossSize) || 
    (currentRelativeChild->resolvedDimensions[dim[crossAxis]]->unit == YGUnitAuto) 
    ? YGMeasureModeUndefined : YGMeasureModeExactly;

// Extract to:
bool hasUndefinedSize = YGFloatIsUndefined(childCrossSize);
bool hasAutoUnit = currentRelativeChild->resolvedDimensions[dim[crossAxis]]->unit == YGUnitAuto;
childCrossMeasureMode = (hasUndefinedSize || hasAutoUnit) 
    ? YGMeasureModeUndefined : YGMeasureModeExactly;

For generic references, prefer explicit, context-specific identifiers:

// Instead of:
return node->layout.measuredDimensions[dim[crossAxis]];

// Use explicit:
return node->layout.measuredDimensions[YGDimensionHeight];

This practice makes code self-documenting, easier to debug, and reduces cognitive load when reading complex logic.


Manage resource lifecycles

Ensure proper resource allocation and cleanup pairing, and maintain clear ownership semantics to prevent memory leaks and null reference issues. When allocating resources like GCHandle, always pair allocation with corresponding cleanup calls. Avoid overwriting allocated resources without first cleaning up the previous allocation.

Additionally, use return types that clearly indicate ownership. Return IntPtr for references you don’t own, and use strongly-typed handles only when your code manages the resource lifecycle.

Example of problematic code:

public void SetMeasureFunction(MeasureFunction measureFunction) {
    var handle = GCHandle.Alloc(this); // Never freed!
    Native.YGNodeSetContext(_ygNode, GCHandle.ToIntPtr(handle));
}

public void SetBaselineFunction(BaselineFunction baselineFunction) {
    var handle = GCHandle.Alloc(this); // Overwrites previous without cleanup!
    Native.YGNodeSetContext(_ygNode, GCHandle.ToIntPtr(handle));
}

Better approach: Track allocated handles and free them before allocating new ones, or use return types like IntPtr when you don’t own the underlying resource to avoid confusion about lifecycle responsibilities.


Write focused single-purpose tests

Tests should focus on validating one specific behavior or scenario rather than combining multiple test cases into complex, multi-purpose tests. Each test should have a clear, meaningful purpose that actually exercises the code under test.

Avoid creating tests that are too complex or that test trivial scenarios where the expected behavior is obvious. When tests fail, focused tests make it much easier to identify and debug the specific issue.

For example, instead of creating one large test case that validates multiple alignment behaviors:

<!-- Avoid: Complex test testing multiple things -->
<div id="complex_alignment_test" style="width: 150px; height: 100px; flex-wrap: wrap; flex-direction: row; align-content: stretch; justify-content: space-between;">
  <div style="width: 50px; height: 10px;"></div>
  <div style="width: 50px; height: 10px;"></div>
  <div style="width: 50px; height: 10px;"></div>
</div>

Create separate, focused tests:

<!-- Prefer: Focused test for align-content stretch -->
<div id="align_content_stretch_test" style="width: 130px; height: 100px; flex-wrap: wrap; align-content: stretch;">
  <div style="width: 50px; height: 10px;"></div>
  <div style="width: 50px; height: 10px;"></div>
</div>

<!-- Separate test for justify-content space-between -->
<div id="justify_content_space_between_test" style="width: 130px; height: 100px; justify-content: space-between;">
  <div style="width: 50px; height: 10px;"></div>
  <div style="width: 50px; height: 10px;"></div>
</div>

Additionally, ensure tests actually validate meaningful scenarios. Avoid creating tests where the expected behavior is trivial or where there’s no actual space to distribute or meaningful layout differences to observe.


Algorithm specification compliance

When implementing layout algorithms, ensure strict adherence to web standards and specifications, particularly regarding control flow and edge case handling. Complex algorithms like baseline calculation require precise implementation of specification details to avoid subtle bugs.

Key considerations:

Example from baseline calculation:

// Wrong: continues past first line, skipping valid children
if (child->lineIndex > 0) {
    continue;  // This skips children incorrectly
}

// Correct: breaks at first line boundary as per spec
if (child->lineIndex > 0) {
    break;  // Only consider first line children
}

This prevents algorithmic errors that can cause incorrect layout behavior and ensures compatibility with web standards.


Follow language naming conventions

Ensure all identifiers (properties, methods, classes, variables) follow the established naming conventions of the programming language being used. This improves code readability, maintainability, and consistency across the codebase.

For example, in C#:

Language conventions exist for good reasons - they make code more predictable for other developers familiar with the language, improve IDE support and tooling integration, and maintain consistency with standard libraries and frameworks. When naming conflicts arise, prioritize following the language’s established patterns over personal preferences or porting convenience.


Strict null checks

Use explicit strict equality checks when testing for null or undefined values. Prefer x === undefined over typeof x === 'undefined' when the variable is known to exist. When checking for both null and undefined, use x == null (loose equality) as it covers both cases, or check each explicitly with x === null || x === undefined. Avoid using the || operator for fallback values when legitimate falsy values (like 0, false, or empty strings) are expected, as they will incorrectly trigger the fallback.

// Good - explicit undefined check
if (value !== undefined) {
  return value;
}

// Good - covers both null and undefined
if (value != null) {
  return value;
}

// Bad - unnecessary typeof when variable exists
if (typeof value !== 'undefined') {
  return value;
}

// Bad - loses legitimate falsy values
return node.style.marginTop || node.style.margin; // 0 becomes fallback value

// Good - explicit existence check
return 'marginTop' in node.style ? node.style.marginTop : node.style.margin;

consistent formatting choices

Maintain consistent formatting and structural choices throughout the codebase to improve readability and maintainability. This includes always using braces for control structures (even single-line statements), choosing appropriate control flow constructs for clarity, and organizing code to prevent execution order issues.

Key practices:

Example of consistent brace usage:

// Good - always use braces
if (!node.lastLayout) {
  node.lastLayout = {};
}

// Avoid - inconsistent formatting
if (!node.lastLayout) node.lastLayout = {};

Example of clearer control structure:

// Preferred for simple cases
if (typeof val === 'number') {
  obj[key] = roundNumber(val);
} else if (typeof val === 'object') {
  inplaceRoundNumbersInObject(val);
}

// Instead of switch for simple type checking

These consistent choices make code more predictable for team members and reduce cognitive load during code reviews.


Reset algorithm state internally

Algorithms should handle their own state initialization and cleanup internally rather than relying on callers to manage it. This prevents bugs caused by stale data from previous executions and reduces the burden on calling code.

When designing algorithms that maintain state between calls or process hierarchical data structures, ensure that:

  1. Internal reset logic: The algorithm resets relevant state at the beginning of execution
  2. Encapsulated cleanup: State management is contained within the algorithm implementation
  3. Caller independence: External code doesn’t need to perform setup/teardown operations

Example from layout algorithm:

function layoutNode(node, parentMaxWidth, parentDirection) {
  // Algorithm handles its own state reset internally
  if (!node.lastLayout) {
    node.lastLayout = {};
  }
  
  // Reset child layouts internally rather than requiring caller to do it
  // This prevents stale position data from affecting current calculations
  resetChildLayouts(node);
  
  // Continue with algorithm logic...
}

This approach prevents issues where “isUndefined checks might fail where they shouldn’t” and ensures “the callsite doesn’t have to care and possibly introduce bugs” by forgetting to reset state properly.


benchmark performance optimizations

Always measure and validate performance optimizations through benchmarking before assuming they provide benefits. Performance changes can have unexpected consequences, and what appears to be an optimization may actually degrade performance in real-world scenarios.

When implementing performance optimizations:

  1. Create benchmarks that represent realistic usage patterns
  2. Measure before and after performance metrics
  3. Consider trade-offs between different performance aspects (memory vs computation, allocation vs GC pressure)
  4. Document the measured improvements to justify the optimization

Example approach:

// Before assuming this is faster:
return node.style[key] || node.style[type + key + suffix];

// Benchmark with realistic test cases:
// "in order to make sure that it has performance improvement, we need to benchmark it.
// Can you use the code that generates a random test to generate a big random tree 
// and then time the layout algorithm before and after? Otherwise we can't know 
// if this is a performance optimization or not."

This is especially important for layout algorithms and frequently-called code paths where performance assumptions can significantly impact application responsiveness.


avoid build side effects

Build scripts should avoid performing operations as side effects and instead use explicit, dedicated tasks for each operation. Side effects make build processes unpredictable, harder to maintain, and difficult to debug when issues arise.

Instead of creating directories, cleaning files, or performing setup operations implicitly within other tasks, create dedicated tasks with clear responsibilities. This approach improves build reliability, makes the build process more transparent, and allows for better control over execution order.

For example, rather than creating a dist folder as a side effect in the main build configuration:

// Avoid this - side effect
module.exports = function(grunt) {
  // Create the dist folder if it doesn't exist. It is deleted by the 'clean' task.
  if (!fs.existsSync('dist')) {
    fs.mkdirSync('dist');
  }
  
  // rest of configuration...
};

Use explicit tasks instead:

// Prefer this - explicit task
grunt.registerTask('ensure-dirs', function() {
  if (!fs.existsSync('dist')) {
    fs.mkdirSync('dist');
  }
});

grunt.registerTask('build', ['ensure-dirs', 'other-tasks']);

This makes the build process more predictable and allows the clean task to properly handle dist/** patterns without worrying about implicit directory creation elsewhere.


Centralize configuration values

Consolidate all configuration variables, constants, and settings into a centralized configuration object rather than declaring them as scattered variables throughout the codebase. This improves maintainability, reduces duplication, and enables consistent templating patterns.

Instead of defining variables separately:

var cTestClean, cTestCompile, cTestExecute;
var pathDelimiter = path.delimiter;

Add them to your config object:

var config = {
  libName: 'css-layout',
  distFolder: 'dist',
  srcFolder: 'src',
  cTestClean: '...',
  cTestCompile: '...',
  cTestExecute: '...',
  pathDelimiter: path.delimiter
};

This allows for consistent templating usage like <%= config.pathDelimiter %> instead of mixing template strings with concatenation, and keeps all configuration in one discoverable location.


Feature flag implementation

When implementing feature flags, ensure consistency between runtime and compiled scenarios. Feature switches marked with FeatureSwitchDefinition must properly return the AppContext switch value when defined:

// INCORRECT implementation
[FeatureSwitchDefinition("System.Net.SocketsHttpHandler.Http3Support")]
public static bool IsHttp3Supported => SomeDefaultLogic();

// CORRECT implementation - must use the AppContext switch value
[FeatureSwitchDefinition("System.Net.SocketsHttpHandler.Http3Support")]
public static bool IsHttp3Supported => 
    AppContext.TryGetSwitch("System.Net.SocketsHttpHandler.Http3Support", out var ret) ? ret : SomeDefaultLogic();

Consider dead code elimination implications when designing feature flags for AOT scenarios, as behavior differences may arise between dotnet run and dotnet publish. Avoid adding configuration switches preemptively - only introduce them when there’s a demonstrated need from users. For platform-specific features, ensure configuration is properly respected across all supported environments.