AgentSkillsCN

meta-library-dev

开发跨语言的可复用库代码。当需要设计公共 API、组织模块、管理版本控制,或创建实用工具库时,可使用此技能。它提供了基础性的模式,而各语言特有的 *-lib-* 技能则在此基础上不断延伸与完善。

SKILL.md
--- frontmatter
name: meta-library-dev
description: Develop reusable library code across languages. Use when designing public APIs, organizing modules, managing versioning, or creating utility libraries. Provides foundational patterns that language-specific *-lib-* skills extend.

Library Development Patterns

Foundational patterns for developing reusable library code across programming languages. This meta-skill provides guidance that language-specific library skills (e.g., rust-lib-dev, python-lib-dev) extend.

When to Use This Skill

  • Designing library public APIs
  • Organizing modules and package structure
  • Managing semantic versioning and compatibility
  • Creating utility libraries, frameworks, or toolkits
  • Establishing documentation and testing standards for libraries
  • Publishing and distributing packages

This Skill Does NOT Cover

  • SDK development (wrapping APIs/services) - see meta-sdk-patterns-eng
  • Application architecture - see architecture-patterns
  • Language-specific implementation details - see *-lib-* skills
  • CLI tool development - see *-cli-* skills

Library vs SDK: Key Distinctions

AspectLibrarySDK
PurposeReusable functionalityAPI/service wrapper
DependenciesMinimal, self-containedTied to external service
VersioningIndependent semverOften tracks API version
Exampleslodash, requests, serdeAWS SDK, Stripe SDK
TestingUnit/integration testsMocks external service

Public API Design

Principle: Minimal Surface Area

Expose only what users need. Everything public becomes a maintenance commitment.

code
Good: 3-5 primary exports that compose
Bad: 50 exports that users must navigate

Export Patterns

Layered Exports:

code
library/
├── mod.rs (or index.ts, __init__.py)  # Primary public API
├── types.rs                            # Public types/interfaces
├── errors.rs                           # Error types
└── internal/                           # Private implementation
    └── ...

Explicit vs Glob Exports:

python
# Preferred: Explicit exports
from .core import parse, validate, transform
__all__ = ["parse", "validate", "transform"]

# Avoid: Glob re-exports (hides what's public)
from .core import *

Naming Conventions

ElementConventionExample
FunctionsVerb-first, descriptiveparse_json, validateInput
Types/ClassesNoun, singularParser, ValidationResult
ConstantsSCREAMING_SNAKEDEFAULT_TIMEOUT, MAX_RETRIES
ModulesLowercase, descriptiveparser, validators

Function Signatures

Prefer Specific Over Generic:

rust
// Good: Clear intent
fn parse_config(path: &Path) -> Result<Config, ParseError>

// Avoid: Too generic, unclear
fn parse(input: &str) -> Result<Value, Error>

Parameter Guidelines:

  • 0-3 parameters: Use positional
  • 4+ parameters: Use options object/struct
  • Required first, optional last
  • Sensible defaults for optional parameters
typescript
// Good: Options object for many parameters
interface ParseOptions {
  encoding?: string;
  strict?: boolean;
  maxDepth?: number;
}
function parse(input: string, options?: ParseOptions): Result

// Avoid: Too many positional parameters
function parse(input: string, encoding: string, strict: boolean, maxDepth: number): Result

Module Organization

Standard Structure

code
library/
├── src/
│   ├── lib.rs           # Rust: Library root
│   ├── index.ts         # TS: Package entry
│   ├── __init__.py      # Python: Package init
│   │
│   ├── core/            # Core functionality
│   │   ├── mod.rs
│   │   ├── parser.rs
│   │   └── validator.rs
│   │
│   ├── types/           # Type definitions
│   │   ├── mod.rs
│   │   └── config.rs
│   │
│   ├── errors/          # Error types
│   │   ├── mod.rs
│   │   └── parse_error.rs
│   │
│   └── utils/           # Internal utilities
│       └── ...
│
├── tests/               # Integration tests
├── examples/            # Usage examples
├── benches/             # Benchmarks (if applicable)
└── docs/                # Additional documentation

Module Cohesion Principles

High Cohesion:

  • Modules should do one thing well
  • Related functionality stays together
  • Clear boundaries between modules

Low Coupling:

  • Modules should be independently testable
  • Minimize cross-module dependencies
  • Use dependency injection for flexibility

Re-export Patterns

Facade Pattern for Complex Libraries:

rust
// lib.rs - Clean public interface
pub use crate::core::{parse, validate};
pub use crate::types::{Config, Result};
pub use crate::errors::ParseError;

// Internal modules hidden
mod core;
mod types;
mod errors;
mod utils;  // Not re-exported

Versioning Strategy

Semantic Versioning (SemVer)

code
MAJOR.MINOR.PATCH

MAJOR: Breaking changes
MINOR: New features (backward compatible)
PATCH: Bug fixes (backward compatible)

What Constitutes Breaking Changes?

Change TypeBreaking?Version Bump
Remove public functionYesMAJOR
Change function signatureYesMAJOR
Add required parameterYesMAJOR
Add optional parameterNoMINOR
Add new functionNoMINOR
Fix bug in existing behaviorNoPATCH
Performance improvementNoPATCH

Pre-release Versions

code
0.x.y  - Initial development (breaking changes allowed in minor)
1.0.0-alpha.1 - Alpha release
1.0.0-beta.1  - Beta release
1.0.0-rc.1    - Release candidate
1.0.0         - Stable release

Deprecation Process

  1. Announce deprecation with @deprecated annotation
  2. Document migration path in deprecation notice
  3. Maintain deprecated API for at least one minor version
  4. Remove in next major version
python
import warnings

def old_function():
    """
    .. deprecated:: 2.0.0
       Use :func:`new_function` instead.
    """
    warnings.warn(
        "old_function is deprecated, use new_function instead",
        DeprecationWarning,
        stacklevel=2
    )
    return new_function()

Error Handling

Error Type Design

Hierarchical Error Types:

rust
#[derive(Debug, thiserror::Error)]
pub enum LibraryError {
    #[error("Parse error: {0}")]
    Parse(#[from] ParseError),

    #[error("Validation error: {0}")]
    Validation(#[from] ValidationError),

    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),
}

#[derive(Debug, thiserror::Error)]
pub enum ParseError {
    #[error("Invalid syntax at line {line}: {message}")]
    InvalidSyntax { line: usize, message: String },

    #[error("Unexpected token: {0}")]
    UnexpectedToken(String),
}

Error Messages

Good Error Messages Include:

  • What happened
  • Where it happened (context)
  • How to fix it (when possible)
code
# Good
ParseError: Invalid JSON at line 42: expected ',' or '}' after object property

# Bad
Error: Parse failed

Result Types

Prefer Result Types Over Exceptions (where language supports):

rust
// Rust: Result type
pub fn parse(input: &str) -> Result<Document, ParseError>

// TypeScript: Discriminated union
type ParseResult =
  | { success: true; data: Document }
  | { success: false; error: ParseError };

Configuration Patterns

Configuration Hierarchy

code
1. Defaults (in code)
2. Config file
3. Environment variables
4. Explicit parameters

Builder Pattern for Configuration

rust
let config = ConfigBuilder::new()
    .timeout(Duration::from_secs(30))
    .max_retries(3)
    .strict_mode(true)
    .build()?;

Validation at Construction

python
@dataclass
class Config:
    timeout: int
    max_retries: int

    def __post_init__(self):
        if self.timeout <= 0:
            raise ValueError("timeout must be positive")
        if self.max_retries < 0:
            raise ValueError("max_retries cannot be negative")

Testing Strategies

Test Pyramid for Libraries

code
         /\
        /  \     E2E (examples work)
       /----\
      /      \   Integration (modules work together)
     /--------\
    /          \ Unit (individual functions work)
   --------------

Testing Patterns

Property-Based Testing:

rust
#[quickcheck]
fn parse_roundtrip(input: ValidJson) -> bool {
    let parsed = parse(&input.0)?;
    let serialized = serialize(&parsed);
    input.0 == serialized
}

Snapshot Testing:

javascript
test('parser output', () => {
  const result = parse(complexInput);
  expect(result).toMatchSnapshot();
});

Fuzz Testing:

rust
#[fuzz]
fn fuzz_parser(data: &[u8]) {
    // Should not panic on any input
    let _ = parse(data);
}

Example-Driven Testing

python
def parse_date(s: str) -> date:
    """Parse a date string.

    Examples:
        >>> parse_date("2024-01-15")
        date(2024, 1, 15)

        >>> parse_date("invalid")
        Traceback (most recent call last):
            ...
        ValueError: Invalid date format
    """

Documentation Standards

Documentation Hierarchy

code
README.md          # Quick start, installation
docs/
├── guide/         # Tutorials, how-tos
├── reference/     # API documentation
└── examples/      # Runnable examples

API Documentation Requirements

Every public item needs:

  1. Summary - One-line description
  2. Description - Detailed explanation (if needed)
  3. Parameters - Each parameter documented
  4. Returns - Return value documented
  5. Errors - Possible errors documented
  6. Examples - At least one usage example
rust
/// Parses a configuration file into a Config struct.
///
/// Reads the file at the given path and parses it as TOML format.
/// The file must exist and be valid UTF-8.
///
/// # Arguments
///
/// * `path` - Path to the configuration file
///
/// # Returns
///
/// A `Config` struct containing the parsed configuration.
///
/// # Errors
///
/// Returns `ParseError::Io` if the file cannot be read.
/// Returns `ParseError::InvalidSyntax` if the TOML is malformed.
///
/// # Examples
///
/// ```
/// let config = parse_config("config.toml")?;
/// assert_eq!(config.timeout, 30);
/// ```
pub fn parse_config(path: &Path) -> Result<Config, ParseError> {
    // ...
}

README Template

markdown
# Library Name

Brief description of what the library does.

## Installation

\`\`\`bash
# Package manager command
\`\`\`

## Quick Start

\`\`\`language
// Minimal working example
\`\`\`

## Features

- Feature 1
- Feature 2
- Feature 3

## Documentation

- [Guide](docs/guide/)
- [API Reference](docs/reference/)
- [Examples](examples/)

## License

[License type]

Compatibility Considerations

Minimum Supported Version

Document and test against minimum versions:

toml
# Cargo.toml
rust-version = "1.70"

# pyproject.toml
requires-python = ">=3.9"

# package.json
"engines": {
  "node": ">=18.0.0"
}

Feature Flags

Use feature flags for optional functionality:

toml
# Cargo.toml
[features]
default = ["json"]
json = ["serde_json"]
yaml = ["serde_yaml"]
async = ["tokio"]

Backward Compatibility Strategies

  1. Additive changes only in minor versions
  2. Feature flags for optional new features
  3. Type aliases to rename types without breaking
  4. Default parameters instead of signature changes

Publishing and Distribution

Pre-publish Checklist

  • Version bumped appropriately
  • CHANGELOG updated
  • All tests passing
  • Documentation updated
  • Examples work with new version
  • No accidental breaking changes
  • License file present
  • README accurate

Registry-Specific Guidelines

RegistryKey Requirements
crates.ioCargo.toml metadata complete, license
npmpackage.json fields, TypeScript types
PyPIpyproject.toml, classifiers, requires-python
Mavenpom.xml, GPG signing, Javadoc

Changelog Format

Follow Keep a Changelog:

markdown
# Changelog

## [Unreleased]

## [2.1.0] - 2024-01-15

### Added
- New `parse_strict` function for strict parsing

### Changed
- Improved error messages for parse failures

### Deprecated
- `parse_loose` is deprecated, use `parse` with `strict: false`

## [2.0.0] - 2024-01-01

### Changed
- **BREAKING**: Renamed `Config` to `Settings`
- **BREAKING**: `parse` now returns `Result` instead of panicking

Performance Considerations

Avoid Premature Optimization

  1. Correctness first - Make it work
  2. Clarity second - Make it readable
  3. Performance third - Make it fast (if needed)

Common Performance Patterns

Zero-Copy Where Possible:

rust
// Good: Borrow instead of clone
fn process(data: &str) -> Result<&str, Error>

// Avoid: Unnecessary allocation
fn process(data: &str) -> Result<String, Error>

Lazy Evaluation:

rust
// Good: Iterator (lazy)
fn items(&self) -> impl Iterator<Item = &Item>

// Avoid: Collect everything (eager)
fn items(&self) -> Vec<Item>

Benchmark Before Optimizing:

rust
#[bench]
fn bench_parse(b: &mut Bencher) {
    let input = include_str!("../fixtures/large.json");
    b.iter(|| parse(input));
}

Extension Points

Plugin Architecture

rust
pub trait Plugin {
    fn name(&self) -> &str;
    fn process(&self, input: &Document) -> Result<Document, Error>;
}

pub struct Library {
    plugins: Vec<Box<dyn Plugin>>,
}

impl Library {
    pub fn register_plugin(&mut self, plugin: impl Plugin + 'static) {
        self.plugins.push(Box::new(plugin));
    }
}

Callback Hooks

typescript
interface Hooks {
  beforeParse?: (input: string) => string;
  afterParse?: (result: Document) => Document;
  onError?: (error: Error) => void;
}

function parse(input: string, hooks?: Hooks): Document {
  const processed = hooks?.beforeParse?.(input) ?? input;
  // ...
}

Anti-Patterns to Avoid

1. God Module

Problem: Single module with too many responsibilities Solution: Split by domain/functionality

2. Leaky Abstractions

Problem: Internal implementation details exposed in public API Solution: Clear public/private boundaries

3. Unstable Dependencies

Problem: Depending on unstable/pre-1.0 libraries in public API Solution: Wrap or re-export with stable types

4. Breaking Changes in Patches

Problem: Changing behavior in patch releases Solution: Strict semver adherence

5. Missing Error Context

Problem: Generic errors that don't help debugging Solution: Rich error types with context

6. Documentation Drift

Problem: Docs out of sync with code Solution: Doc tests, examples in tests


References