Start HereOrdered learning track

Immutability vs Runtime Mutability

Learn Java Microservices File Handling, State, Configuration and Secret Management - Part 004

Deep production-grade explanation of immutable artifacts versus runtime mutability in Java microservices, covering build artifacts, container images, deployment config, hot reload, file/state/config/secret mutation, rollout safety, invariants, and failure modeling.

14 min read2763 words
PrevNext
Lesson 0470 lesson track01–13 Start Here
#java#microservices#immutable-artifact#runtime-mutability+5 more

Part 004 — Immutable Artifact vs Runtime Mutability

Tujuan part ini: memahami batas antara sesuatu yang harus immutable dan sesuatu yang boleh mutable saat runtime. Ini penting karena file, state, configuration, dan secret semuanya terlihat seperti “hal yang bisa berubah”, tetapi setiap jenis perubahan punya risiko konsistensi, keamanan, compliance, dan operasional yang berbeda.


1. Masalah Inti

Microservices modern mengejar prinsip:

Build once, deploy many times.

Artinya artifact yang sama harus bisa berjalan di dev, staging, production, region berbeda, tenant berbeda, atau mode worker berbeda dengan externalized config.

Tetapi production system juga membutuhkan perubahan runtime:

  • menaikkan timeout;
  • mengganti endpoint dependency;
  • rotate database credential;
  • mengubah retention policy;
  • menambah allowed file type;
  • menonaktifkan parser bermasalah;
  • mengganti certificate;
  • mengubah log level;
  • memindahkan traffic;
  • mengaktifkan quarantine mode.

Di sinilah tension muncul:

Immutability gives reproducibility.
Mutability gives operational flexibility.
Too much immutability makes operations slow.
Too much mutability makes systems unpredictable.

Top-level engineer tidak memilih salah satu secara dogmatis. Mereka mendesain mutation boundary.


2. Definisi yang Harus Tegas

2.1 Immutable artifact

Artifact adalah hasil build yang tidak berubah setelah diproduksi.

Contoh:

  • JAR/WAR;
  • container image;
  • generated OpenAPI client;
  • compiled migration binary;
  • static resource;
  • packaged default config;
  • SBOM;
  • checksum/signature;
  • build metadata.

Invariant:

Artifact with the same digest must behave the same when given the same external inputs and runtime configuration.

2.2 Runtime mutability

Runtime mutability adalah kemampuan mengubah nilai/keadaan setelah artifact dibangun atau saat process berjalan.

Contoh:

  • environment variable berbeda per deployment;
  • ConfigMap berubah;
  • Secret di-rotate;
  • mounted certificate diperbarui;
  • log level diubah;
  • feature flag berubah;
  • cache di-invalidate;
  • worker pause/resume;
  • tenant policy version diganti;
  • local temp file dibuat dan dihapus.

Invariant:

Every mutable thing must have an owner, lifecycle, consistency model, and rollback story.

3. Mutation Taxonomy

Jangan bicara “mutable” secara umum. Pisahkan berdasarkan jenisnya.

Jenis MutasiContohFrekuensiPerlu Restart?Risiko Utama
Build mutationganti code, dependency, schema classrendahbuild ulangartifact drift
Deploy-time mutationendpoint, bucket, queue, profilesedangrolloutwrong wiring
Runtime config mutationtimeout, log level, samplingsedang/tinggitergantungpartial consistency
Secret mutationpassword, token, certperiodik/darurattergantung clientoutage/security leak
File mutationtemp file, uploaded blob, quarantine markertinggitidakcorruption/lost file
Durable state mutationDB row, object metadata, workflow statetinggitidaklost update/invariant break
Policy mutationretention, legal hold, allowed typerendah/sedangtergantungcompliance breach
Operational mutationscale replica, drain worker, pause consumersedangtidakbacklog/SLA impact

Jika desain tidak membedakan kategori ini, semua akan diperlakukan sama: “ubah config”. Itu berbahaya.


4. Layer Immutability

Immutability bukan satu lapisan. Ada beberapa lapisan.

Build artifact dan image digest harus immutable. Deployment manifest bisa berubah lewat GitOps/release pipeline, tetapi setiap versi manifest harus historis dan bisa diaudit. Running process mutable dalam batas tertentu. External state memang mutable, tetapi harus punya transaction/invariant.


5. Artifact Immutability: Kenapa Harus Keras?

Tanpa artifact immutability, production debugging menjadi kacau.

Pertanyaan sederhana menjadi tidak bisa dijawab:

Kode apa yang berjalan saat incident?
Dependency versi apa yang aktif?
Config default apa yang dipaketkan?
Apakah image tag ini sama dengan kemarin?
Apakah JAR di pod A sama dengan pod B?

Anti-pattern:

image: evidence-service:latest

Masalah:

  • tag bisa menunjuk digest berbeda dari waktu ke waktu;
  • rollback tidak deterministik;
  • audit sulit;
  • reproducibility hilang;
  • pod baru dan pod lama bisa jalan dengan binary berbeda walaupun manifest terlihat sama.

Lebih baik:

image: registry.acme.internal/evidence-service@sha256:4a7f...

Atau minimal gunakan semver/build version immutable yang tidak dipush ulang:

image: registry.acme.internal/evidence-service:1.42.7-build.98312

Invariant:

Never mutate an artifact after it is promoted.
Create a new artifact for every code/build change.

6. Apa yang Harus Masuk Artifact?

Artifact boleh membawa:

  • compiled code;
  • static default non-sensitive config;
  • schema class;
  • migration logic;
  • validation rules yang memang bagian dari code;
  • resource file yang tidak environment-specific;
  • generated metadata;
  • build information;
  • dependency manifest;
  • safe local development defaults.

Artifact tidak boleh membawa:

  • production password;
  • production endpoint yang confidential;
  • tenant-specific policy;
  • private key;
  • environment inventory lengkap;
  • runtime operational override;
  • “hotfix config” yang seharusnya external;
  • data file yang berubah setelah deploy.

Rule:

A built artifact must be safe to publish internally without exposing production capability.

7. Container Filesystem: Immutable Image, Mutable Layer

Container image bersifat immutable, tetapi container runtime memberi writable layer ephemeral.

Ini sering membingungkan engineer.

Image filesystem: immutable template
Container writable layer: mutable, ephemeral
Mounted volume: mutable depending on volume type
Object store/database: durable external state

Kalau Java service menulis ke /app/data, secara teknis bisa berhasil, tetapi data itu berada di writable layer container dan hilang saat container diganti.

Gunakan filesystem lokal container hanya untuk:

  • temporary file;
  • spill buffer;
  • short-lived processing;
  • cache yang bisa direbuild;
  • Unix socket/runtime file;
  • downloaded trust material yang bisa diperoleh ulang.

Jangan gunakan untuk:

  • uploaded business file final;
  • durable audit evidence;
  • state machine checkpoint yang tidak bisa hilang;
  • secret long-term;
  • generated report final tanpa external persistence.

Invariant:

Anything written inside a container must be disposable unless explicitly backed by a durable volume or external store.

8. Mutable Local File: Aman Jika Scope Jelas

Local file dalam Java service bisa aman bila lifecycle-nya jelas.

Contoh processing upload:

HTTP multipart stream
  -> temp file under /tmp/evidence-upload/<request-id>
  -> validate magic bytes
  -> scan virus
  -> compute checksum
  -> upload to object storage
  -> persist metadata
  -> delete temp file

Boundary:

  • temp file bukan source of truth;
  • temp file bisa dihapus kapan saja setelah request gagal;
  • retry harus bisa dimulai ulang;
  • cleanup harus idempotent;
  • quota harus dibatasi;
  • path harus aman dari traversal;
  • file permission harus minimal;
  • sensitive file tidak boleh masuk log/dump.

Java sketch:

public final class TempFileWorkspace implements AutoCloseable {
    private final Path directory;

    private TempFileWorkspace(Path directory) {
        this.directory = directory;
    }

    public static TempFileWorkspace create(Path root, String operationId) throws IOException {
        Path safeRoot = root.toAbsolutePath().normalize();
        Path dir = Files.createTempDirectory(safeRoot, operationId + "-");
        return new TempFileWorkspace(dir);
    }

    public Path resolve(String name) {
        Path path = directory.resolve(name).normalize();
        if (!path.startsWith(directory)) {
            throw new IllegalArgumentException("Invalid path traversal attempt");
        }
        return path;
    }

    @Override
    public void close() throws IOException {
        try (Stream<Path> paths = Files.walk(directory)) {
            paths.sorted(Comparator.reverseOrder())
                    .forEach(path -> {
                        try {
                            Files.deleteIfExists(path);
                        } catch (IOException ignored) {
                            // Log sanitized path or schedule janitor cleanup.
                        }
                    });
        }
    }
}

Design point:

Mutable local file is acceptable when it is operational workspace, not business truth.

9. Runtime Config Mutability: Restart vs Hot Reload

Ada dua model utama.

9.1 Restart-based config update

Config changes -> Deployment changes -> New pods start with new config -> Old pods drain

Kelebihan:

  • deterministic;
  • easy to reason;
  • all beans constructed from one config version;
  • works well with Spring Boot;
  • easy rollback via previous deployment;
  • easier audit.

Kekurangan:

  • lebih lambat;
  • butuh readiness/liveness yang benar;
  • bisa mengganggu long-running operation;
  • perlu graceful shutdown.

9.2 Hot reload

Config source changes -> running process detects -> validate -> apply without restart

Kelebihan:

  • cepat;
  • cocok untuk low-risk tuning;
  • mengurangi deployment churn;
  • berguna untuk incident mitigation.

Kekurangan:

  • consistency sulit;
  • bean existing bisa stale;
  • rollback logic perlu eksplisit;
  • inflight operation bisa split config;
  • testing lebih kompleks;
  • audit harus lebih detail.

Default recommendation:

Prefer restart-based rollout unless the configuration is explicitly designed for safe dynamic reload.

10. Hot Reload Safety Checklist

Sebuah config boleh hot reload jika semua jawaban berikut jelas:

1. Apa type dan invariant value baru?
2. Bagaimana validasi dilakukan sebelum apply?
3. Apakah apply bersifat atomik?
4. Apakah operasi yang sedang berjalan memakai snapshot lama?
5. Apakah operasi baru memakai snapshot baru?
6. Bagaimana rollback dilakukan?
7. Bagaimana observability membedakan config version?
8. Apakah resource lama harus ditutup?
9. Apakah reload bisa gagal sebagian?
10. Apa blast radius jika value salah?

Jika tidak bisa menjawab, jangan hot reload.


11. Atomic Swap Pattern

Untuk config runtime yang aman diubah, gunakan immutable config object dan atomic reference.

public record RuntimeTuning(
        Duration uploadTimeout,
        Duration scanTimeout,
        int maxConcurrentScans,
        boolean quarantineEnabled,
        long version
) {}

Provider:

public final class RuntimeTuningProvider {
    private final AtomicReference<RuntimeTuning> current;

    public RuntimeTuningProvider(RuntimeTuning initial) {
        this.current = new AtomicReference<>(initial);
    }

    public RuntimeTuning current() {
        return current.get();
    }

    public void update(RuntimeTuning candidate) {
        validate(candidate);
        current.set(candidate);
    }

    private void validate(RuntimeTuning candidate) {
        if (candidate.scanTimeout().compareTo(candidate.uploadTimeout()) < 0) {
            throw new IllegalArgumentException("scanTimeout must be >= uploadTimeout");
        }
        if (candidate.maxConcurrentScans() < 1 || candidate.maxConcurrentScans() > 64) {
            throw new IllegalArgumentException("maxConcurrentScans outside safe range");
        }
    }
}

Usage:

public UploadResult handleUpload(UploadCommand command) {
    RuntimeTuning tuning = tuningProvider.current();
    return uploadWithConfigSnapshot(command, tuning);
}

Invariant:

Do not mutate fields inside a shared config object.
Replace the whole immutable config snapshot.

12. Mutable Secret: Lebih Sulit dari Config Biasa

Secret rotation bukan hanya mengganti value. Secret adalah capability.

Contoh database password rotation:

old password works
new password created
application receives new password
connection pool opens new connections
old connections drain
old password revoked

Kalau urutan salah:

new secret written -> old secret revoked -> app pool still uses old connection/new login fails -> outage

Secret mutability butuh state machine.

Secret rotation invariant:

A consuming service must never require all old capability to disappear before it can prove new capability works.

13. Certificate Rotation

Certificate rotation punya kompleksitas tambahan.

  • TLS client may cache SSL context;
  • JVM truststore may be loaded once;
  • mounted cert file may update but existing clients may not reload;
  • server certificate reload depends on embedded server support;
  • mutual TLS requires both client and server trust chain compatibility;
  • clock skew can invalidate cert unexpectedly;
  • CA rotation needs overlap period.

Safe pattern:

1. Add new CA to trust bundle while keeping old CA.
2. Deploy consumers that trust both.
3. Rotate producer certificate to new CA.
4. Verify traffic.
5. Remove old CA after all producers migrated.

Do not rotate CA as a single-step config change.


14. Mutable Policy: Treat Like Versioned Domain Logic

Policy config contohnya:

retention:
  default-period: P7Y
  delete-after-case-closed: P2Y
  legal-hold-overrides-delete: true

Ini tidak boleh diubah seperti log level.

Policy mutation harus punya:

  • policy version;
  • effective timestamp;
  • approval;
  • migration effect;
  • audit log;
  • dry-run report;
  • backward compatibility;
  • affected records count;
  • rollback semantics.

Contoh policy version record:

CREATE TABLE retention_policy_version (
    id UUID PRIMARY KEY,
    policy_code TEXT NOT NULL,
    version INTEGER NOT NULL,
    effective_from TIMESTAMPTZ NOT NULL,
    config_json JSONB NOT NULL,
    approved_by TEXT NOT NULL,
    approved_at TIMESTAMPTZ NOT NULL,
    checksum TEXT NOT NULL,
    UNIQUE (policy_code, version)
);

Runtime service sebaiknya tidak hanya membaca “current retention days” dari env var. Ia harus membaca policy version yang bisa diaudit.


15. Mutable State: Jangan Disamakan dengan Mutable Config

State berubah karena business operation. Config berubah karena deployment/runtime decision.

Contoh state:

file uploaded
scan pending
scan passed
metadata persisted
evidence linked to case
retention clock started

Contoh config:

scan timeout is 120s
allowed type includes application/pdf
retention default is 7 years
bucket name is evidence-prod

Jika state disimpan dalam config, sistem akan rusak.

Anti-pattern:

current-processing-file-id: abc123
last-successful-offset: 99823

Ini bukan config. Ini state/checkpoint. Simpan di durable store dengan concurrency control.


16. Immutable Input, Mutable Processing, Immutable Output

Untuk file pipeline, pattern yang kuat:

Raw upload sebaiknya immutable setelah diterima. Processing workspace boleh mutable. Output accepted object sebaiknya immutable. Metadata state mencatat lifecycle.

Kenapa?

  • audit lebih kuat;
  • retry tidak merusak input;
  • derived artifact bisa diregenerate;
  • tamper detection lebih mudah;
  • legal hold lebih defensible.

17. Version Everything That Matters

Hal yang perlu version:

HalVersioning Bentuk
Artifactimage digest, build number, git commit
Configchecksum, config generation, Git commit
Secretversion id, lease id, created timestamp
Policypolicy version, effective date
Filecontent hash, object version id
Metadata schemamigration version
Parser/scannerengine version, signature version
Workflowstate machine version

Tanpa version, incident reconstruction menjadi spekulasi.

Pertanyaan audit:

File X diproses oleh artifact versi apa?
Dengan config versi apa?
Menggunakan scanner signature versi apa?
Dengan policy retention versi apa?
Secret/database credential versi apa yang aktif?

Tidak semua harus disimpan di setiap row, tetapi sistem harus bisa merekonstruksi jawabannya.


18. Rollout Semantics

Mutability harus dikaitkan dengan rollout model.

PerubahanRollout Aman
code changebuild new artifact, deploy new image digest
endpoint configdeployment rollout with readiness
ConfigMap env varupdate manifest/checksum, rollout pods
mounted config filereload only if app supports it; otherwise rollout
secret rotationoverlap old/new, update consumer, drain, revoke
feature flagprogressive rollout with targeting and kill switch
retention policyversioned policy activation with audit
file processing algorithmnew artifact + record processor version

Jangan deploy semua perubahan dengan mekanisme yang sama.


19. Readiness, Liveness, and Mutability

Runtime mutation harus tercermin di health model.

Contoh:

  • config reload gagal → readiness mungkin tetap up jika old config masih valid, tapi alert harus menyala;
  • secret expired → readiness harus fail jika service tidak bisa membuat new connection;
  • object storage bucket missing → readiness fail untuk API yang butuh storage;
  • scanner unavailable → readiness bisa partial/degraded tergantung policy;
  • policy config invalid → fail closed jika memengaruhi compliance.

Health endpoint buruk:

UP because JVM process alive.

Health endpoint lebih baik:

{
  "status": "UP",
  "components": {
    "config": { "status": "UP", "details": { "version": "2026-07-05.3" } },
    "storage": { "status": "UP" },
    "scanner": { "status": "DEGRADED" },
    "secretLease": { "status": "UP", "details": { "expiresInSeconds": 1800 } }
  }
}

Tetap sanitized. Jangan expose secret.


20. Failure Modeling: Immutable vs Mutable

20.1 Artifact mutable failure

Same tag points to different images.

Dampak:

  • rollback salah;
  • audit gagal;
  • pod berbeda behavior;
  • debugging tidak deterministik.

Control:

  • digest pinning;
  • registry immutability;
  • signed artifact;
  • SBOM;
  • deployment annotation build commit.

20.2 Config mutable failure

ConfigMap edited manually in prod.

Dampak:

  • Git drift;
  • unknown active config;
  • rollback lewat Git tidak mengembalikan manual patch;
  • audit gap.

Control:

  • GitOps reconciliation;
  • RBAC deny manual edits;
  • immutable ConfigMap generation;
  • drift detection.

20.3 Secret mutable failure

Secret rotated but app does not reload connection pool.

Dampak:

  • new connections fail;
  • old connections work temporarily;
  • outage muncul delayed;
  • root cause membingungkan.

Control:

  • secret lease awareness;
  • connection pool refresh;
  • dual credential;
  • alert before expiry;
  • rotation runbook.

20.4 File mutable failure

Service modifies file in place while another worker reads it.

Dampak:

  • partial read;
  • checksum mismatch;
  • corrupted output;
  • non-idempotent retry.

Control:

  • write temp then atomic rename if filesystem supports it;
  • object immutability;
  • content hash;
  • exclusive ownership;
  • state machine lock.

21. Java-Specific Pitfalls

21.1 Singleton bean captures old config

@Bean
S3Client s3Client(StorageProperties props) {
    return S3Client.builder()
            .region(Region.of(props.region()))
            .build();
}

Kalau props.region() berubah runtime, S3Client tidak otomatis berubah.

Conclusion:

Do not advertise dynamic config if dependent beans are static.

21.2 @Value scattered everywhere

@Value("${scan.timeout}")
private Duration timeout;

Masalah:

  • sulit validasi global;
  • sulit snapshot;
  • sulit mencari dependency;
  • sulit reload atomik;
  • mudah inconsistent.

Prefer @ConfigurationProperties.

21.3 Static field config

public static String BUCKET;

Ini hampir selalu buruk. Static config membuat testing, reload, dan dependency graph kacau.

21.4 Mutable global map

Map<String, String> runtimeConfig = new ConcurrentHashMap<>();

Concurrent map tidak otomatis memberi config consistency. Atomicity per key tidak sama dengan atomic config snapshot.


22. Designing Mutation Boundary per Component

Contoh service evidence upload.

ComponentMutable?MechanismNotes
API codenonew artifactbuild/deploy
max upload sizedeploy-time or controlled runtimeconfig rollout or snapshot reloadaffects validation
allowed MIME typescontrolled runtimeversioned config snapshotaudit needed
raw uploaded fileimmutable after writeobject storage version/hashnever modify in place
temp processing filemutable disposablelocal /tmpcleanup mandatory
scan resultmutable state transitionDB row/eventcontrolled by state machine
scanner endpointdeploy-timeconfig rolloutclient reconstruction likely
scanner timeoutruntime-tunableatomic snapshotsafe if applied per request
DB passwordmutable secretsecret rotation state machinedual credential
retention policyversioned policydomain config tableapproval/effective date

23. Mutability Budget

Mutability should be budgeted. The more mutable knobs, the harder the system is to reason about.

Questions:

How many runtime knobs does this service expose?
How many can change without deployment?
How many affect correctness?
How many affect security?
How many affect compliance?
How many are tested under change?
How many are observable?

A service with 300 mutable runtime properties is not flexible. It is usually ungoverned.

Principle:

Make the common safe changes easy.
Make dangerous changes explicit, reviewed, and slower.

24. Governance Model

Not every mutation should have the same approval path.

ChangeApproval
log level temporary increaseon-call engineer
timeout small increaseservice owner/on-call
endpoint changeservice owner + platform
secret rotationplatform/security automation
retention policydomain owner + compliance + engineering
parser algorithmengineering release process
encryption keysecurity + platform + migration plan
object deletion policycompliance + data owner

Governance is not bureaucracy when blast radius is real. It is an operational safety mechanism.


25. Immutable Release Record

For regulated/mission-critical systems, create a release record that binds immutable and mutable parts.

Example:

{
  "service": "evidence-service",
  "artifact": {
    "image": "registry/evidence-service@sha256:4a7f...",
    "gitCommit": "9d8c1a0",
    "buildNumber": "98312"
  },
  "deployment": {
    "environment": "prod-ap-southeast-1",
    "manifestCommit": "1e8b7c2",
    "configChecksum": "sha256:7c1e...",
    "secretRefs": [
      "vault://prod/evidence/db#version=42",
      "vault://prod/evidence/s3#version=17"
    ]
  },
  "policy": {
    "retentionPolicyVersion": "RETENTION-2026-04",
    "allowedDocumentTypesVersion": "DOC-TYPE-2026-07"
  }
}

Ini membantu menjawab “apa yang berjalan?” secara defensible.


26. Pattern: Immutable Config Generation

Alih-alih mengedit ConfigMap dengan nama tetap, buat ConfigMap per generation.

apiVersion: v1
kind: ConfigMap
metadata:
  name: evidence-service-config-20260705-003
  labels:
    app: evidence-service
    config-generation: "20260705-003"
data:
  FILE_UPLOAD_MAX_SIZE: "50MB"

Deployment menunjuk generation tertentu:

envFrom:
  - configMapRef:
      name: evidence-service-config-20260705-003

Keuntungan:

  • old pod jelas pakai config generation lama;
  • rollback mudah;
  • audit lebih kuat;
  • tidak ada silent mutation pada object yang sama;
  • drift lebih mudah dideteksi.

Trade-off:

  • perlu cleanup ConfigMap lama;
  • manifest lebih verbose;
  • tooling harus mendukung generation.

27. Pattern: Mutable Reference to Immutable Value

Ini pattern sangat kuat.

Mutable pointer -> immutable target

Contoh:

current retention policy -> RETENTION-2026-04
RETENTION-2026-04 -> immutable policy document

Atau:

active config generation -> config-20260705-003
config-20260705-003 -> immutable config set

Keuntungan:

  • value historis tidak berubah;
  • switch bisa cepat;
  • rollback hanya memindahkan pointer;
  • audit tetap kuat;
  • diff jelas.

Risiko:

  • pointer update harus atomic;
  • cache harus tahu version;
  • concurrent readers harus pakai snapshot.

28. Pattern: Copy-on-Write for File Processing

Jangan modify object final in place. Gunakan copy-on-write.

input.pdf             immutable raw
input.normalized.tmp  mutable workspace
input.normalized.pdf  immutable derived output
metadata row          state transition references output hash

Pseudo-flow:

Path workspace = Files.createTempDirectory("normalize-");
Path candidate = workspace.resolve("normalized.pdf");

normalize(rawInputStream, candidate);
String sha256 = computeSha256(candidate);

objectStore.putObject("derived/" + sha256, candidate);
metadataRepository.markNormalized(fileId, sha256, processorVersion);

Key invariant:

Publish derived object only after full write and integrity check.

29. Pattern: Restart for Structural Change, Reload for Tuning Change

Structural change:

  • database URL;
  • queue name;
  • object storage bucket;
  • auth issuer;
  • encryption key reference;
  • worker topology;
  • persistence schema mode.

Tuning change:

  • timeout;
  • concurrency limit;
  • cache TTL;
  • log level;
  • scan batch size;
  • retry backoff cap.

Default rule:

Structural config changes require rollout.
Tuning config changes may support runtime reload if snapshot-safe.

30. Operational Playbook

When asked “can we change this at runtime?”, answer using this decision tree.


31. Engineering Review Checklist

Sebelum menerima mutability baru:

[ ] Is the value categorized correctly: config, secret, state, file, policy, flag?
[ ] Is there a clear owner?
[ ] Is the source of truth defined?
[ ] Is the delivery mechanism defined?
[ ] Is the consistency model defined?
[ ] Does change require restart?
[ ] Is runtime reload atomic if supported?
[ ] Are old and new versions observable?
[ ] Is rollback possible?
[ ] Are secrets masked and separately governed?
[ ] Are file writes idempotent and recoverable?
[ ] Is audit required?
[ ] Are tests covering invalid and transition cases?

32. Practical Defaults for Java Microservices

Use these defaults unless there is a strong reason not to.

AreaDefault Stance
Artifactimmutable, digest pinned
Internal configsafe defaults only
Deployment configexternalized, rollout-based
Secretexternal secret manager or Kubernetes Secret with encryption/RBAC controls
Secret rotationdual-valid overlap, not single-step replace
Runtime reloaddisabled by default
Log level reloadallowed with audit/timebox
Timeout reloadallowed only through snapshot provider
Datasource reloadrollout or explicit pool rotation
File workspacelocal temp only, disposable
Business fileimmutable object storage + metadata state
Policy configversioned domain object, not env var
Feature flagdedicated flag system for progressive rollout

33. Mental Model Final

Pikirkan sistem sebagai kombinasi tiga benda:

Immutable artifact: what the service knows how to do.
External configuration: how the environment asks it to run.
Mutable state: what has happened and must be preserved.

Lalu tambahkan secret:

Secret: capability granted to the service, not just a value.

Dan file:

File: bytes with lifecycle, ownership, integrity, and retention semantics.

Kesalahan umum adalah mencampur kelimanya.

Salah CampurDampak
code sebagai configperlu rebuild untuk environment change
config sebagai statelost checkpoint, race condition
secret sebagai configleak dan rotation sulit
temp file sebagai durable statedata hilang saat restart
feature flag sebagai configrollout tidak terkendali
policy sebagai env varcompliance/audit lemah
mutable tag sebagai artifactrollback tidak deterministik

34. Kesimpulan

Immutability dan mutability bukan pilihan ideologis. Keduanya alat.

Production-grade Java microservice harus:

1. Build immutable artifacts.
2. Externalize environment-specific config.
3. Keep local runtime file mutation disposable.
4. Store durable state outside process/container.
5. Treat secrets as rotating capabilities.
6. Treat policy as versioned domain configuration.
7. Prefer rollout for structural change.
8. Allow hot reload only with explicit atomic snapshot semantics.
9. Version every important runtime input.
10. Preserve enough evidence to reconstruct behavior during incident/audit.

Part berikutnya akan membahas ownership model: siapa yang seharusnya memiliki file, state, config, dan secret; bagaimana ownership itu memengaruhi API, lifecycle, permission, audit, dan operational responsibility.


Referensi Utama

Lesson Recap

You just completed lesson 04 in start here. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.

Continue The Track

Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.