From c0158b4e1148cb980fefbe97ebe16aef735f7fa4 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Wed, 7 Jan 2026 13:20:48 +0900 Subject: [PATCH 1/5] feat: add Practice section (P1 Quick Start, P2 Tutorial) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add two new practice documents in English: - P1: Quick Start guide using be-framework/app skeleton - P2: Emergency Triage tutorial demonstrating Be Framework paradigm The tutorial showcases: - Domain ontology via semantic variables - Metamorphosis pattern (Input → Being → Final) - First-class citizen treatment of domain logic (JTASProtocol) - Type-driven branching with $being property --- manuals/1.0/en/P1-getting-started.md | 159 +++++++++++ manuals/1.0/en/P2-tutorial.md | 394 +++++++++++++++++++++++++++ 2 files changed, 553 insertions(+) create mode 100644 manuals/1.0/en/P1-getting-started.md create mode 100644 manuals/1.0/en/P2-tutorial.md diff --git a/manuals/1.0/en/P1-getting-started.md b/manuals/1.0/en/P1-getting-started.md new file mode 100644 index 0000000..48a6859 --- /dev/null +++ b/manuals/1.0/en/P1-getting-started.md @@ -0,0 +1,159 @@ +--- +layout: docs-en +title: "P1. Getting Started" +category: Manual +permalink: /manuals/1.0/en/P1-getting-started.html +--- + +# Getting Started + +> Now that you understand the philosophy, let's put it into practice. + +## Requirements + +- PHP 8.4+ +- Composer + +## Installation + +```bash +git clone https://github.com/be-framework/app my-project +cd my-project +rm -rf .git +composer install +``` + +## Run the Example + +```bash +php bin/app.php +``` + +Output: + +```txt +Hello World +``` + +That's it! Let's look at the code. + +## Project Structure + +``` +src/ +├── Input/ +│ └── HelloInput.php # Starting point +├── Final/ +│ └── Hello.php # Destination +├── Reason/ +│ └── Greeting.php # Transcendent capability +├── Semantic/ +│ └── Name.php # Validation rules +├── Exception/ +│ └── EmptyNameException.php +└── Module/ + └── AppModule.php # DI configuration +``` + +## The Code + +### Input Class + +```php +#[Be([Hello::class])] +final readonly class HelloInput +{ + public function __construct( + public string $name + ) {} +} +``` + +The `#[Be]` attribute declares the **destiny**—what this input will become. + +### Final Class + +```php +final readonly class Hello +{ + public string $greeting; + + public function __construct( + #[Input] string $name, + #[Inject] Greeting $greeting, + ) { + $this->greeting = "{$greeting->greeting} {$name}"; + } +} +``` + +- `#[Input]` receives data from the previous stage (HelloInput) +- `#[Inject]` receives **Transcendence** (capability from outside) + +### Reason Class + +```php +final class Greeting +{ + public string $greeting = 'Hello'; +} +``` + +The Greeting provides the **transcendent capability**—the power to greet. + +### Executing Metamorphosis + +```php +$injector = new Injector(new AppModule()); +$becoming = new Becoming($injector, __NAMESPACE__ . '\\Semantic'); + +$input = new HelloInput('World'); +$hello = $becoming($input); + +echo $hello->greeting; // "Hello World" +``` + +## What Just Happened? + +``` +HelloInput('World') + ↓ Becoming executes +Hello (with Greeting injected) + → "Hello World" +``` + +The input didn't "do" anything—it **became** Hello through metamorphosis. + +## Try Semantic Validation + +Edit `bin/app.php` to pass an empty name: + +```php +$input = new HelloInput(''); +``` + +Run again: + +```bash +php bin/app.php +``` + +You'll see an error message because `Semantic/Name.php` validates that name cannot be empty. + +## Key Concepts Demonstrated + +| Concept | In This Example | +|---------|-----------------| +| **Immanence** | `$name` in HelloInput | +| **Transcendence** | `Greeting` injected via `#[Inject]` | +| **Metamorphosis** | HelloInput → Hello transformation | +| **Semantic Validation** | Name.php validates input | + +## Next Steps + +Ready for a more complete example with Being classes and branching? Continue to [Tutorial](./P2-tutorial.html) → + +Or revisit the concepts: +- [Input Classes](./02-input-classes.html) - Starting points +- [Final Objects](./04-final-objects.html) - Destinations +- [Semantic Variables](./06-semantic-variables.html) - Validation diff --git a/manuals/1.0/en/P2-tutorial.md b/manuals/1.0/en/P2-tutorial.md new file mode 100644 index 0000000..ebef696 --- /dev/null +++ b/manuals/1.0/en/P2-tutorial.md @@ -0,0 +1,394 @@ +--- +layout: docs-en +title: "P2. Tutorial" +category: Manual +permalink: /manuals/1.0/en/P2-tutorial.html +--- + +# Tutorial: Emergency Triage + +> Build a triage system where vital signs determine a patient's existence as "emergency" or "observation." + +In this tutorial, we'll build an emergency triage system that demonstrates the core philosophy of Be Framework: **objects don't DO things—they BECOME things.** + +A patient doesn't "get triaged." They **become** an emergency case or an observation case, based on the transcendent wisdom of medical protocol. + +## The Metamorphosis + +``` +PatientArrival (raw vital signs) + ↓ JTAS Protocol assesses +TriageAssessment (the chrysalis stage) + ↓ Destiny is determined +EmergencyCase or ObservationCase (final existence) +``` + +## Step 1: Define the Ontology + +Before writing logic, we define our **domain ontology**—the vocabulary of what can exist in this domain. + +### BodyTemperature + +```php +// src/Semantic/BodyTemperature.php + +/** + * Below 30°C or above 45°C, a human cannot survive. + * Such values are rejected at the semantic level. + */ +final class BodyTemperature +{ + #[Validate] + public function validate(float $bodyTemperature): void + { + if ($bodyTemperature < 30.0 || $bodyTemperature > 45.0) { + throw new LethalVitalException(); + } + } +} +``` + +### HeartRate + +```php +// src/Semantic/HeartRate.php + +/** + * Below 20 or above 250 bpm indicates cardiac arrest or lethal arrhythmia. + */ +final class HeartRate +{ + #[Validate] + public function validate(int $heartRate): void + { + if ($heartRate < 20 || $heartRate > 250) { + throw new LethalVitalException(); + } + } +} +``` + +**Key insight:** These aren't just validation rules. They define your **domain ontology**—the vocabulary of what can exist. This declarative foundation serves as documentation that both humans and AI can read to understand your domain. (See [Semantic Variables](./06-semantic-variables.html) for how this enables AI-readable system design.) + +## Step 2: Define Exceptions + +When vital signs indicate non-survivable conditions, the patient's existence is rejected: + +```php +// src/Exception/LethalVitalException.php + +#[Message([ + 'en' => 'Vital signs indicate non-survivable conditions.', + 'ja' => 'バイタルサインが生存不可能な状態を示しています。' +])] +final class LethalVitalException extends DomainException +{ +} +``` + +## Step 3: Define the Reason (Transcendence) + +The **JTASProtocol** (Japan Triage and Acuity Scale) is not a programmer's arbitrary rule. It represents **transcendent medical wisdom**—objective knowledge that exists independently in the world. In Be Framework, such domain logic becomes a **first-class citizen**: injectable, testable, and explicitly visible. + +```php +// src/Reason/JTASProtocol.php + +/** + * JTAS (Japan Triage and Acuity Scale) Protocol + * + * A transcendent medical wisdom that exists independently + * of any individual patient or programmer. + */ +final readonly class JTASProtocol +{ + /** @return 'emergency'|'observation' */ + public function assess(float $bodyTemperature, int $heartRate): string + { + // Level 1 (Resuscitation) or Level 2 (Emergency) criteria + if ($bodyTemperature >= 39.0 || $heartRate >= 120) { + return 'emergency'; + } + return 'observation'; + } +} +``` + +This is the **Reason**—the external force that enables metamorphosis. Just as a caterpillar needs environmental conditions to become a butterfly, our data needs the JTASProtocol to become a triaged patient. + +## Step 4: Create Input Class + +The starting point—raw vital signs at the moment of arrival: + +```php +// src/Input/PatientArrival.php + +#[Be([TriageAssessment::class])] +final readonly class PatientArrival +{ + public function __construct( + public float $bodyTemperature, + public int $heartRate + ) {} +} +``` + +The `#[Be]` attribute declares destiny: this arrival WILL BECOME a TriageAssessment. + +## Step 5: Create Destiny Markers + +These types represent the two possible destinies: + +```php +// src/Reason/Emergency.php +final readonly class Emergency {} + +// src/Reason/Observation.php +final readonly class Observation {} +``` + +These aren't empty classes—they ARE the distinction. An `Emergency` is fundamentally different from an `Observation`. The type itself carries meaning. + +## Step 6: Create Being Class + +This is where metamorphosis happens. The patient is in a liminal state—their final form not yet determined: + +```php +// src/Being/TriageAssessment.php + +/** + * Raw vital signs meet the JTAS Protocol (transcendent wisdom) + * and the patient's destiny is determined. + */ +#[Be([EmergencyCase::class, ObservationCase::class])] +final readonly class TriageAssessment +{ + public Emergency|Observation $being; + + public function __construct( + #[Input] public float $bodyTemperature, + #[Input] public int $heartRate, + #[Inject] JTASProtocol $protocol + ) { + $urgency = $protocol->assess($bodyTemperature, $heartRate); + $this->being = ($urgency === 'emergency') + ? new Emergency() + : new Observation(); + } +} +``` + +**Key concepts:** +- `#[Inject]` brings in the JTASProtocol—transcendent wisdom from outside +- The `$being` property (Union type) determines which Final class receives the transformation +- We don't "set status"—the patient BECOMES their destiny + +## Step 7: Create Final Classes + +The final forms—each with their own **unique capabilities**: + +### EmergencyCase + +```php +// src/Final/EmergencyCase.php + +/** + * A patient who EXISTS as highest priority. + * This is not just a status flag. This patient IS an emergency. + * Their type grants them capabilities that others don't have. + */ +final readonly class EmergencyCase +{ + public string $priority; + public string $color; + + public function __construct( + #[Input] public float $bodyTemperature, + #[Input] public int $heartRate, + #[Input] public Emergency $being + ) { + $this->priority = 'IMMEDIATE'; + $this->color = 'RED'; + } + + /** + * Only an EmergencyCase can demand ER assignment + */ + public function assignER(): string + { + return "Secure ER Room 1 immediately. Summon emergency physician."; + } +} +``` + +### ObservationCase + +```php +// src/Final/ObservationCase.php + +/** + * A patient who EXISTS as stable. + * They can safely wait while emergency cases are handled. + */ +final readonly class ObservationCase +{ + public string $priority; + public string $color; + + public function __construct( + #[Input] public float $bodyTemperature, + #[Input] public int $heartRate, + #[Input] public Observation $being + ) { + $this->priority = 'DELAYED'; + $this->color = 'GREEN'; + } + + /** + * Observation cases are assigned to waiting area + */ + public function assignWaitingArea(): string + { + return "Move to waiting area. Monitor vitals every 30 minutes."; + } +} +``` + +Notice: Each outcome has **different methods**. `EmergencyCase` can `assignER()`, while `ObservationCase` can `assignWaitingArea()`. The **type determines capability**—you cannot assign an ER room to an observation patient. + +## Step 8: Execute the Metamorphosis + +```php +// bin/app.php + +use Be\App\Input\PatientArrival; +use Be\App\Module\AppModule; +use Be\Framework\Becoming; +use Ray\Di\Injector; + +$injector = new Injector(new AppModule()); +$becoming = new Becoming($injector, 'Be\\App\\Semantic'); + +// High fever patient +$patient = new PatientArrival(bodyTemperature: 39.5, heartRate: 90); +$result = $becoming($patient); + +echo $result->priority; // "IMMEDIATE" +echo $result->color; // "RED" +echo $result->assignER(); // "Secure ER Room 1 immediately..." +``` + +## The Complete Flow + +``` +PatientArrival(39.5°C, 90 bpm) + ↓ #[Be([TriageAssessment::class])] +TriageAssessment + ├─ JTASProtocol->assess() returns 'emergency' + └─ $being = Emergency + ↓ #[Be([EmergencyCase::class, ObservationCase::class])] +EmergencyCase (because $being is Emergency) + → priority: IMMEDIATE + → color: RED + → assignER(): "Secure ER Room 1..." +``` + +## Handling Non-Survivable Existence + +```php +// Temperature outside survivable range +$invalid = new PatientArrival(bodyTemperature: 50.0, heartRate: 80); + +try { + $becoming($invalid); +} catch (SemanticVariableException $e) { + echo $e->getErrors()->getMessages('en')[0]; + // "Vital signs indicate non-survivable conditions." +} +``` + +The metamorphosis is **rejected**. A patient with lethal vital signs cannot exist in our system. + +## Why This Matters + +### Traditional Approach (Doing) + +```php +$patient = new Patient($temp, $hr); +if ($triageService->isEmergency($patient)) { + $patient->setStatus('emergency'); + $this->erService->assign($patient); +} +``` + +Problems: +- Patient can exist in invalid state +- Status can be changed at any time +- `erService->assign()` can be called on any patient + +### Be Framework Approach (Being) + +```php +$patient = new PatientArrival($temp, $hr); +$result = $becoming($patient); + +// $result IS an EmergencyCase or ObservationCase +// Only EmergencyCase has assignER() method +$result->assignER(); // Type-safe: only possible for EmergencyCase +``` + +Benefits: +- Non-survivable states cannot exist +- Type IS the status (immutable) +- Capabilities belong to existence + +## Project Structure + +``` +src/ +├── Being/ +│ └── TriageAssessment.php # Intermediate stage +├── Exception/ +│ └── LethalVitalException.php +├── Input/ +│ └── PatientArrival.php # Raw data +├── Module/ +│ └── AppModule.php # DI configuration +├── Final/ +│ ├── EmergencyCase.php # Final form: emergency +│ └── ObservationCase.php # Final form: observation +├── Reason/ +│ ├── Emergency.php # Destiny marker +│ ├── JTASProtocol.php # Transcendent wisdom +│ └── Observation.php # Destiny marker +└── Semantic/ + ├── BodyTemperature.php # What CAN exist + └── HeartRate.php +``` + +## Key Insights + +1. **Existence over Action**: The patient doesn't "get triaged"—they BECOME a triaged state +2. **Type IS Status**: `EmergencyCase` and `ObservationCase` are different types with different capabilities +3. **Semantic Boundaries**: Lethal vital signs are rejected before metamorphosis +4. **Transcendent Wisdom**: JTASProtocol exists independently—it's injected, not created +5. **Immutability**: Once transformed, a patient cannot change status without new metamorphosis + +## Metamorphosis in Other Domains + +The same pattern applies everywhere: + +| Domain | Input | Being | Final | Reason | +|--------|-------|-------|---------|--------| +| **Triage** | PatientArrival | TriageAssessment | Emergency/Observation | JTASProtocol | +| **Brewing** | RawMaterials | Fermentation | PremiumSake/Vinegar | YeastCulture | +| **Immigration** | VisaApplication | ConsularReview | Resident/Visitor | ImmigrationLaw | +| **Justice** | Evidence | Trial | Guilty/Acquitted | PenalCode | +| **Stellar** | GasCloud | Protostar | Star/BlackHole | PhysicsLaws | + +Every domain has its metamorphosis. Every existence has its reason. + +## Next Steps + +- [Semantic Variables](./06-semantic-variables.html) - Deep dive into semantic validation +- [Type-Driven Metamorphosis](./07-type-driven-metamorphosis.html) - Advanced branching patterns +- [Reason Layer](./08-reason-layer.html) - Understanding transcendence From 0a1d5eb52e92130dd0db377c0e27ed9b7388ef01 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Wed, 7 Jan 2026 13:24:13 +0900 Subject: [PATCH 2/5] refactor: simplify file names (remove P1/P2 prefix) --- manuals/1.0/en/{P1-getting-started.md => getting-started.md} | 4 ++-- manuals/1.0/en/{P2-tutorial.md => tutorial.md} | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename manuals/1.0/en/{P1-getting-started.md => getting-started.md} (97%) rename manuals/1.0/en/{P2-tutorial.md => tutorial.md} (99%) diff --git a/manuals/1.0/en/P1-getting-started.md b/manuals/1.0/en/getting-started.md similarity index 97% rename from manuals/1.0/en/P1-getting-started.md rename to manuals/1.0/en/getting-started.md index 48a6859..78c52d7 100644 --- a/manuals/1.0/en/P1-getting-started.md +++ b/manuals/1.0/en/getting-started.md @@ -1,8 +1,8 @@ --- layout: docs-en -title: "P1. Getting Started" +title: "Getting Started" category: Manual -permalink: /manuals/1.0/en/P1-getting-started.html +permalink: /manuals/1.0/en/getting-started.html --- # Getting Started diff --git a/manuals/1.0/en/P2-tutorial.md b/manuals/1.0/en/tutorial.md similarity index 99% rename from manuals/1.0/en/P2-tutorial.md rename to manuals/1.0/en/tutorial.md index ebef696..c72f73e 100644 --- a/manuals/1.0/en/P2-tutorial.md +++ b/manuals/1.0/en/tutorial.md @@ -1,8 +1,8 @@ --- layout: docs-en -title: "P2. Tutorial" +title: "Tutorial" category: Manual -permalink: /manuals/1.0/en/P2-tutorial.html +permalink: /manuals/1.0/en/tutorial.html --- # Tutorial: Emergency Triage From dceb9a1ae5c0e22e249683445a042f359c7a544c Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Wed, 7 Jan 2026 13:27:51 +0900 Subject: [PATCH 3/5] fix: address review feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Prerequisites section to tutorial - Fix broken link (P2-tutorial.html → tutorial.html) - Unify namespace style across examples --- manuals/1.0/en/getting-started.md | 4 ++-- manuals/1.0/en/tutorial.md | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/manuals/1.0/en/getting-started.md b/manuals/1.0/en/getting-started.md index 78c52d7..56668db 100644 --- a/manuals/1.0/en/getting-started.md +++ b/manuals/1.0/en/getting-started.md @@ -105,7 +105,7 @@ The Greeting provides the **transcendent capability**—the power to greet. ```php $injector = new Injector(new AppModule()); -$becoming = new Becoming($injector, __NAMESPACE__ . '\\Semantic'); +$becoming = new Becoming($injector, 'Be\\App\\Semantic'); $input = new HelloInput('World'); $hello = $becoming($input); @@ -151,7 +151,7 @@ You'll see an error message because `Semantic/Name.php` validates that name cann ## Next Steps -Ready for a more complete example with Being classes and branching? Continue to [Tutorial](./P2-tutorial.html) → +Ready for a more complete example with Being classes and branching? Continue to [Tutorial](./tutorial.html) → Or revisit the concepts: - [Input Classes](./02-input-classes.html) - Starting points diff --git a/manuals/1.0/en/tutorial.md b/manuals/1.0/en/tutorial.md index c72f73e..8d6663d 100644 --- a/manuals/1.0/en/tutorial.md +++ b/manuals/1.0/en/tutorial.md @@ -9,6 +9,14 @@ permalink: /manuals/1.0/en/tutorial.html > Build a triage system where vital signs determine a patient's existence as "emergency" or "observation." +## Prerequisites + +- Complete [Getting Started](./getting-started.html) +- PHP 8.4+ +- Basic understanding of [Be Framework philosophy](./01-overview.html) + +## Introduction + In this tutorial, we'll build an emergency triage system that demonstrates the core philosophy of Be Framework: **objects don't DO things—they BECOME things.** A patient doesn't "get triaged." They **become** an emergency case or an observation case, based on the transcendent wisdom of medical protocol. @@ -104,7 +112,6 @@ final readonly class JTASProtocol /** @return 'emergency'|'observation' */ public function assess(float $bodyTemperature, int $heartRate): string { - // Level 1 (Resuscitation) or Level 2 (Emergency) criteria if ($bodyTemperature >= 39.0 || $heartRate >= 120) { return 'emergency'; } From 018b10ec43aff5ce6effb32f58e201cef6302c2f Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Wed, 7 Jan 2026 13:30:31 +0900 Subject: [PATCH 4/5] fix: add simplified note to JTAS protocol --- manuals/1.0/en/tutorial.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/manuals/1.0/en/tutorial.md b/manuals/1.0/en/tutorial.md index 8d6663d..fc06316 100644 --- a/manuals/1.0/en/tutorial.md +++ b/manuals/1.0/en/tutorial.md @@ -106,6 +106,8 @@ The **JTASProtocol** (Japan Triage and Acuity Scale) is not a programmer's arbit * * A transcendent medical wisdom that exists independently * of any individual patient or programmer. + * + * Note: Simplified. Real JTAS has 5 levels. */ final readonly class JTASProtocol { From 70f3d6e52d024ab2494f36847e6a5acd488c2b62 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Wed, 7 Jan 2026 15:21:38 +0900 Subject: [PATCH 5/5] feat: add Japanese translations for Getting Started and Tutorial --- manuals/1.0/ja/getting-started.md | 159 ++++++++++++ manuals/1.0/ja/tutorial.md | 403 ++++++++++++++++++++++++++++++ 2 files changed, 562 insertions(+) create mode 100644 manuals/1.0/ja/getting-started.md create mode 100644 manuals/1.0/ja/tutorial.md diff --git a/manuals/1.0/ja/getting-started.md b/manuals/1.0/ja/getting-started.md new file mode 100644 index 0000000..3eb585f --- /dev/null +++ b/manuals/1.0/ja/getting-started.md @@ -0,0 +1,159 @@ +--- +layout: docs-ja +title: "Getting Started" +category: Manual +permalink: /manuals/1.0/ja/getting-started.html +--- + +# Getting Started + +> 哲学を理解したら、実践してみましょう。 + +## 要件 + +- PHP 8.4+ +- Composer + +## インストール + +```bash +git clone https://github.com/be-framework/app my-project +cd my-project +rm -rf .git +composer install +``` + +## サンプルを実行 + +```bash +php bin/app.php +``` + +出力: + +```txt +Hello World +``` + +これだけです!コードを見てみましょう。 + +## プロジェクト構造 + +``` +src/ +├── Input/ +│ └── HelloInput.php # 出発点 +├── Final/ +│ └── Hello.php # 目的地 +├── Reason/ +│ └── Greeting.php # 超越的な能力 +├── Semantic/ +│ └── Name.php # 検証ルール +├── Exception/ +│ └── EmptyNameException.php +└── Module/ + └── AppModule.php # DI設定 +``` + +## コード + +### Input クラス + +```php +#[Be([Hello::class])] +final readonly class HelloInput +{ + public function __construct( + public string $name + ) {} +} +``` + +`#[Be]` 属性は**運命**を宣言します—この入力が何になるかを。 + +### Final クラス + +```php +final readonly class Hello +{ + public string $greeting; + + public function __construct( + #[Input] string $name, + #[Inject] Greeting $greeting, + ) { + $this->greeting = "{$greeting->greeting} {$name}"; + } +} +``` + +- `#[Input]` は前の段階(HelloInput)からデータを受け取る +- `#[Inject]` は**超越**(外部からの能力)を受け取る + +### Reason クラス + +```php +final class Greeting +{ + public string $greeting = 'Hello'; +} +``` + +Greeting は**超越的な能力**—挨拶する力—を提供します。 + +### 変態の実行 + +```php +$injector = new Injector(new AppModule()); +$becoming = new Becoming($injector, 'Be\\App\\Semantic'); + +$input = new HelloInput('World'); +$hello = $becoming($input); + +echo $hello->greeting; // "Hello World" +``` + +## 何が起きたのか? + +``` +HelloInput('World') + ↓ Becoming が実行 +Hello (Greeting が注入された状態) + → "Hello World" +``` + +入力は何も「しなかった」—変態を通じて Hello に**なった**のです。 + +## セマンティック検証を試す + +`bin/app.php` を編集して空の名前を渡してみましょう: + +```php +$input = new HelloInput(''); +``` + +再度実行: + +```bash +php bin/app.php +``` + +`Semantic/Name.php` が名前が空であることを検証するため、エラーメッセージが表示されます。 + +## 示された主要概念 + +| 概念 | この例では | +|------|----------| +| **内在** | HelloInput の `$name` | +| **超越** | `#[Inject]` で注入された `Greeting` | +| **変態** | HelloInput → Hello の変換 | +| **セマンティック検証** | Name.php が入力を検証 | + +## 次のステップ + +Being クラスと分岐を含むより完全な例に進む準備ができましたか? [チュートリアル](./tutorial.html) へ → + +または概念を復習: +- [Input Classes](./02-input-classes.html) - 出発点 +- [Final Objects](./04-final-objects.html) - 目的地 +- [Semantic Variables](./06-semantic-variables.html) - 検証 diff --git a/manuals/1.0/ja/tutorial.md b/manuals/1.0/ja/tutorial.md new file mode 100644 index 0000000..973f6ea --- /dev/null +++ b/manuals/1.0/ja/tutorial.md @@ -0,0 +1,403 @@ +--- +layout: docs-ja +title: "Tutorial" +category: Manual +permalink: /manuals/1.0/ja/tutorial.html +--- + +# チュートリアル: 救急トリアージ + +> バイタルサインが患者の存在を「緊急」または「経過観察」として決定するトリアージシステムを構築します。 + +## 前提条件 + +- [Getting Started](./getting-started.html) を完了していること +- PHP 8.4+ +- [Be Framework の哲学](./01-overview.html) の基本的な理解 + +## はじめに + +このチュートリアルでは、Be Framework の核心哲学を示す救急トリアージシステムを構築します:**オブジェクトは何かを「する」のではなく、何かに「なる」のです。** + +患者は「トリアージされる」のではありません。医学プロトコルという超越的な知恵に基づいて、緊急症例または経過観察症例に**なる**のです。 + +## 変態の流れ + +``` +PatientArrival(生のバイタルサイン) + ↓ JTAS プロトコルが評価 +TriageAssessment(蛹の段階) + ↓ 運命が決定される +EmergencyCase または ObservationCase(最終的な存在) +``` + +## ステップ 1: オントロジーを定義する + +ロジックを書く前に、**ドメインオントロジー**—このドメインで何が存在できるかの語彙—を定義します。 + +### BodyTemperature + +```php +// src/Semantic/BodyTemperature.php + +/** + * 30°C未満または45°Cを超えると、人間は生存できない。 + * そのような値はセマンティックレベルで拒否される。 + */ +final class BodyTemperature +{ + #[Validate] + public function validate(float $bodyTemperature): void + { + if ($bodyTemperature < 30.0 || $bodyTemperature > 45.0) { + throw new LethalVitalException(); + } + } +} +``` + +### HeartRate + +```php +// src/Semantic/HeartRate.php + +/** + * 20 bpm未満または250 bpmを超えると心停止または致死的不整脈を示す。 + */ +final class HeartRate +{ + #[Validate] + public function validate(int $heartRate): void + { + if ($heartRate < 20 || $heartRate > 250) { + throw new LethalVitalException(); + } + } +} +``` + +**重要な洞察:** これらは単なる検証ルールではありません。**ドメインオントロジー**—何が存在できるかの語彙—を定義しています。この宣言的な基盤は、人間とAIの両方がドメインを理解するために読めるドキュメントとして機能します。([セマンティック変数](./06-semantic-variables.html) でAI可読なシステム設計の詳細をご覧ください。) + +## ステップ 2: 例外を定義する + +バイタルサインが生存不可能な状態を示す場合、患者の存在は拒否されます: + +```php +// src/Exception/LethalVitalException.php + +#[Message([ + 'en' => 'Vital signs indicate non-survivable conditions.', + 'ja' => 'バイタルサインが生存不可能な状態を示しています。' +])] +final class LethalVitalException extends DomainException +{ +} +``` + +## ステップ 3: Reason(超越)を定義する + +**JTASProtocol**(Japan Triage and Acuity Scale)はプログラマーの恣意的なルールではありません。**超越的な医学の知恵**—世界に独立して存在する客観的な知識—を表します。Be Framework では、このようなドメインロジックは**第一級市民**になります:注入可能、テスト可能、明示的に可視。 + +```php +// src/Reason/JTASProtocol.php + +/** + * JTAS (Japan Triage and Acuity Scale) プロトコル + * + * 個々の患者やプログラマーから独立して存在する + * 超越的な医学の知恵。 + * + * 注: 簡略化。実際のJTASは5レベル。 + */ +final readonly class JTASProtocol +{ + /** @return 'emergency'|'observation' */ + public function assess(float $bodyTemperature, int $heartRate): string + { + if ($bodyTemperature >= 39.0 || $heartRate >= 120) { + return 'emergency'; + } + return 'observation'; + } +} +``` + +これが**Reason**—変態を可能にする外部の力です。幼虫が蝶になるために環境条件が必要なように、私たちのデータもトリアージされた患者になるために JTASProtocol が必要です。 + +## ステップ 4: Input クラスを作成 + +出発点—到着時の生のバイタルサイン: + +```php +// src/Input/PatientArrival.php + +#[Be([TriageAssessment::class])] +final readonly class PatientArrival +{ + public function __construct( + public float $bodyTemperature, + public int $heartRate + ) {} +} +``` + +`#[Be]` 属性は運命を宣言します:この到着は TriageAssessment に**なります**。 + +## ステップ 5: 運命マーカーを作成 + +これらの型は2つの可能な運命を表します: + +```php +// src/Reason/Emergency.php +final readonly class Emergency {} + +// src/Reason/Observation.php +final readonly class Observation {} +``` + +これらは空のクラスではありません—それ自体が**区別**です。`Emergency` は `Observation` とは根本的に異なります。型自体が意味を持ちます。 + +## ステップ 6: Being クラスを作成 + +ここで変態が起こります。患者は中間状態にあり、最終形態はまだ決まっていません: + +```php +// src/Being/TriageAssessment.php + +/** + * 生のバイタルサインが JTAS プロトコル(超越的な知恵)と出会い、 + * 患者の運命が決定される。 + */ +#[Be([EmergencyCase::class, ObservationCase::class])] +final readonly class TriageAssessment +{ + public Emergency|Observation $being; + + public function __construct( + #[Input] public float $bodyTemperature, + #[Input] public int $heartRate, + #[Inject] JTASProtocol $protocol + ) { + $urgency = $protocol->assess($bodyTemperature, $heartRate); + $this->being = ($urgency === 'emergency') + ? new Emergency() + : new Observation(); + } +} +``` + +**重要な概念:** +- `#[Inject]` が JTASProtocol を持ち込む—外部からの超越的な知恵 +- `$being` プロパティ(Union型)がどの Final クラスが変態を受け取るかを決定 +- 「ステータスを設定する」のではなく、患者がその運命に**なる** + +## ステップ 7: Final クラスを作成 + +最終形態—それぞれ独自の**能力**を持つ: + +### EmergencyCase + +```php +// src/Final/EmergencyCase.php + +/** + * 最高優先度として存在する患者。 + * これは単なるステータスフラグではない。この患者は緊急である。 + * その型が他にはない能力を与える。 + */ +final readonly class EmergencyCase +{ + public string $priority; + public string $color; + + public function __construct( + #[Input] public float $bodyTemperature, + #[Input] public int $heartRate, + #[Input] public Emergency $being + ) { + $this->priority = 'IMMEDIATE'; + $this->color = 'RED'; + } + + /** + * EmergencyCase だけが ER 割り当てを要求できる + */ + public function assignER(): string + { + return "直ちに救急室1を確保。救急医を呼び出し。"; + } +} +``` + +### ObservationCase + +```php +// src/Final/ObservationCase.php + +/** + * 安定として存在する患者。 + * 緊急症例が処理される間、安全に待機できる。 + */ +final readonly class ObservationCase +{ + public string $priority; + public string $color; + + public function __construct( + #[Input] public float $bodyTemperature, + #[Input] public int $heartRate, + #[Input] public Observation $being + ) { + $this->priority = 'DELAYED'; + $this->color = 'GREEN'; + } + + /** + * 経過観察症例は待合室に割り当てられる + */ + public function assignWaitingArea(): string + { + return "待合室へ移動。30分ごとにバイタル監視。"; + } +} +``` + +注目:各 Final は**異なるメソッド**を持ちます。`EmergencyCase` は `assignER()` を、`ObservationCase` は `assignWaitingArea()` を持ちます。**型が能力を決定します**—経過観察の患者に救急室を割り当てることはできません。 + +## ステップ 8: 変態を実行 + +```php +// bin/app.php + +use Be\App\Input\PatientArrival; +use Be\App\Module\AppModule; +use Be\Framework\Becoming; +use Ray\Di\Injector; + +$injector = new Injector(new AppModule()); +$becoming = new Becoming($injector, 'Be\\App\\Semantic'); + +// 高熱の患者 +$patient = new PatientArrival(bodyTemperature: 39.5, heartRate: 90); +$result = $becoming($patient); + +echo $result->priority; // "IMMEDIATE" +echo $result->color; // "RED" +echo $result->assignER(); // "直ちに救急室1を確保..." +``` + +## 完全なフロー + +``` +PatientArrival(39.5°C, 90 bpm) + ↓ #[Be([TriageAssessment::class])] +TriageAssessment + ├─ JTASProtocol->assess() が 'emergency' を返す + └─ $being = Emergency + ↓ #[Be([EmergencyCase::class, ObservationCase::class])] +EmergencyCase($being が Emergency なので) + → priority: IMMEDIATE + → color: RED + → assignER(): "直ちに救急室1を確保..." +``` + +## 生存不可能な存在の処理 + +```php +// 生存可能範囲外の体温 +$invalid = new PatientArrival(bodyTemperature: 50.0, heartRate: 80); + +try { + $becoming($invalid); +} catch (SemanticVariableException $e) { + echo $e->getErrors()->getMessages('ja')[0]; + // "バイタルサインが生存不可能な状態を示しています。" +} +``` + +変態は**拒否されます**。致死的なバイタルサインを持つ患者は私たちのシステムに存在できません。 + +## なぜこれが重要か + +### 従来のアプローチ(Doing) + +```php +$patient = new Patient($temp, $hr); +if ($triageService->isEmergency($patient)) { + $patient->setStatus('emergency'); + $this->erService->assign($patient); +} +``` + +問題点: +- 患者は無効な状態で存在できる +- ステータスはいつでも変更できる +- `erService->assign()` はどの患者にも呼べる + +### Be Framework のアプローチ(Being) + +```php +$patient = new PatientArrival($temp, $hr); +$result = $becoming($patient); + +// $result は EmergencyCase または ObservationCase である +// EmergencyCase だけが assignER() メソッドを持つ +$result->assignER(); // 型安全:EmergencyCase でのみ可能 +``` + +利点: +- 生存不可能な状態は存在できない +- 型がステータスである(不変) +- 能力は存在に属する + +## プロジェクト構造 + +``` +src/ +├── Being/ +│ └── TriageAssessment.php # 中間段階 +├── Exception/ +│ └── LethalVitalException.php +├── Input/ +│ └── PatientArrival.php # 生データ +├── Module/ +│ └── AppModule.php # DI設定 +├── Final/ +│ ├── EmergencyCase.php # 最終形態:緊急 +│ └── ObservationCase.php # 最終形態:経過観察 +├── Reason/ +│ ├── Emergency.php # 運命マーカー +│ ├── JTASProtocol.php # 超越的な知恵 +│ └── Observation.php # 運命マーカー +└── Semantic/ + ├── BodyTemperature.php # 何が存在できるか + └── HeartRate.php +``` + +## 重要な洞察 + +1. **アクションより存在**: 患者は「トリアージされる」のではなく、トリアージされた状態に**なる** +2. **型がステータス**: `EmergencyCase` と `ObservationCase` は異なる能力を持つ異なる型 +3. **セマンティックな境界**: 致死的なバイタルサインは変態前に拒否される +4. **超越的な知恵**: JTASProtocol は独立して存在する—作成されるのではなく注入される +5. **不変性**: 一度変態すると、新たな変態なしにステータスは変更できない + +## 他のドメインでの変態 + +同じパターンがあらゆる場所に適用されます: + +| ドメイン | Input | Being | Final | Reason | +|---------|-------|-------|-------|--------| +| **トリアージ** | PatientArrival | TriageAssessment | Emergency/Observation | JTASProtocol | +| **醸造** | RawMaterials | Fermentation | PremiumSake/Vinegar | YeastCulture | +| **入国審査** | VisaApplication | ConsularReview | Resident/Visitor | ImmigrationLaw | +| **裁判** | Evidence | Trial | Guilty/Acquitted | PenalCode | +| **恒星進化** | GasCloud | Protostar | Star/BlackHole | PhysicsLaws | + +すべてのドメインに変態があります。すべての存在に理由があります。 + +## 次のステップ + +- [Semantic Variables](./06-semantic-variables.html) - セマンティック検証の詳細 +- [Type-Driven Metamorphosis](./07-type-driven-metamorphosis.html) - 高度な分岐パターン +- [Reason Layer](./08-reason-layer.html) - 超越の理解