Definition & Overview
A stub is a placeholder implementation that returns hardcoded or minimal responses instead of performing real operations. In testing contexts, stubs replace external dependencies (databases, APIs, file systems) with predictable stand-ins that return predetermined values. In production code, stubs represent incomplete implementations -- functions that claim to implement an interface but actually skip the real logic, typically raising "not implemented" exceptions or returning dummy data.
The distinction between testing stubs and production stubs is critical. Testing stubs are a legitimate (though often inferior) alternative to more expressive test doubles. Production stubs are technical debt that violates interface contracts, misleads callers, and creates hidden failure modes. A module that claims to implement a behaviour but stubs out half the callbacks is worse than no implementation at all -- it passes compile-time checks while silently failing at runtime.
In the Prismatic Platform, stubs in production code are explicitly and categorically forbidden. The NO MERCY doctrine requires that every line of code be production-ready from the moment of creation. The platform's forbidden patterns scanner (Phase 7 of the pre-commit hook) detects and blocks stub patterns in lib/ directories, including raise "not implemented", raise :not_implemented, # STUB, # PLACEHOLDER, and # FIXME. This enforcement is non-bypassable: no exceptions, no temporary allowances, no "we'll fix it later" deferrals.
Technical Deep Dive
Forbidden Stub Patterns
The platform's forbidden pattern scanner detects these stub indicators:
defmodule PrismaticQuality.ForbiddenPatterns.StubDetector do
@moduledoc """
Detects stub and placeholder patterns in production code.
Part of the forbidden patterns enforcement system.
BLOCKING: Commits with stubs in lib/ are rejected.
"""
@stub_patterns [
# Code patterns
{~r/raise\s+"not\s+implemented"/i, :code_stub, :block},
{~r/raise\s+:not_implemented/i, :code_stub, :block},
{~r/raise\s+"TODO"/i, :code_stub, :block},
{~r/fn\s*_.*->\s*:ok\s*end/, :noop_stub, :block},
{~r/def\s+\w+.*do\s*\n\s*:ok\s*\n\s*end/, :empty_impl, :block},
# Comment patterns
{~r/#\s*STUB/i, :comment_stub, :block},
{~r/#\s*PLACEHOLDER/i, :comment_placeholder, :block},
{~r/#\s*FIXME/i, :comment_fixme, :block},
{~r/#\s*HACK/i, :comment_hack, :block},
{~r/#\s*WORKAROUND/i, :comment_workaround, :block},
{~r/#\s*XXX/i, :comment_xxx, :block},
{~r/#\s*temporary/i, :comment_temporary, :block},
{~r/#\s*quick\s+and\s+dirty/i, :comment_qad, :block},
{~r/#\s*naive/i, :comment_naive, :block}
]
@whitelisted_paths [
"lib/mix/tasks/quality/",
"prismatic_credo/",
"config/",
"garden/",
"deps/",
"_build/"
]
@spec scan_file(String.t()) :: [map()]
def scan_file(file_path) do
if whitelisted?(file_path) do
[]
else
file_path
|> File.read!()
|> String.split("\n")
|> Enum.with_index(1)
|> Enum.flat_map(fn {line, line_num} ->
detect_patterns(line, line_num, file_path)
end)
end
end
defp detect_patterns(line, line_num, file_path) do
Enum.flat_map(@stub_patterns, fn {regex, category, severity} ->
if Regex.match?(regex, line) do
[%{
file: file_path,
line: line_num,
category: category,
severity: severity,
content: String.trim(line)
}]
else
[]
end
end)
end
defp whitelisted?(path) do
Enum.any?(@whitelisted_paths, &String.contains?(path, &1))
end
endThe Right Alternative: Complete Implementations
Instead of stubs, the platform requires complete implementations or explicit feature flags:
# FORBIDDEN: stub implementation
defmodule BadAdapter do
@behaviour PrismaticStorage.Core
@impl true
def get(_key, _opts), do: raise("not implemented")
@impl true
def put(_key, _value, _opts), do: :ok # noop stub
end
# CORRECT: complete implementation
defmodule PrismaticStorage.ETS do
@behaviour PrismaticStorage.Core
@impl true
def get(key, opts) do
table = Keyword.fetch!(opts, :table)
case :ets.lookup(table, key) do
[{^key, value}] -> {:ok, value}
[] -> {:ok, nil}
end
end
@impl true
def put(key, value, opts) do
table = Keyword.fetch!(opts, :table)
:ets.insert(table, {key, value})
{:ok, value}
end
end
# CORRECT: explicit unsupported operation (not a stub)
defmodule PrismaticStorage.ReadOnlyAdapter do
@behaviour PrismaticStorage.Core
@impl true
def get(key, opts) do
# Full implementation
{:ok, fetch_from_source(key, opts)}
end
@impl true
def put(_key, _value, _opts) do
{:error, :read_only_adapter}
end
endTesting Stubs vs Production Stubs
In test code, the platform prefers behaviours and dependency injection over stubs:
# Test helper: configurable test adapter (NOT a stub)
defmodule PrismaticStorage.TestAdapter do
@moduledoc """
Test adapter that stores data in a process-local Agent.
This is a COMPLETE implementation, not a stub.
"""
@behaviour PrismaticStorage.Core
def start_link do
Agent.start_link(fn -> %{} end, name: __MODULE__)
end
@impl true
def get(key, _opts) do
value = Agent.get(__MODULE__, &Map.get(&1, key))
{:ok, value}
end
@impl true
def put(key, value, _opts) do
Agent.update(__MODULE__, &Map.put(&1, key, value))
{:ok, value}
end
@impl true
def delete(key, _opts) do
Agent.update(__MODULE__, &Map.delete(&1, key))
:ok
end
@impl true
def list(_opts) do
values = Agent.get(__MODULE__, &Map.values/1)
{:ok, values}
end
@impl true
def exists?(key, _opts) do
exists = Agent.get(__MODULE__, &Map.has_key?(&1, key))
{:ok, exists}
end
@impl true
def count(_opts) do
count = Agent.get(__MODULE__, &map_size/1)
{:ok, count}
end
endArchitecture & Implementation
The platform's anti-stub enforcement operates at three levels. The pre-commit hook (Phase 7) scans changed files for forbidden patterns before the commit is created. The CI pipeline runs a full codebase scan. The quality gates mix task (mix quality.forbidden_patterns) provides on-demand checking.
The enforcement is strict but scoped. Test files (test/ directories) are not scanned for stub patterns because test doubles are legitimate there (though the platform still prefers complete test adapters over stubs). Configuration files, dependency code, and quality tooling itself are whitelisted to prevent false positives.
The NO MERCY doctrine's rationale for banning stubs is straightforward: stubs represent deferred decisions, and deferred decisions compound into technical debt. A stub in module A causes module B (which depends on A) to develop workarounds, which causes module C to compensate for B's workarounds. Banning stubs from the start prevents this cascade entirely.
Usage in Prismatic Platform
Stub detection is automated and non-bypassable:
# Run forbidden patterns check
# mix quality.forbidden_patterns --category stubs
# Pre-commit hook output on violation:
# BLOCKED: Stub detected in lib/prismatic_foo/bar.ex:42
# raise "not implemented"
# Commit rejected. NO MERCY: Complete the implementation.Cross-References
- Forbidden Patterns - Scanner that detects and blocks stubs
- Quality Gates - Enforcement system including stub detection
- Behaviour - Contract mechanism that stubs violate
- NO MERCY - Doctrine requiring complete, production-ready code
Created by Tomas Korcak (korczis) | GitHub