Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Humble Objects And Functional Core

ASecurity

Isolating decisions from hard-to-test effects with Humble Objects, or a pure functional core and imperative shell when explicit data inputs fit the contract. Use when a rule can only be exercised by standing up the framework, when controller, scheduler, listener or UI logic makes focused tests difficult, or when retry, fallback or routing policy is entangled with the call it governs. Inspect heavy mocking as a possible symptom, not proof that a refactor is needed. Preserve adequate direct tes...

2 stars
0 votes
0 copies
0 views
Added 9/19/2026
developmentgojavashellexpressspringtestingrefactoringgitdatabaseperformance

Security Analysis

A100/100

Scanned 9/19/2026

Install to Claude Code

$npx -y skills add robsonkades/agent-skills --skill humble-objects-and-functional-core --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Humble Objects And Functional Core?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Humble Objects And Functional Core
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/robsonkades-humble-objects-and-functional-core/badge)](https://www.skillsdirectory.com/skills/robsonkades-humble-objects-and-functional-core)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: humble-objects-and-functional-core
description: >
  Isolating decisions from hard-to-test effects with Humble Objects, or a pure functional
  core and imperative shell when explicit data inputs fit the contract. Use when a rule can
  only be exercised by standing up the framework, when controller, scheduler, listener or UI
  logic makes focused tests difficult, or when retry, fallback or routing policy is entangled
  with the call it governs. Inspect heavy mocking as a possible symptom, not proof that a
  refactor is needed. Preserve adequate direct tests and boundary contracts. Does not cover
  which test level to use (architecture-testing,
  java-testing-strategy), choosing and writing the doubles themselves (java-test-doubles),
  where business rules belong across layers (domain-logic-organization), the mechanics of
  immutable types (java-immutability), or module dependency direction
  (layering-and-boundaries).
---

# Humble Objects and the Functional Core

## Purpose

Make the interesting part of a component testable by moving it out of the part that is hard
to test. A decision — which discount applies, whether to retry, which shard to route to,
what to render — is a function of data. An effect — writing to a socket, a database, a
screen — is not. Mixing them produces code where the only way to check a business rule is to
stand up the world.

The techniques overlap. **Humble Object** extracts logic from a hard-to-test component so
its remaining boundary responsibilities can be tested narrowly; the extracted logic need
not be pure. **Functional core, imperative shell** additionally makes decisions functions
of explicit data while the shell owns effects and their consistency.

The two failures this exists to prevent: logic trapped inside a framework component, so a
rule change is verified by a slow test that spins up HTTP and a database; and the opposite
excess, where every effect is wrapped in ceremony and the reader loses the actual work in a
pipeline of indirection.

## Workflow

Inspect the project's Java release/toolchain and framework/transaction configuration before
refactoring. The sealed outcomes and pattern switches below use Java 21 without preview;
retain existing alternatives on older targets rather than upgrading the project. Preserve
observable behavior, authorization, transaction boundaries and failure ordering. Report the
decision extracted or retained, the effect contract and actual core/boundary checks; test
speed or reliability improvements remain unmeasured unless compared. Reuse existing tests,
consumer contracts and failure evidence to identify the testability or change goal. Ask only
about unresolved inputs, authority or effects that would change the seam; investigate the
independent parts while those answers are pending.

1. **Find the decision.** In the component, identify the branch that would be worth a test if
   it were reachable — the conditional, the calculation, the selection.
2. **Name its inputs.** Everything the decision reads: parameters, fetched data, the clock,
   configuration. If an input arrives through I/O, the decision does not need the I/O, it
   needs the value.
3. **Choose the smallest useful seam.** Keep adequate direct tests or an existing service
   with controlled collaborators. A Humble Object may extract testable effectful logic;
   choose a pure function when explicit data inputs simplify the decision. In that core,
   fetching, writing, clock reads and randomness stay outside; sampled values become inputs.
4. **Leave the shell humble.** What remains fetches, calls the decision, and performs the result.
   Branches expressing infrastructure policy may remain, but test them at the cheapest level that
   observes their effects rather than forcing every branch into a pure core.
5. **Represent the outcome as data where the shell must act on it.** "Retry after 200 ms",
   "reject with this reason" — an outcome the shell interprets, not an effect the core
   performs.
6. **Check the payoff.** Compare access to the decision, test setup and the consumer/change
   cost against the goal. Retain required boundary tests even if their setup is unchanged.
   Stop when the seam and retained contracts are verified; keep the existing design or
   simplify a proposed extraction when it adds no useful testability or maintenance benefit.

## The split

```text
              ┌──────────────────────── SHELL (imperative, humble) ──┐
   request ──►│ fetch what the decision needs                        │
              │        │                                             │
              │        ▼                                             │
              │  ┌── CORE (pure) ─────────────────────────┐          │
              │  │ inputs in, decision out.               │          │
              │  │ No I/O, no clock, no randomness,       │          │
              │  │ no framework, no mutation of anything  │          │
              │  │ the caller can see.                    │          │
              │  └────────────────────────────────────────┘          │
              │        │  outcome (data)                             │
              │        ▼                                             │
              │ perform the effect it describes                      │
              └──────────────────────────────────────────────────────┘

  Tests of the core: explicit input fixtures, outcomes and boundary cases.
  Tests of the shell: effects, wiring, failure order and consistency.
```

What makes the core pure is not the absence of the word `void` — it is that **calling it twice
with the same inputs gives the same answer, and calling it zero times changes nothing**. The
clock and the random source are inputs like any other; passing `Instant` rather than calling
`Instant.now()` is usually the single highest-value move in this whole technique.

## Decision rules

```text
The logic is inside a controller, listener, scheduled method or UI
component, and the boundary obstructs testing a consequential branch
        → compare direct testing with extracting that decision. Keep
          the existing shape when it already provides a useful seam.

The chosen pure core needs data from a repository or a remote call
        → the shell fetches, the core receives the values. Do not pass
          the repository into the core "so it can fetch what it needs" —
          that reintroduces the collaborator you were removing.

The decision needs the current time, a random value or a generated id
        → pass the sampled value for a pure core. Injecting Clock into
          a service gives controllable time, not production purity.

The core must cause something to happen
        → return a description of it. The shell interprets. This is what
          makes retry, fallback and routing policy unit-testable
          (retries-and-backoff, circuit-breakers).

The component has no interesting branch — it maps, binds or forwards
        → leave it. There is nothing to extract, and wrapping it in a
          port produces indirection (enterprise-architecture-smells).

The work IS the effect: streaming bytes, a bulk UPDATE, a batch insert
        → do not split it. There is no decision to isolate, and the
          set-based operation belongs in the database
          (domain-logic-organization).

Purity would force loading a large result set into memory to keep the
core pure
        → the boundary is in the wrong place. Push the filtering into
          the query and let the core decide over what comes back
          (architecture-and-performance).
```

## Rules

- Humility minimizes logic in the hard-to-test boundary; it does not make boundary tests worthless.
  Binding, authentication, transaction demarcation, serialization and failure translation can all
  deserve focused integration tests even when business decisions live in the core.
- A computed plan is not continuing authority to perform an effect. Preserve the actual
  transaction/version/eligibility check where the contract requires current state, including
  authorization that may change after planning. The shell retains resource acquisition,
  cleanup and task ownership on success, failure and cancellation; ending the caller's wait
  does not by itself stop dispatched work. Extraction must not close borrowed resources or
  move an effect outside its required lifetime.
- Extract the decision, not the I/O. Wrapping a repository in an interface does not make the
  logic testable if the logic still lives in the shell; it only adds a seam
  (`java-dependency-inversion`).
- Heavy interaction mocking can signal that a decision is entangled with collaborators, but mocks
  are also legitimate for protocols, failure injection and orchestration. Inspect whether the test
  asserts stable outcomes or incidental call order before changing the design.
- Pass controllable ambient inputs when exact outcomes or boundary cases matter. Direct time/random
  calls do not automatically make every property test flaky, but they obstruct replay and precise
  failure diagnosis. `Clock` is in the JDK for the time calls; the id and the
  random source are supplied the same way, by the shell.
- **Purity is about observable effect, not about avoiding assignment.** A core that builds a
  local `ArrayList` and returns a stable result can be pure when no mutable aliases or
  mutable elements escape or change concurrently. Local mutation can simplify sequential code
  (`java-immutability`).
- Records and sealed outcomes can make input and result contracts clear when their shape
  fits. Keep adequate existing value types or a simple boolean; preserve public consumers.
  An exhaustive `switch` checks new outcomes when its source is recompiled, subject to any
  deliberate catch-all (`java-composition-over-inheritance`).
- Many distributed policies have a pure decision kernel, but breakers, adaptive limits and routing
  depend on concurrent, time-varying state. Model transitions explicitly and test both deterministic
  policy and thread-safe state/effect integration. Separating them from the call they govern is
  what makes them testable without a network, and what stops policy from being reimplemented
  slightly differently at each call site.
- Do not push effects into the core disguised as parameters. A `Runnable`, a `Consumer` or a
  callback handed to the core so it can "just call this" restores the impurity while hiding
  it from the signature.
- The shell is allowed to be dull and repetitive. Resisting duplication there, by inventing an
  abstraction over the effects, is how a humble shell becomes a framework nobody understands.
- **This is a component-level technique, not an architecture.** It composes with any layering
  and any domain-logic organisation, and it does not require ports, adapters or a hexagon
  (`layering-and-boundaries`).

## References

- [Applying the pattern to real components](references/humble-object-patterns.md) — the
  recurring applications: controller and presenter, scheduled job, message listener, gateway,
  and view; what stays in the framework component and what leaves; the Spring-specific version
  of each; and the diagnosis for a component that resists extraction. Read when restructuring a
  specific class that is hard to test.
- [The functional core in Java](references/functional-core-in-java.md) — expressing the core
  with records, sealed outcomes and exhaustive switches; effects as returned data; where
  mutation is legitimate; passing the clock and other ambient inputs; the allocation and
  readability costs and when they exceed the benefit. Read when writing or reviewing the core
  itself.

Attribution

robsonkadesrobsonkades
View sourceMore from robsonkades →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

281612 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2132 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

9881 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →