Luigit
repositories / dotfiles

dotfiles

bugabingas dorkfiles

owned by admin

pi/agent/skills/desloppy/references/poor-patterns.md

Raw
Rendered preview

Poor patterns

Poor patterns include blindly applying SOLID, Uncle Bob-style “Clean Code”, or old OOP patterns when they add ceremony, indirection, or hidden costs instead of making the system simpler.

What to look for

Look for code shaped by patterns such as:

  • SOLID applied mechanically
  • “Clean Code” rules applied mechanically
  • deep type hierarchies
  • reference types for everything
  • ignoring memory and performance implications in the name of “maintainability”

Why it matters

Patterns can make code worse when they add indirection, allocation, dispatch, hierarchy, or conceptual weight without a real need.

Maintainability does not mean ignoring memory and performance implications.

Prefer composition over inheritance when behavior can be assembled directly instead of encoded in a type hierarchy.

SOLID anti-patterns

SOLID concepts can be useful, but applied mechanically they often create slop.

Single Responsibility Principle

Anti-pattern: splitting code until every tiny operation becomes a separate class, service, or function, even when the pieces do not make sense independently.

class UserNameTrimmer
class UserEmailLowercaser
class UserAgeValidator
class UserNormalizerCoordinator

This may satisfy a narrow idea of “one responsibility” while making behavior harder to read as a whole.

Open/Closed Principle

Anti-pattern: adding extension points, inheritance, plugins, or registries before there is a real need for variation.

interface PriceRule
class DefaultPriceRule implements PriceRule
class PriceRuleRegistry
class PriceRuleFactory

This can make simple code harder to change because future flexibility was guessed too early.

Liskov Substitution Principle

Anti-pattern: deep inheritance hierarchies where subclasses technically share a parent type but violate expectations through special cases, unsupported operations, or surprising overrides.

class Storage
class ReadOnlyStorage extends Storage:
    function write(data):
        throw unsupported_operation

The type relationship claims substitutability, but the behavior does not support it.

Interface Segregation Principle

Anti-pattern: creating many tiny interfaces that add names, files, dispatch, and navigation without reducing real coupling.

interface CanGetName
interface CanSetName
interface CanValidateName
interface CanNormalizeName

Small interfaces are not automatically simple if they fragment one concept across many places.

Dependency Inversion Principle

Anti-pattern: wrapping every direct dependency in an interface, adapter, provider, or factory even when there is only one implementation and no useful boundary.

interface ClockProvider
class SystemClockProvider implements ClockProvider
class ClockProviderFactory
class ClockProviderFactoryProvider

This can replace a clear dependency with ceremony and indirection.

Pseudo-code examples

Bad: deep type hierarchy

interface Thing
class AbstractThing implements Thing
class AbstractNamedThing extends AbstractThing
class ConfigurableNamedThing extends AbstractNamedThing
class RuntimeConfigurableNamedThing extends ConfigurableNamedThing
class UserRuntimeConfigurableNamedThing extends RuntimeConfigurableNamedThing

The hierarchy becomes the thing the reader must understand before understanding the behavior.

Better: flatter data and behavior

type Thing:
    name
    config

function run_thing(thing, runtime):
    use thing.name
    use thing.config
    use runtime

Prefer a simpler shape when the hierarchy does not carry real value.

Bad: inheritance for assembled behavior

class Exporter
class CsvExporter extends Exporter
class CompressedCsvExporter extends CsvExporter
class EncryptedCompressedCsvExporter extends CompressedCsvExporter

The type hierarchy encodes combinations of behavior.

Better: composition over inheritance

exporter = compose(
    csv_format,
    compression,
    encryption,
)

exporter.export(data)

Assemble behavior directly when that is simpler than encoding combinations in subclasses.

Bad: reference types for everything

class UserName:
    value

class UserAge:
    value

class UserEmail:
    value

class User:
    name: UserName reference
    age: UserAge reference
    email: UserEmail reference

Reference types for everything can add allocation, navigation, and runtime cost without improving the system.

Better: use direct values when appropriate

type User:
    name
    age
    email

Do not introduce reference-heavy structure unless it has a real purpose.

Bad: ceremony in the name of maintainability

interface UserFactory
class DefaultUserFactory implements UserFactory
class UserFactoryProvider
class UserFactoryProviderFactory

user = UserFactoryProviderFactory.create().provider().factory().create_user(data)

This may satisfy pattern rules while making the actual behavior harder to see.

Better: direct construction when enough

user = create_user(data)

Avoid pattern ceremony when direct code is simpler and sufficient.

Bad: ignoring performance implications

function draw_frame(items):
    objects = items.map(item -> new DrawableItemWrapper(item))
    objects.each(object -> object.render())

A maintainability argument is weak if the code creates avoidable memory or performance costs in a hot path.

Better: consider the runtime context

function draw_frame(items):
    for each item in items:
        render item

When memory or performance matters, do not hide costs behind abstraction.

# Poor patterns

Poor patterns include blindly applying SOLID, Uncle Bob-style “Clean Code”, or
old OOP patterns when they add ceremony, indirection, or hidden costs instead of
making the system simpler.

## What to look for

Look for code shaped by patterns such as:

- SOLID applied mechanically
- “Clean Code” rules applied mechanically
- deep type hierarchies
- reference types for everything
- ignoring memory and performance implications in the name of “maintainability”

## Why it matters

Patterns can make code worse when they add indirection, allocation, dispatch,
hierarchy, or conceptual weight without a real need.

Maintainability does not mean ignoring memory and performance implications.

Prefer composition over inheritance when behavior can be assembled directly instead of encoded in a type hierarchy.

## SOLID anti-patterns

SOLID concepts can be useful, but applied mechanically they often create slop.

### Single Responsibility Principle

Anti-pattern: splitting code until every tiny operation becomes a separate class, service, or function, even when the pieces do not make sense independently.

```text
class UserNameTrimmer
class UserEmailLowercaser
class UserAgeValidator
class UserNormalizerCoordinator
```

This may satisfy a narrow idea of “one responsibility” while making behavior harder to read as a whole.

### Open/Closed Principle

Anti-pattern: adding extension points, inheritance, plugins, or registries before there is a real need for variation.

```text
interface PriceRule
class DefaultPriceRule implements PriceRule
class PriceRuleRegistry
class PriceRuleFactory
```

This can make simple code harder to change because future flexibility was guessed too early.

### Liskov Substitution Principle

Anti-pattern: deep inheritance hierarchies where subclasses technically share a parent type but violate expectations through special cases, unsupported operations, or surprising overrides.

```text
class Storage
class ReadOnlyStorage extends Storage:
    function write(data):
        throw unsupported_operation
```

The type relationship claims substitutability, but the behavior does not support it.

### Interface Segregation Principle

Anti-pattern: creating many tiny interfaces that add names, files, dispatch, and navigation without reducing real coupling.

```text
interface CanGetName
interface CanSetName
interface CanValidateName
interface CanNormalizeName
```

Small interfaces are not automatically simple if they fragment one concept across many places.

### Dependency Inversion Principle

Anti-pattern: wrapping every direct dependency in an interface, adapter, provider, or factory even when there is only one implementation and no useful boundary.

```text
interface ClockProvider
class SystemClockProvider implements ClockProvider
class ClockProviderFactory
class ClockProviderFactoryProvider
```

This can replace a clear dependency with ceremony and indirection.

## Pseudo-code examples

### Bad: deep type hierarchy

```text
interface Thing
class AbstractThing implements Thing
class AbstractNamedThing extends AbstractThing
class ConfigurableNamedThing extends AbstractNamedThing
class RuntimeConfigurableNamedThing extends ConfigurableNamedThing
class UserRuntimeConfigurableNamedThing extends RuntimeConfigurableNamedThing
```

The hierarchy becomes the thing the reader must understand before understanding
the behavior.

### Better: flatter data and behavior

```text
type Thing:
    name
    config

function run_thing(thing, runtime):
    use thing.name
    use thing.config
    use runtime
```

Prefer a simpler shape when the hierarchy does not carry real value.

### Bad: inheritance for assembled behavior

```text
class Exporter
class CsvExporter extends Exporter
class CompressedCsvExporter extends CsvExporter
class EncryptedCompressedCsvExporter extends CompressedCsvExporter
```

The type hierarchy encodes combinations of behavior.

### Better: composition over inheritance

```text
exporter = compose(
    csv_format,
    compression,
    encryption,
)

exporter.export(data)
```

Assemble behavior directly when that is simpler than encoding combinations in subclasses.

### Bad: reference types for everything

```text
class UserName:
    value

class UserAge:
    value

class UserEmail:
    value

class User:
    name: UserName reference
    age: UserAge reference
    email: UserEmail reference
```

Reference types for everything can add allocation, navigation, and runtime cost
without improving the system.

### Better: use direct values when appropriate

```text
type User:
    name
    age
    email
```

Do not introduce reference-heavy structure unless it has a real purpose.

### Bad: ceremony in the name of maintainability

```text
interface UserFactory
class DefaultUserFactory implements UserFactory
class UserFactoryProvider
class UserFactoryProviderFactory

user = UserFactoryProviderFactory.create().provider().factory().create_user(data)
```

This may satisfy pattern rules while making the actual behavior harder to see.

### Better: direct construction when enough

```text
user = create_user(data)
```

Avoid pattern ceremony when direct code is simpler and sufficient.

### Bad: ignoring performance implications

```text
function draw_frame(items):
    objects = items.map(item -> new DrawableItemWrapper(item))
    objects.each(object -> object.render())
```

A maintainability argument is weak if the code creates avoidable memory or
performance costs in a hot path.

### Better: consider the runtime context

```text
function draw_frame(items):
    for each item in items:
        render item
```

When memory or performance matters, do not hide costs behind abstraction.