diff --git a/_includes/manuals/1.0/en/contents.html b/_includes/manuals/1.0/en/contents.html index e3930fa..8b7dbfc 100644 --- a/_includes/manuals/1.0/en/contents.html +++ b/_includes/manuals/1.0/en/contents.html @@ -16,15 +16,19 @@
- + \ No newline at end of file diff --git a/_includes/manuals/1.0/ja/contents.html b/_includes/manuals/1.0/ja/contents.html index 707221b..85bc93d 100644 --- a/_includes/manuals/1.0/ja/contents.html +++ b/_includes/manuals/1.0/ja/contents.html @@ -16,15 +16,19 @@ - + \ No newline at end of file diff --git a/index.html b/index.html index e35a05b..f9b1755 100644 --- a/index.html +++ b/index.html @@ -11,7 +11,18 @@ The Ontological Programming Framework for PHP - + Learn more » + diff --git a/manuals/1.0/en/01-overview.md b/manuals/1.0/en/01-overview.md index 1dc98aa..3361b5f 100644 --- a/manuals/1.0/en/01-overview.md +++ b/manuals/1.0/en/01-overview.md @@ -5,7 +5,11 @@ category: Manual permalink: /manuals/1.0/en/01-overview.html --- -# Overview: A Different Way to Think About Code +# A Different Way to Think About Code + +> "The real voyage of discovery consists not in seeking new landscapes, but in having new eyes." +> +> —Marcel Proust, 'The Prisoner' (In Search of Lost Time, Volume 5) 1923 ## First, Look at This diff --git a/manuals/1.0/en/02-input-classes.md b/manuals/1.0/en/02-input-classes.md index 9720c34..54914ba 100644 --- a/manuals/1.0/en/02-input-classes.md +++ b/manuals/1.0/en/02-input-classes.md @@ -7,6 +7,12 @@ permalink: /manuals/1.0/en/02-input-classes.html # Input Classes +> "We begin from conditions we did not choose, and from there we build our existence." +> +> —From Heidegger's concept of Geworfenheit (thrownness) in 'Being and Time' (1927) + +## The Beginning + Input Classes are the starting point of every transformation in Be Framework. They contain only what the object itself possesses—no external dependencies. Think of it as the object's identity. These elements exist within the object, forming what we call the object's **Immanent Nature**. diff --git a/manuals/1.0/en/03-being-classes.md b/manuals/1.0/en/03-being-classes.md index d38d993..c7fe6f7 100644 --- a/manuals/1.0/en/03-being-classes.md +++ b/manuals/1.0/en/03-being-classes.md @@ -7,6 +7,12 @@ permalink: /manuals/1.0/en/03-being-classes.html # Being Classes +> "The Tao does nothing, yet nothing is left undone." +> +> —Laozi, Tao Te Ching, Chapter 37 (6th century BC) + +## Immanence Meets Transcendence + Being Classes are where transformation actually occurs. The object's own nature (**Immanent Nature**) meets forces provided from the outside (**Transcendent Forces**), and a new being is born. If Input Classes are the "beginning," Being Classes express the "moment of change." diff --git a/manuals/1.0/en/04-final-objects.md b/manuals/1.0/en/04-final-objects.md index 45f2e3b..d0aa83f 100644 --- a/manuals/1.0/en/04-final-objects.md +++ b/manuals/1.0/en/04-final-objects.md @@ -7,6 +7,12 @@ permalink: /manuals/1.0/en/04-final-objects.html # Final Objects +> "You are not me. How can you know that I don't know the feelings of fish?" +> +> —Zhuangzi's reply when asked "You are not a fish. How can you know the feelings of fish?" (Zhuangzi, 4th century BC) + +## The Destination + Final Objects represent the destination of metamorphosis—complete, transformed beings that embody the user's actual interest. These are what the application ultimately cares about. ## Characteristics of Final Objects @@ -17,9 +23,20 @@ Final Objects represent the destination of metamorphosis—complete, transformed **Rich State**: Unlike Input Classes, Final Objects contain the full richness of transformed data. +## Temporal Completeness + +Here's an intriguing question: What if objects had such completeness that they needed no external testing? + +The Be Framework captures the temporal existence of objects along two axes: + +- **`#[Be]`**: The intended self, the destination (future directionality) +- **`$been`**: The completed self (past perfect self-evidence) + +Traditional programming verifies whether objects have been processed correctly through external tests. But what if objects themselves contained evidence of their completion? Instead of external verification, intrinsic self-evidence becomes possible. + ## Examples -### Successful Outcomes +### Intrinsic Self-Evidence ```php final class SuccessfulOrder { @@ -27,43 +44,71 @@ final class SuccessfulOrder public readonly string $confirmationCode; public readonly DateTimeImmutable $timestamp; public readonly string $message; + public readonly BeenProcessed $been; // Self-evidence public function __construct( - #[Input] Money $total, // Immanent from validation - #[Input] CreditCard $card, // Immanent from validation - #[Inject] OrderIdGenerator $generator, // Transcendent - #[Inject] Receipt $receipt // Transcendent + #[Input] Money $total, // Immanent nature + #[Input] CreditCard $card, // Immanent nature + #[Inject] OrderIdGenerator $generator, // Transcendent force + #[Inject] Receipt $receipt // Transcendent force ) { - $this->orderId = $generator->generate(); // New Immanent - $this->confirmationCode = $receipt->generate($total); // New Immanent - $this->timestamp = new DateTimeImmutable(); // New Immanent - $this->message = "Order confirmed: {$this->orderId}"; // New Immanent + $this->orderId = $generator->generate(); // New immanent nature + $this->confirmationCode = $receipt->generate($total); // New immanent nature + $this->timestamp = new DateTimeImmutable(); // New immanent nature + $this->message = "Order confirmed: {$this->orderId}"; // New immanent nature + + // Self-evidence of completion + $this->been = new BeenProcessed( + actor: $card->getHolderName(), + timestamp: $this->timestamp, + evidence: [ + 'total' => $total->getAmount(), + 'payment_method' => $card->getType(), + 'confirmation' => $this->confirmationCode + ] + ); } } ``` -### Error States as Final Objects +This object requires no external testing. The `$been` property contains complete evidence of completion. + +### Error States with Self-Evidence ```php final class FailedOrder { public readonly string $errorCode; public readonly string $message; public readonly DateTimeImmutable $timestamp; + public readonly BeenRejected $been; // Self-evidence of failure public function __construct( - #[Input] array $errors, // Immanent from validation - #[Inject] Logger $logger, // Transcendent - #[Inject] ErrorCodeGenerator $generator // Transcendent + #[Input] array $errors, // Immanent nature + #[Inject] Logger $logger, // Transcendent force + #[Inject] ErrorCodeGenerator $generator // Transcendent force ) { $this->errorCode = $generator->generate(); $this->message = "Order failed: " . implode(', ', $errors); $this->timestamp = new DateTimeImmutable(); + // Self-evidence of failure + $this->been = new BeenRejected( + reason: 'validation_failed', + timestamp: $this->timestamp, + evidence: [ + 'error_count' => count($errors), + 'error_types' => array_keys($errors), + 'error_code' => $this->errorCode + ] + ); + $logger->logOrderFailure($this->errorCode, $errors); // Side effect } } ``` +Both success and failure carry their own self-evidence of completion. Instead of external tests, the objects themselves maintain complete records of what occurred. + ## Final Objects vs Input Classes | Input Classes | Final Objects | @@ -99,8 +144,12 @@ The path from Input to Final Object represents a complete transformation journey 2. **Being Classes**: Transformation stages ("Here's how I change") 3. **Final Object**: Complete result ("Here's what I became") -Users primarily care about Input (what they provide) and Final Objects (what they get back). The Being Classes in between are the framework's responsibility—the machinery of transformation that creates the bridge between intention and result. +Users primarily care about Input (what they provide) and Final Objects (what they get back). The Being Classes in between are our responsibility as designers. It's crucial to understand the temporal transformation of the domain well and design the mechanisms of that transformation to bridge intention and result. + +## Transformation Complete + +Final Objects express the state of entelecheia (complete realization). They are fully realized beings that no longer need transformation. -## Natural Completion +The immanent nature that began with Input Classes, through encounters with various transcendent forces and natural transformation, finally reaches this completed form. There is no more "trying to become" or "intending to change." Everything is complete, and the value that users truly sought is realized here. This is the essential value of our system. -Final Objects embody the completion of natural transformation. They don't need to "do" anything more—they simply *are* the result that was meant to emerge from the original input's encounter with the world's capabilities. +This is the destination that Be Framework aims for in programming—existence that embodies not "what to do" but "what to be." diff --git a/manuals/1.0/en/05-metamorphosis-patterns.md b/manuals/1.0/en/05-metamorphosis-patterns.md index 42a80e8..2a3afba 100644 --- a/manuals/1.0/en/05-metamorphosis-patterns.md +++ b/manuals/1.0/en/05-metamorphosis-patterns.md @@ -1,40 +1,46 @@ --- layout: docs-en -title: "5. Metamorphosis Patterns" +title: "5. Metamorphosis" category: Manual -permalink: /manuals/1.0/en/05-metamorphosis-patterns.html +permalink: /manuals/1.0/en/05-metamorphosis.html --- -# Metamorphosis Patterns +# Metamorphosis -Be Framework supports various patterns of transformation, from simple linear chains to complex branching destinies. Understanding these patterns helps you design natural transformation flows. +> "Space and time cannot be defined independently of each other." +> +> —Albert Einstein, The Foundation of the General Theory of Relativity (1916) -## Linear Metamorphic Chain +## Time and Domain Are Inseparable -The simplest pattern: A → B → C → D +Just as Einstein discovered the inseparability of time and space, the Be Framework considers time and domain as a single entity that cannot be divided. Approval processes have their approval time, payments have their payment time, and transformation naturally emerges along the unique temporal axis that each domain logic possesses. + +## Irreversible Flow of Time + +Object metamorphosis follows the arrow of time in a unidirectional flow. There is no returning to the past, no remaining in the same moment: ```php -// Input +// Time T0: Birth of input #[Be(EmailValidation::class)] final class EmailInput { /* ... */ } -// First transformation +// Time T1: First metamorphosis (T0 is already past) #[Be(UserCreation::class)] final class EmailValidation { /* ... */ } -// Second transformation +// Time T2: Second metamorphosis (T1 becomes memory) #[Be(WelcomeMessage::class)] final class UserCreation { /* ... */ } -// Final result +// Time T3: Final existence (encompassing all past) final class WelcomeMessage { /* ... */ } ``` -Each stage naturally leads to the next, like a river flowing to the sea. +Each moment never returns, and new existence preserves previous forms as memory within itself. Like a river flowing, time moves only in one direction. -## Branching Destinies +## Self-Determination of Destiny -Objects can have multiple possible futures based on their nature: +Like living beings in reality, objects determine their own destiny through the interaction between intrinsic nature and external environment. This is not following a predetermined route, but natural metamorphosis responding to the circumstances of that moment: ```php #[Be([ApprovedApplication::class, RejectedApplication::class])] @@ -43,11 +49,12 @@ final class ApplicationReview public readonly ApprovedApplication|RejectedApplication $being; public function __construct( - #[Input] array $documents, // Immanent - #[Inject] ReviewService $reviewer // Transcendent + #[Input] array $documents, // Intrinsic nature + #[Inject] ReviewService $reviewer // External environment ) { $result = $reviewer->evaluate($documents); + // Destiny is decided at this very moment $this->being = $result->isApproved() ? new ApprovedApplication($documents, $result->getScore()) : new RejectedApplication($result->getReasons()); @@ -55,61 +62,7 @@ final class ApplicationReview } ``` -The object determines its own destiny through **Type-Driven Metamorphosis**. - -## Fork-Join Pattern - -A single input branches into parallel transformations that later converge: - -```php -#[Be(PersonalizedRecommendation::class)] -final class UserAnalysis -{ - public readonly PersonalizedRecommendation $being; - - public function __construct( - #[Input] string $userId, // Immanent - #[Inject] BehaviorAnalyzer $behavior, // Transcendent - #[Inject] PreferenceAnalyzer $preference, // Transcendent - #[Inject] SocialAnalyzer $social // Transcendent - ) { - // Parallel analysis - $behaviorScore = $behavior->analyze($userId); - $preferenceScore = $preference->analyze($userId); - $socialScore = $social->analyze($userId); - - // Convergence - $this->being = new PersonalizedRecommendation( - $behaviorScore, - $preferenceScore, - $socialScore - ); - } -} -``` - -## Conditional Transformation - -Sometimes transformation depends on runtime conditions: -```php -#[Be([PremiumFeatures::class, BasicFeatures::class])] -final class FeatureActivation -{ - public readonly PremiumFeatures|BasicFeatures $being; - - public function __construct( - #[Input] User $user, // Immanent - #[Inject] SubscriptionService $service // Transcendent - ) { - $subscription = $service->getSubscription($user); - - $this->being = $subscription->isPremium() - ? new PremiumFeatures($user, $subscription) - : new BasicFeatures($user); - } -} -``` ## Nested Metamorphosis @@ -122,8 +75,8 @@ final class OrderProcessing public readonly ShippingResult $shipping; public function __construct( - #[Input] Order $order, // Immanent - #[Inject] Becoming $becoming // Transcendent + #[Input] Order $order, // Intrinsic nature + #[Inject] Becoming $becoming // External environment ) { // Nested transformations $this->payment = $becoming(new PaymentInput($order->getPayment())); @@ -134,7 +87,26 @@ final class OrderProcessing ## Self-Organizing Pipelines -The beauty of these patterns is that they're **self-organizing**. Objects declare their own destinies, and the framework naturally follows the transformation paths without external orchestration. +The beauty of these patterns is that they're **self-organizing**. Like UNIX pipes that combine simple commands to create powerful systems, Be Framework combines typed objects to create natural transformation flows. + +### Comparison with UNIX Pipes + +```bash +# UNIX: Text flows through externally controlled pipelines +cat access.log | grep "404" | awk '{print $7}' | sort | uniq -c +``` + +```php +// Be Framework: Rich objects flow through intrinsically controlled pipelines +$finalObject = $becoming(new ApplicationInput($documents)); +// Objects themselves know their next transformation destination +``` + +Key evolution: +- **UNIX**: External shell controls the pipeline +- **Be Framework**: Objects declare their own destiny with `#[Be()]` + +### Self-Organization in Action ```php // No controllers, no orchestrators—just natural flow @@ -147,14 +119,77 @@ match (true) { }; ``` -## Pattern Selection +This self-organization provides: +- No external orchestration needed +- Type safety maintained +- Capabilities provided through dependency injection +- Testable independent components + +## Implementation Guidelines + +### When to Choose Linear Metamorphosis + +For sequential processing where each stage prepares the data needed for the next: + +```php +User Registration → Email Verification → Account Activation → Welcome Notification +``` + +This is suitable when failure at any stage should halt the entire process. + +### When to Choose Conditional Branching + +When the same input branches into different results based on nature or permissions: + +```php +// Implementation example: Feature differentiation by payment capability +#[Be([FullAccess::class, LimitedAccess::class, ReadOnlyAccess::class])] +final class AccessDetermination +{ + public readonly FullAccess|LimitedAccess|ReadOnlyAccess $being; + + public function __construct( + #[Input] User $user, + #[Inject] PaymentStatus $payment + ) { + $this->being = match($payment->getStatus()) { + 'premium' => new FullAccess($user, $payment->getFeatures()), + 'basic' => new LimitedAccess($user, $payment->getLimits()), + default => new ReadOnlyAccess($user) + }; + } +} +``` + +### When to Choose Nested Metamorphosis + +When executing multiple independent processes in parallel and aggregating their results: + +```php +final class OrderCompletion +{ + public function __construct( + #[Input] OrderData $order, + #[Inject] Becoming $becoming + ) { + // Independent parallel processing + $this->inventory = $becoming(new InventoryCheck($order->items)); + $this->payment = $becoming(new PaymentProcess($order->payment)); + $this->shipping = $becoming(new ShippingArrange($order->address)); + } +} +``` + +## Design Principles + +Choose metamorphosis patterns according to the natural flow of domain logic: -Choose patterns based on your domain's natural flow: +- **Don't Force**: Don't force into artificial patterns +- **Keep Simple**: Choose the most simple and understandable form +- **Testable**: Each metamorphosis stage can be tested independently +- **Type Safe**: Next type is guaranteed by `#[Be()]` -- **Linear**: Sequential processes (validation → processing → completion) -- **Branching**: Decision points (approve/reject, success/failure) -- **Fork-Join**: Parallel analysis that converges -- **Conditional**: Feature flags, permissions, subscriptions -- **Nested**: Complex operations with sub-processes +Objects govern their own metamorphosis. -The key is to let the transformation emerge naturally from the domain logic, not force it into artificial patterns. +Heraclitus said "the river flows" is not correct, but rather "the flowing is the river." He believed that existence cannot be separated from change. Be Framework likewise believes that to capture essence, domain and time cannot be separated. +Domains are temporal existence. There are possibilities and being at each moment. Capturing how input classes, being classes, and final objects naturally metamorphose along the flow of time is the core of the Be Framework. diff --git a/manuals/1.0/en/06-semantic-variables.md b/manuals/1.0/en/06-semantic-variables.md index 909bd66..cb07461 100644 --- a/manuals/1.0/en/06-semantic-variables.md +++ b/manuals/1.0/en/06-semantic-variables.md @@ -7,35 +7,49 @@ permalink: /manuals/1.0/en/06-semantic-variables.html # Semantic Variables -> "What should exist must be valid. What cannot exist will never be born." +> "What exists necessarily exists, and what does not exist necessarily does not exist" +> +> —Spinoza, *Ethics*, Part I, Proposition 29 (1677) -Semantic Variables embody Be Framework's deepest principle: **only meaningful beings can exist**. +Where should data validity be guaranteed? Controller? Model? Validator? -## The Problem +Be Framework's answer is clear: **names themselves should carry constraints**. +`$email` should not be just a string—it should be a **valid email address**. `$age` cannot have negative values. -Traditional types defend against the meaningless: +Semantic Variables are identifiers of information that express meaning and hold constraints—they are **complete information models**. + +## The Problem: Scattered Incompleteness + +Traditional approaches scatter the definition of meaning across multiple locations: ```php -function createUser(string $name, string $email, int $age) { - if (empty($name)) throw new Exception(); - if (!filter_var($email, FILTER_VALIDATE_EMAIL)) throw new Exception(); - // ... endless defensive programming -} +// Controllers/models/validators... +if (empty($name)) throw new Exception("error.name.empty"); +if (!filter_var($email, FILTER_VALIDATE_EMAIL)) throw new Exception("error.email.invalid"); + +// messages/en.yml +error.name.empty: "Name is required" +error.email.invalid: "Please enter a valid email address" + +// README.md +// "Name must be 1-100 characters, whitespace-only not allowed..." ``` -## The Solution +The following problems occur: +- **Validation**: Scattered across controllers +- **Error messages**: Managed in separate files +- **Constraint rules**: Duplicated in multiple places +- **Meaning definition**: Exists only in documentation -Semantic Variables change the fundamental question from "Is this valid?" to "Can this exist?" +There is no central place to see the meanings that the system handles. -```php -function createUser(PersonName $name, EmailAddress $email, Age $age) { - // If we reach here, existence is already guaranteed -} -``` +## The Solution: Semantic Completeness + +Be Framework integrates scattered definitions into **complete information models**. Constructor arguments and class properties can only use registered **semantic variables**. ## Defining Existence -Every semantic variable defines what can exist in its domain: +Semantic variables are defined as classes in dedicated folders: ```php final class Name @@ -50,25 +64,45 @@ final class Name } ``` -Multiple validation contexts exist naturally: +## Validation Contexts + +Different business contexts may require different rules. Semantic variables naturally support multiple validation contexts: ```php final class ProductCode { #[Validate] - public function validate(string $code): void { /* standard rules */ } + public function validate(string $code): void + { + // Standard product code validation (e.g., 8-digit alphanumeric) + if (!preg_match('/^[A-Z0-9]{8}$/', $code)) { + throw new InvalidProductCodeException(); + } + } #[Validate] - public function validateLegacy(#[Legacy] string $code): void { /* legacy rules */ } + public function validateLegacy(#[Legacy] string $code): void + { + // Relaxed validation for legacy systems (e.g., 6-10 digit alphanumeric) + if (!preg_match('/^[A-Z0-9]{6,10}$/', $code)) { + throw new InvalidLegacyProductCodeException(); + } + } #[Validate] - public function validatePremium(#[Premium] string $code): void { /* premium rules */ } + public function validatePremium(#[Premium] string $code): void + { + // Strict validation for premium products (e.g., specific prefix required) + if (!preg_match('/^PREM[A-Z0-9]{4}$/', $code)) { + throw new InvalidPremiumProductCodeException(); + } + } } ``` -## Meaningful Failure +## The Meaning of Failure -When existence fails, meaning must be preserved: +When existence fails, the meaning of failure must be preserved: ```php #[Message([ @@ -78,18 +112,18 @@ When existence fails, meaning must be preserved: final class EmptyNameException extends DomainException {} ``` -The framework collects **all validation errors** before throwing, creating complete understanding of what cannot exist. +The framework collects not just the first thrown exception but **all validation errors** as a collection of exceptions, creating complete understanding of why existence is impossible. ## Natural Integration -Semantic variables work automatically in Being constructors: +Semantic variables work automatically in constructors: ```php final readonly class UserProfile { public function __construct( #[Input] #[English] public string $name, // Auto-validated as English name - #[Input] string $emailAddress, // Auto-validated as email + #[Input] string $emailAddress, // Auto-validated as email address #[Inject] NameFormatter $formatter ) { // At this point, all inputs are guaranteed valid @@ -97,9 +131,11 @@ final readonly class UserProfile } ``` +The variable name `$name` is automatically associated with the `Name` semantic variable class, and `$emailAddress` with the `EmailAddress` semantic variable class. + ## Hierarchical Validation -Semantic variables can build upon each other: +Semantic variables can build upon other semantic variables. This is a powerful technique for expressing the natural hierarchical structure of business rules in the type system. ```php final class TeenAge @@ -107,13 +143,68 @@ final class TeenAge #[Validate] public function validate(#[Teen] int $age): void { - // Inherits basic Age validation, adds teen-specific rules + // First, basic Age validation is executed (automatically called via #[Teen]) + // Then, teen-specific rules are added if ($age < 13) throw new TeenAgeTooYoungException(); if ($age > 19) throw new TeenAgeTooOldException(); } } ``` +This hierarchical approach builds rich semantic hierarchies: + +- `Email` → `CorporateEmail` (corporate domain required) → `ExecutiveEmail` (executive-level constraints) +- `Price` → `DiscountPrice` (discount rate limits) → `MemberPrice` (member pricing rules) +- `Password` → `AdminPassword` (admin requirements) → `SystemPassword` (strict system admin requirements) +- `Address` → `ShippingAddress` (deliverable regions) → `InternationalAddress` (international shipping support) + +Each layer inherits constraints from the previous layer and adds its own unique constraints. Nothing that fails basic `Email` validation can ever exist as `ExecutiveEmail`. This is not merely a combination of validations—it is the **natural refinement of concepts**. + +## Relationship Constraints + +Semantic variables exist not only in isolation but can also hold relationships with other semantic variables as constraints. What's remarkable is **how easy this is to describe**: + +```php +final readonly class UserRegistration +{ + public function __construct( + #[Input] string $email, + #[Input] string $confirmEmail, + #[Input] string $password, + #[Input] string $confirmPassword, + ) { + // Nothing needs to be written here! + // The framework automatically validates relationships + } +} +``` + +The framework automatically discovers and applies validation classes that **partially match** the target constructor's signature. + +```php +// If this exists... +final class EmailConfirmation +{ + #[Validate] + public function validate(string $email, string $confirmEmail): void + { + if ($email !== $confirmEmail) { + throw new EmailMismatchException(); + } + } +} + +// It's automatically applied to any constructor with $email, $confirmEmail! +``` + +Examples of relationship constraints: +- `$startDate` and `$endDate`: Start date must be before end date +- `$minPrice` and `$maxPrice`: Minimum price must be less than or equal to maximum price +- `$email` and `$confirmEmail`: Email address confirmation match required +- `$currentPassword` and `$newPassword`: New password must differ from current one + +Developers define business rules once, and they're automatically applied to all objects with matching signatures. These constraints function as **preconditions** for object existence. Unless preconditions are met, that object cannot even exist. + ## Error Handling Multilingual error messages adapt automatically: @@ -127,13 +218,16 @@ try { } ``` -## The Revolution +## What Meaning Brings + +**Names are identifiers of meaning and constraints.** This simple principle alone realizes a world rich enough to be called a framework. + +Semantic Variables make **impossible states impossible**. Invalid email addresses cannot exist as `$email`, negative ages cannot be born as `$age`. Out-of-stock products cannot be ordered as `$orderId`, and addresses outside delivery zones cannot be specified as `$shippingAddress`. -Semantic Variables eliminate defensive programming by making **impossible states impossible**. +The type system itself becomes a **domain language**, where each type speaks of what can exist in your business domain. -The type system becomes a **domain language**—each type carries the meaning of what can exist in your business domain. +Looking at function signatures, they become specifications: -Function signatures become **documentation**: ```php function processOrder(ProductCode $product, PaymentAmount $amount, CustomerAge $age) { @@ -141,8 +235,14 @@ function processOrder(ProductCode $product, PaymentAmount $amount, CustomerAge $ } ``` +This function accepts only valid product codes, positive amounts, and valid ages. No need to read documentation—the types tell the whole story. + +Defensive programming becomes unnecessary. Argument validation, null checks, range verification, inventory confirmation, geographic constraints—semantic variables guarantee all of these. Code can focus on its true purpose: implementing business logic. + +What began as a simple naming convention evolves into hierarchical validation, relationship constraints, external resource integration, building a complete domain guarantee system. **The meaning embedded in names supports the integrity of the entire system.** + --- -**Next**: Learn about [Type-Driven Metamorphosis](06-type-driven-metamorphosis.md) where objects discover their own nature. +**Next**: Learn about [Type-Driven Metamorphosis](07-type-driven-metamorphosis.html) where objects discover their own nature. *"Semantic Variables don't just validate data—they ensure only meaningful beings can exist."* diff --git a/manuals/1.0/en/12-from-doing-to-being-final.md b/manuals/1.0/en/12-from-doing-to-being-final.md index 37157b0..5c63655 100644 --- a/manuals/1.0/en/12-from-doing-to-being-final.md +++ b/manuals/1.0/en/12-from-doing-to-being-final.md @@ -7,7 +7,11 @@ permalink: /manuals/1.0/en/12-from-doing-to-being-final.html # From Doing to Being: The Bigger Picture -> *"The real voyage of discovery consists not in seeking new landscapes, but in having new eyes."* — Marcel Proust +> "All things that exist are in the process of becoming." +> +> —Heraclitus, Fragments (c. 500 BC) + +## What You Have Discovered You've written Input Classes, created Being Classes, and watched objects transform rather than mutate. diff --git a/manuals/1.0/en/index.md b/manuals/1.0/en/index.md index c5fec09..cdbfb37 100644 --- a/manuals/1.0/en/index.md +++ b/manuals/1.0/en/index.md @@ -21,7 +21,7 @@ Intermediate transformations through Immanent + Transcendent interactions ## [4. Final Objects](04-final-objects.html) The destination of metamorphosis - complete transformed beings -## [5. Metamorphosis Patterns](05-metamorphosis-patterns.html) +## [5. Metamorphosis Patterns](05-metamorphosis.html) Simple chains, branching destinies, and complex transformations ## [6. Semantic Variables](06-semantic-variables.html) diff --git a/manuals/1.0/ja/01-overview.md b/manuals/1.0/ja/01-overview.md index caff87a..5faf23a 100644 --- a/manuals/1.0/ja/01-overview.md +++ b/manuals/1.0/ja/01-overview.md @@ -5,7 +5,11 @@ category: Manual permalink: /manuals/1.0/ja/01-overview.html --- -## 概要: 新しいパラダイム +# 概要 + +> 「真の発見の航海は、新しい風景を求めることではなく、新しい目を持つことにある。」 +> +> —マルセル・プルースト『囚われの女』(À la recherche du temps perdu 第5巻)1923年 ## まず、これを見てください diff --git a/manuals/1.0/ja/02-input-classes.md b/manuals/1.0/ja/02-input-classes.md index 7e3f178..ff08507 100644 --- a/manuals/1.0/ja/02-input-classes.md +++ b/manuals/1.0/ja/02-input-classes.md @@ -7,6 +7,12 @@ permalink: /manuals/1.0/ja/02-input-classes.html # 入力クラス +> 「私たちは自分で選択できない条件から始まり、そこから自分の存在を築く」 +> +> —ハイデガーの被投性(Geworfenheit)概念より(『存在と時間』1927年) + +## 出発点 + 入力クラスは、Beフレームワークにおけるすべての変容の出発点です。 ここにはオブジェクト自身が持つ要素だけが含まれ、外部依存がありません。いわばオブジェクトのアイデンティティです。オブジェクトの内側にあるものなので、これを**内在的性質、イマナンス(Immanence)**と呼びます。 diff --git a/manuals/1.0/ja/03-being-classes.md b/manuals/1.0/ja/03-being-classes.md index 0b1d419..423b2e0 100644 --- a/manuals/1.0/ja/03-being-classes.md +++ b/manuals/1.0/ja/03-being-classes.md @@ -7,6 +7,12 @@ permalink: /manuals/1.0/ja/03-being-classes.html # 存在クラス +> 「道常無為而無不為」 +> +> —道は常に無為にして、而も為さざることなし(老子『道徳経』第三十七章 紀元前6世紀) + +## 内在と超越 + 存在クラスは変容が実際に起こる場所です。 オブジェクト自身が持つ性質(**内在的性質(イマナンス)**)と、外部から提供される力(**超越的な力(トランセンデンス)**)が出会い、次の新しい存在が生まれます。入力クラスが「始まり」なら、存在クラスは「変わる瞬間」を表現します。 diff --git a/manuals/1.0/ja/04-final-objects.md b/manuals/1.0/ja/04-final-objects.md index e3f2713..077ee58 100644 --- a/manuals/1.0/ja/04-final-objects.md +++ b/manuals/1.0/ja/04-final-objects.md @@ -7,19 +7,39 @@ permalink: /manuals/1.0/ja/04-final-objects.html # 最終オブジェクト -最終オブジェクトは変容の目的地を表します—ユーザーの実際の関心を体現する、完全で変容した存在です。これらはアプリケーションが最終的に気にかけるものです。 +> 「あなたは私ではない。どうして私が魚の気持ちを知らないと分かるのか?」 +> +> —「あなたは魚ではない。どうして魚の気持ちが分かるのか」と問われた時に荘子が返した言葉 (『荘子』紀元前4世紀) + +## 終着点 + +最終オブジェクトは変容の旅路の到達点です。 +ユーザーが求める価値、アプリケーションが届けたい結果が具現化された、完全で最終的な存在です。 + +これは入力クラスから始まった内在的性質(イマナンス)が、様々な超越的力(トランセンデンス)と出会い、自然な変容を経て達成した最終形態です。アリストテレスの言うエンテレケイア、すなわち潜在性が完全に現実化された状態を体現しています。 ## 最終オブジェクトの特徴 -**完全な存在**: 最終オブジェクトは意図された目的のためにさらなる変容を必要としない、完全に形成されたエンティティです。 +**完全性(エンテレケイア)**: これ以上の変容を必要としない、完全に現実化された存在です。 + +**ユーザー価値の実現**: ユーザーが本当に必要とするもの、意味のあるデータや操作の成功結果を表現します。 + +**豊かな状態**: 入力クラスとは対照的に、最終オブジェクトはドメインの豊富さを完全に表現した存在です。 + +## 時間的存在の完全性 + +ここで興味深い問いがあります。テストが不要になるほどの完全性を持つオブジェクトがあったらどうでしょう? -**ユーザー中心**: これらはユーザーが実際に欲しいもの—成功した操作、意味のあるデータ、実行可能な結果を表します。 +Be Frameworkでは、オブジェクトの時間的存在を二つの軸で捉えます: -**豊富な状態**: 入力クラスとは異なり、最終オブジェクトは変容されたデータの完全な豊かさを含みます。 +- **`#[Be]`**: なりたい自分、向かう先(未来への方向性) +- **`$been`**: 完了した自分(過去完了の自己証明) + +従来のプログラミングでは、オブジェクトが正しく処理されたかどうかを外部のテストで検証します。しかし、オブジェクト自身が完了の証拠を内包していたらどうでしょう?外部による検証ではなく、内在的な自己証明が可能になります。 ## 例 -### 成功した結果 +### 内在的自己証明を持つ結果 ```php final class SuccessfulOrder { @@ -27,51 +47,79 @@ final class SuccessfulOrder public readonly string $confirmationCode; public readonly DateTimeImmutable $timestamp; public readonly string $message; + public readonly BeenProcessed $been; // 自己証明 public function __construct( - #[Input] Money $total, // 検証からの内在的 - #[Input] CreditCard $card, // 検証からの内在的 - #[Inject] OrderIdGenerator $generator, // 超越的 - #[Inject] Receipt $receipt // 超越的 + #[Input] Money $total, // 内在的性質 + #[Input] CreditCard $card, // 内在的性質 + #[Inject] OrderIdGenerator $generator, // 超越的力 + #[Inject] Receipt $receipt // 超越的力 ) { - $this->orderId = $generator->generate(); // 新しい内在的 - $this->confirmationCode = $receipt->generate($total); // 新しい内在的 - $this->timestamp = new DateTimeImmutable(); // 新しい内在的 - $this->message = "注文確認: {$this->orderId}"; // 新しい内在的 + $this->orderId = $generator->generate(); // 新しい内在的性質 + $this->confirmationCode = $receipt->generate($total); // 新しい内在的性質 + $this->timestamp = new DateTimeImmutable(); // 新しい内在的性質 + $this->message = "注文確認: {$this->orderId}"; // 新しい内在的性質 + + // 完了の自己証明 + $this->been = new BeenProcessed( + actor: $card->getHolderName(), + timestamp: $this->timestamp, + evidence: [ + 'total' => $total->getAmount(), + 'payment_method' => $card->getType(), + 'confirmation' => $this->confirmationCode + ] + ); } } ``` -### 最終オブジェクトとしてのエラー状態 +このオブジェクトは外部テストを必要としません。`$been`プロパティが完了の完全な証拠を内包しているからです。 + +### エラー状態の自己証明 ```php final class FailedOrder { public readonly string $errorCode; public readonly string $message; public readonly DateTimeImmutable $timestamp; + public readonly BeenRejected $been; // 失敗の自己証明 public function __construct( - #[Input] array $errors, // 検証からの内在的 - #[Inject] Logger $logger, // 超越的 - #[Inject] ErrorCodeGenerator $generator // 超越的 + #[Input] array $errors, // 内在的性質 + #[Inject] Logger $logger, // 超越的力 + #[Inject] ErrorCodeGenerator $generator // 超越的力 ) { $this->errorCode = $generator->generate(); $this->message = "注文失敗: " . implode(', ', $errors); $this->timestamp = new DateTimeImmutable(); + // 失敗の自己証明 + $this->been = new BeenRejected( + reason: 'validation_failed', + timestamp: $this->timestamp, + evidence: [ + 'error_count' => count($errors), + 'error_types' => array_keys($errors), + 'error_code' => $this->errorCode + ] + ); + $logger->logOrderFailure($this->errorCode, $errors); // 副作用 } } ``` +成功も失敗も、どちらも完了の自己証明を持ちます。外部テストではなく、オブジェクト自身が何が起こったかの完全な記録を保持しているのです。 + ## 最終オブジェクト vs 入力クラス | 入力クラス | 最終オブジェクト | |-----------|-----------------| -| 純粋なアイデンティティ | 豊富で変容した状態 | -| 出発点 | 目的地 | +| 純粋なアイデンティティ | 豊かで変容した状態 | +| 変容の出発点 | 変容の到達点 | | ユーザーが提供するもの | ユーザーが受け取るもの | -| 単純な構造 | 完全な機能 | +| シンプルな構造 | 完全に実現された機能 | ## 複数の最終的運命 @@ -99,8 +147,12 @@ if ($order->being instanceof SuccessfulOrder) { 2. **存在クラス**: 変容段階(「これが私の変化の仕方です」) 3. **最終オブジェクト**: 完全な結果(「これが私がなったものです」) -ユーザーは主に入力(彼らが提供するもの)と最終オブジェクト(彼らが受け取るもの)に関心を持ちます。間にある存在クラスはフレームワークの責任です—意図と結果の間の橋を作る変容の機械です。 +ユーザーは主に入力(彼らが提供するもの)と最終オブジェクト(彼らが受け取るもの)に関心を持ちます。間にある存在クラスは私たち設計者の責任です。意図と結果の間の橋渡しをするためにドメインの時間的変容をよく理解し、その変容の仕組みを設計することが重要です。 + +## 変容の完成 + +最終オブジェクトは、エンテレケイア(完全実現)の状態を表現します。変容の必要がもうない、完全に実現された存在です。 -## 自然な完成 +入力クラスから始まった内在的性質(イマナンス)が、様々な超越的力(トランセンデンス)と出会いながら自然な変容を経て、ついに到達した完成形です。ここにはもう「なろうとする」努力も、「変わろうとする」意図もありません。すべてが完了し、ユーザーが本当に求めていた価値がここに実現されています。私たちのシステムの本質的な価値です。 -最終オブジェクトは自然な変容の完成を体現します。これらはもう何かを「する」必要がありません—単純に、元の入力が世界の能力と出会うことから生まれることを意図された結果*である*のです。 \ No newline at end of file +これこそが、Be Frameworkが目指すプログラミングの到達点—「何をするか」ではなく「何であるか」が体現された存在です。 diff --git a/manuals/1.0/ja/05-metamorphosis-patterns.md b/manuals/1.0/ja/05-metamorphosis-patterns.md index 543afbc..2a256ba 100644 --- a/manuals/1.0/ja/05-metamorphosis-patterns.md +++ b/manuals/1.0/ja/05-metamorphosis-patterns.md @@ -1,40 +1,46 @@ --- layout: docs-ja -title: "5. 変容パターン" +title: "5. メタモルフォーシス" category: Manual -permalink: /manuals/1.0/ja/05-metamorphosis-patterns.html +permalink: /manuals/1.0/ja/05-metamorphosis.html --- -# 変容パターン +# メタモルフォーシス -Beフレームワークは、単純な線形チェーンから複雑な分岐する運命まで、様々な変容パターンをサポートします。これらのパターンを理解することで、自然な変容フローを設計できます。 +> 「空間と時間は独立に定義できない」 +> +> —アルベルト・アインシュタイン『一般相対性理論の基礎』(1916年) -## 線形変容チェーン +## 時間とドメインは分割できない -最もシンプルなパターン:A → B → C → D +アインシュタインが時間と空間の不可分性を発見したように、Beフレームワークでは時間とドメインは分割できない一つの実体です。承認プロセスには承認の時間が、決済には決済の時間があり、それぞれのドメインロジックが持つ固有の時間軸に沿って変容が自然に現れます。 + +## 不可逆的時間の流れ + +オブジェクトの変容は時間の矢に沿った一方向の流れです。過去に戻ることも、同じ瞬間に留まることもできません: ```php -// 入力 +// 時間 T0: 入力の誕生 #[Be(EmailValidation::class)] final class EmailInput { /* ... */ } -// 第一変容 +// 時間 T1: 第一変容(T0は既に過去) #[Be(UserCreation::class)] final class EmailValidation { /* ... */ } -// 第二変容 +// 時間 T2: 第二変容(T1は記憶となる) #[Be(WelcomeMessage::class)] final class UserCreation { /* ... */ } -// 最終結果 +// 時間 T3: 最終存在(すべての過去を内包) final class WelcomeMessage { /* ... */ } ``` -各段階は自然に次へと導かれ、川が海に流れるようです。 +各瞬間は二度と戻らず、新しい存在は前の形態をその内部に記憶として保持します。川が流れるように、時間は一方向にのみ流れます。 -## 分岐する運命 +## 運命の自己決定 -オブジェクトはその性質に基づいて複数の可能な未来を持つことができます: +現実の生物と同様に、オブジェクトは内在的な性質と外部環境の相互作用によって、自身の運命を決定します。これは予め決められたルートを辿るのではなく、その瞬間の状況に応じた自然な変容です: ```php #[Be([ApprovedApplication::class, RejectedApplication::class])] @@ -43,11 +49,12 @@ final class ApplicationReview public readonly ApprovedApplication|RejectedApplication $being; public function __construct( - #[Input] array $documents, // 内在的 - #[Inject] ReviewService $reviewer // 超越的 + #[Input] array $documents, // 内在的性質 + #[Inject] ReviewService $reviewer // 外部環境 ) { $result = $reviewer->evaluate($documents); + // 運命は今この瞬間に決まる $this->being = $result->isApproved() ? new ApprovedApplication($documents, $result->getScore()) : new RejectedApplication($result->getReasons()); @@ -55,106 +62,136 @@ final class ApplicationReview } ``` -オブジェクトは**型駆動変容**を通して自身の運命を決定します。 -## フォーク・ジョインパターン +## ネストした変容 -単一の入力が並列変容に分岐し、後に収束します: +複雑なオブジェクトは独自の変容チェーンを含むことができます: ```php -#[Be(PersonalizedRecommendation::class)] -final class UserAnalysis +final class OrderProcessing { - public readonly PersonalizedRecommendation $being; + public readonly PaymentResult $payment; + public readonly ShippingResult $shipping; public function __construct( - #[Input] string $userId, // 内在的 - #[Inject] BehaviorAnalyzer $behavior, // 超越的 - #[Inject] PreferenceAnalyzer $preference, // 超越的 - #[Inject] SocialAnalyzer $social // 超越的 + #[Input] Order $order, // 内在的 + #[Inject] Becoming $becoming // 超越的 ) { - // 並列分析 - $behaviorScore = $behavior->analyze($userId); - $preferenceScore = $preference->analyze($userId); - $socialScore = $social->analyze($userId); - - // 収束 - $this->being = new PersonalizedRecommendation( - $behaviorScore, - $preferenceScore, - $socialScore - ); + // ネストした変容 + $this->payment = $becoming(new PaymentInput($order->getPayment())); + $this->shipping = $becoming(new ShippingInput($order->getAddress())); } } ``` -## 条件付き変容 +## 自己組織化パイプライン + +これらのパターンの美しさは、それらが**自己組織化**であることです。Unixパイプが単純なコマンドを組み合わせて強力なシステムを作るように、Beフレームワークは型付きオブジェクトを組み合わせて自然な変容の流れを作ります。 + +### Unixパイプとの比較 + +```bash +# Unix: テキストが流れる外部制御のパイプライン +cat access.log | grep "404" | awk '{print $7}' | sort | uniq -c +``` + +```php +// Be Framework: リッチなオブジェクトが流れる内在的制御のパイプライン +$finalObject = $becoming(new ApplicationInput($documents)); +// オブジェクト自身が次の変容先を知っている +``` + +重要な進化: +- **Unix**: 外部のshellがパイプを制御 +- **Be Framework**: オブジェクト自身が`#[Be()]`で運命を宣言 + +### 自己組織化の実現 + +```php +// コントローラーもオーケストレーターもなし—ただ自然な流れ +$finalObject = $becoming(new ApplicationInput($documents)); + +// オブジェクトはあるべき姿になりました +match (true) { + $finalObject->being instanceof ApprovedApplication => $this->sendApprovalEmail($finalObject->being), + $finalObject->being instanceof RejectedApplication => $this->sendRejectionEmail($finalObject->being), +}; +``` + +この自己組織化により: +- 外部オーケストレーションが不要 +- 型安全性が保たれる +- 依存性注入による能力の提供 +- テスト可能な独立したコンポーネント + +## 実装上の選択指針 + +### いつ線形変容を選ぶか -時として変容はランタイム条件に依存します: +シーケンシャルな処理で、各段階が次に必要なデータを準備する場合: ```php -#[Be([PremiumFeatures::class, BasicFeatures::class])] -final class FeatureActivation +ユーザー登録 → メール検証 → アカウント有効化 → ウェルカム通知 +``` + +各段階での失敗は全体を停止させる必要がある場合に適しています。 + +### いつ条件分岐を選ぶか + +同じ入力から性質や権限によって異なる結果に分岐する場合: + +```php +// 実装例:支払い能力による機能差 +#[Be([FullAccess::class, LimitedAccess::class, ReadOnlyAccess::class])] +final class AccessDetermination { - public readonly PremiumFeatures|BasicFeatures $being; + public readonly FullAccess|LimitedAccess|ReadOnlyAccess $being; public function __construct( - #[Input] User $user, // 内在的 - #[Inject] SubscriptionService $service // 超越的 + #[Input] User $user, + #[Inject] PaymentStatus $payment ) { - $subscription = $service->getSubscription($user); - - $this->being = $subscription->isPremium() - ? new PremiumFeatures($user, $subscription) - : new BasicFeatures($user); + $this->being = match($payment->getStatus()) { + 'premium' => new FullAccess($user, $payment->getFeatures()), + 'basic' => new LimitedAccess($user, $payment->getLimits()), + default => new ReadOnlyAccess($user) + }; } } ``` -## ネストした変容 +### いつネストした変容を選ぶか -複雑なオブジェクトは独自の変容チェーンを含むことができます: +複数の独立した処理を並行して実行し、それぞれの結果を集約する場合: ```php -final class OrderProcessing +final class OrderCompletion { - public readonly PaymentResult $payment; - public readonly ShippingResult $shipping; - public function __construct( - #[Input] Order $order, // 内在的 - #[Inject] Becoming $becoming // 超越的 + #[Input] OrderData $order, + #[Inject] Becoming $becoming ) { - // ネストした変容 - $this->payment = $becoming(new PaymentInput($order->getPayment())); - $this->shipping = $becoming(new ShippingInput($order->getAddress())); + // 独立した処理を並行実行 + $this->inventory = $becoming(new InventoryCheck($order->items)); + $this->payment = $becoming(new PaymentProcess($order->payment)); + $this->shipping = $becoming(new ShippingArrange($order->address)); } } ``` -## 自己組織化パイプライン +## 設計原則 -これらのパターンの美しさは、それらが**自己組織化**であることです。オブジェクトは自身の運命を宣言し、フレームワークは外部のオーケストレーションなしに自然に変容パスに従います。 +変容パターンの選択は、ドメインロジックの自然な流れに従ってください: -```php -// コントローラーもオーケストレーターもなし—ただ自然な流れ -$finalObject = $becoming(new ApplicationInput($documents)); +- **強制しない**: 人工的なパターンに無理やり当てはめない +- **シンプルに**: 最も単純で理解しやすい形を選ぶ +- **テスト可能**: 各変容段階が独立してテストできる +- **型安全**: `#[Be()]` によって次の型が保証される -// オブジェクトはあるべき姿になりました -match (true) { - $finalObject->being instanceof ApprovedApplication => $this->sendApprovalEmail($finalObject->being), - $finalObject->being instanceof RejectedApplication => $this->sendRejectionEmail($finalObject->being), -}; -``` +オブジェクトは自らが自らの変容を規定します。 -## パターンの選択 +ヘラクレイトスは『川が流れている』のではなく『流れているのが川だ』と言いました。存在は変化とは切り離せないと考えたのです。Be Frameworkも同じように本質を捉えるためにはドメインと時間は切り離せないものと考えました。 +ドメインは時間的存在です。その時その時の可能性と存在があります。入力クラス、存在クラス、最終オブジェクトが時間の流れに沿って自然に変容していく様を捉えることが、Beフレームワークの核心です。 -ドメインの自然な流れに基づいてパターンを選択してください: -- **線形**: 順次プロセス(検証 → 処理 → 完了) -- **分岐**: 決定ポイント(承認/拒否、成功/失敗) -- **フォーク・ジョイン**: 収束する並列分析 -- **条件付き**: 機能フラグ、権限、サブスクリプション -- **ネストした**: サブプロセスを持つ複雑な操作 -重要なのは、変容をドメインロジックから自然に生まれさせることであり、人工的なパターンに強制することではありません。 \ No newline at end of file diff --git a/manuals/1.0/ja/06-semantic-variables.md b/manuals/1.0/ja/06-semantic-variables.md index 8a337c8..cf32eab 100644 --- a/manuals/1.0/ja/06-semantic-variables.md +++ b/manuals/1.0/ja/06-semantic-variables.md @@ -7,35 +7,49 @@ permalink: /manuals/1.0/ja/06-semantic-variables.html # 意味変数 -> 「存在すべきものは有効でなければなりません。存在できないものは決して生まれることはありません。」 +> 「存在するものは必然的に存在し、存在しないものは必然的に存在しない」 +> +> —スピノザ『エチカ』第1部定理29(1677年) -意味変数はBeフレームワークの最も深い原理を体現します:**意味のある存在のみが存在できる**。 +データの妥当性はどこで保証されるべきでしょうか?コントローラー?モデル?バリデーター? -## 問題 +Be Frameworkの答えは明確です:**名前そのものが制約を持つべき**と考えます。 +`$email`は単なる文字列ではなく、**有効なメールアドレス**であるべきです。`$age`にはマイナスの値は存在できません。 -従来の型は無意味なものから守ります: +意味変数は、情報の識別子であり、意味を表し、制約を持つ**完全な情報モデル**です。 + +## 問題:分散した不完全性 + +従来のアプローチでは、意味の定義が散在しています: ```php -function createUser(string $name, string $email, int $age) { - if (empty($name)) throw new Exception(); - if (!filter_var($email, FILTER_VALIDATE_EMAIL)) throw new Exception(); - // ... 無限の防御的プログラミング -} +// コントローラー/model/validator... +if (empty($name)) throw new Exception("error.name.empty"); +if (!filter_var($email, FILTER_VALIDATE_EMAIL)) throw new Exception("error.email.invalid"); + +// messages/ja.yml +error.name.empty: "名前を入力してください" +error.email.invalid: "有効なメールアドレスを入力してください" + +// README.md +// "名前は1-100文字で空白のみは不可..." ``` -## 解決法 +以下の問題が発生します: +- **バリデーション**:コントローラーに散在 +- **エラーメッセージ**:別ファイルで管理 +- **制約ルール**:複数の場所に重複 +- **意味定義**:ドキュメントにのみ存在 -意味変数は「これは有効ですか?」から「これは存在できますか?」へと根本的な問いを変えます。 +システムが扱う意味を集中して見ることのできる場所がありません。 -```php -function createUser(PersonName $name, EmailAddress $email, Age $age) { - // ここに到達すれば、存在は既に保証されています -} -``` +## 解決法:意味的完全性 + +Be Frameworkは、分散した定義を**完全な情報モデル**として統合します。コンストラクタの引数やクラスのプロパティには、登録された**意味変数**のみを使用できます。 ## 存在の定義 -すべての意味変数はそのドメインで何が存在できるかを定義します: +意味変数は専用フォルダにクラスとして定義されます: ```php final class Name @@ -50,25 +64,45 @@ final class Name } ``` -複数の検証コンテキストが自然に存在します: +## 検証コンテキスト + +異なるビジネスコンテキストには異なるルールが適用されることがあります。意味変数は複数の検証コンテキストを自然にサポートします: ```php final class ProductCode { #[Validate] - public function validate(string $code): void { /* 標準ルール */ } + public function validate(string $code): void + { + // 標準的な商品コード検証(例:8桁の英数字) + if (!preg_match('/^[A-Z0-9]{8}$/', $code)) { + throw new InvalidProductCodeException(); + } + } #[Validate] - public function validateLegacy(#[Legacy] string $code): void { /* レガシールール */ } + public function validateLegacy(#[Legacy] string $code): void + { + // レガシーシステム用の緩い検証(例:6-10桁の英数字) + if (!preg_match('/^[A-Z0-9]{6,10}$/', $code)) { + throw new InvalidLegacyProductCodeException(); + } + } #[Validate] - public function validatePremium(#[Premium] string $code): void { /* プレミアムルール */ } + public function validatePremium(#[Premium] string $code): void + { + // プレミアム商品用の厳格な検証(例:特定のプレフィックス必須) + if (!preg_match('/^PREM[A-Z0-9]{4}$/', $code)) { + throw new InvalidPremiumProductCodeException(); + } + } } ``` -## 意味のある失敗 +## 失敗の意味 -存在が失敗したとき、意味は保持されなければなりません: +存在が失敗したとき、失敗の意味が保持されなければなりません: ```php #[Message([ @@ -78,18 +112,18 @@ final class ProductCode final class EmptyNameException extends DomainException {} ``` -フレームワークは投げる前に**すべての検証エラー**を収集し、何が存在できないかの完全な理解を作り出します。 +フレームワークは最初に投げられる例外だけでなく、**すべての検証エラー**を例外の集合として収集し、なぜ存在できないかの完全な理解を作り出します。 ## 自然な統合 -意味変数は存在コンストラクタで自動的に動作します: +意味変数はコンストラクタで自動的に動作します: ```php final readonly class UserProfile { public function __construct( #[Input] #[English] public string $name, // 英語名として自動検証 - #[Input] string $emailAddress, // メールとして自動検証 + #[Input] string $emailAddress, // メールアドレスとして自動検証 #[Inject] NameFormatter $formatter ) { // この時点で、すべての入力が有効であることが保証されています @@ -97,9 +131,11 @@ final readonly class UserProfile } ``` +変数名`$name`は`Name`意味変数クラスと、`$emailAddress`は`EmailAddress`意味変数クラスと自動的に関連付けられます。 + ## 階層的検証 -意味変数は互いに構築できます: +意味変数は他の意味変数を基盤として構築できます。これはビジネスルールの自然な階層構造を型システムで表現する強力な手法です。 ```php final class TeenAge @@ -107,13 +143,68 @@ final class TeenAge #[Validate] public function validate(#[Teen] int $age): void { - // 基本的なAge検証を継承し、ティーン固有のルールを追加 + // まず基本的なAge検証が実行される(#[Teen]により自動的に呼び出される) + // その後、ティーン固有のルールを追加 if ($age < 13) throw new TeenAgeTooYoungException(); if ($age > 19) throw new TeenAgeTooOldException(); } } ``` +この階層的アプローチにより、豊かな意味の階層が構築されます: + +- `Email` → `CorporateEmail`(企業ドメイン必須)→ `ExecutiveEmail`(役員レベルの制約) +- `Price` → `DiscountPrice`(割引率制限)→ `MemberPrice`(会員特価ルール) +- `Password` → `AdminPassword`(管理者要件)→ `SystemPassword`(システム管理者の厳格要件) +- `Address` → `ShippingAddress`(配送可能地域)→ `InternationalAddress`(国際配送対応) + +各階層は前の層の制約を継承し、さらに固有の制約を追加します。基本的な`Email`検証が通らないものは、決して`ExecutiveEmail`として存在できません。これは単なる検証の組み合わせではなく、**概念の自然な精緻化**です。 + +## 関係性制約 + +意味変数は単独で存在するだけでなく、他の意味変数との関係性も制約として持てます。特筆すべきは**その記述の容易さ**です: + +```php +final readonly class UserRegistration +{ + public function __construct( + #[Input] string $email, + #[Input] string $confirmEmail, + #[Input] string $password, + #[Input] string $confirmPassword, + ) { + // 何も書く必要はありません! + // フレームワークが自動的に関係性を検証します + } +} +``` + +フレームワークは、対象のコンストラクタのシグネチャと**部分マッチ**する検証クラスを自動的に発見し、適用します。 + +```php +// これがあれば... +final class EmailConfirmation +{ + #[Validate] + public function validate(string $email, string $confirmEmail): void + { + if ($email !== $confirmEmail) { + throw new EmailMismatchException(); + } + } +} + +// $email, $confirmEmail を持つ任意のコンストラクタで自動適用される! +``` + +関係性制約の例: +- `$startDate` と `$endDate`:開始日は終了日より前でなければならない +- `$minPrice` と `$maxPrice`:最小価格は最大価格以下でなければならない +- `$email` と `$confirmEmail`:メールアドレスの確認一致が必要 +- `$currentPassword` と `$newPassword`:新しいパスワードは現在のものと異なる必要 + +開発者はビジネスルールを一度定義するだけで、該当するシグネチャを持つ全てのオブジェクトで自動的に適用されます。これらの制約は、オブジェクトが存在する**前提条件**として機能します。前提が満たされない限り、そのオブジェクトは存在することすらできません。 + ## エラーハンドリング 多言語エラーメッセージは自動的に適応します: @@ -127,13 +218,16 @@ try { } ``` -## 革命 +## 意味がもたらすもの + +**名前は、意味、制約の識別子です。**この単純な原理だけで、フレームワークといえるほどの豊かな世界が実現されます。 + +意味変数により、**不可能な状態が不可能になります**。無効なメールアドレスは`$email`として存在できず、負の年齢は`$age`として生まれることすらありません。在庫のない商品は`$orderId`として注文されることなく、東京23区外の住所は`$city`として配送先に指定されることもありません。 -意味変数は**不可能な状態を不可能にする**ことで防御的プログラミングを排除します。 +型システムそのものが**ドメイン言語**となり、各型があなたのビジネスドメインで何が存在可能かを語ります。 -型システムは**ドメイン言語**になります—各型があなたのビジネスドメインで何が存在できるかの意味を運びます。 +関数シグネチャを見れば、それが仕様書になります: -関数シグネチャは**ドキュメント**になります: ```php function processOrder(ProductCode $product, PaymentAmount $amount, CustomerAge $age) { @@ -141,8 +235,14 @@ function processOrder(ProductCode $product, PaymentAmount $amount, CustomerAge $ } ``` +この関数は有効な商品コード、正の金額、有効な年齢のみを受け入れます。ドキュメントを読む必要はありません—型が全てを物語っています。 + +防御的プログラミングは不要になります。引数の検証、null チェック、範囲確認、在庫確認、地理的制約—これらはすべて意味変数が保証します。コードは本来の目的であるビジネスロジックの実装に集中できるのです。 + +単なる命名規約から始まった概念が、階層的検証、関係性制約、外部リソース統合まで発展し、完全なドメイン保証システムを構築します。**名前に込められた意味が、システム全体の整合性を支えるのです。** + --- **次へ**: オブジェクトが自身の性質を発見する[型駆動変容](07-type-driven-metamorphosis.html)について学びましょう。 -*「意味変数はデータを検証するだけでなく、意味のある存在のみが存在できることを保証します。」* \ No newline at end of file +*「意味変数はデータを検証するだけでなく、意味のある存在のみが存在できることを保証します。」* diff --git a/manuals/1.0/ja/12-from-doing-to-being-final.md b/manuals/1.0/ja/12-from-doing-to-being-final.md index a915665..958f410 100644 --- a/manuals/1.0/ja/12-from-doing-to-being-final.md +++ b/manuals/1.0/ja/12-from-doing-to-being-final.md @@ -7,7 +7,11 @@ permalink: /manuals/1.0/ja/12-from-doing-to-being-final.html # Doingから Beingへ: より大きな視点 -> *「真の発見の航海は、新しい風景を求めることではなく、新しい目を持つことにある。」* — マルセル・プルースト +> 「存在するものは全て生成の途上にある」 +> +> —ヘラクレイトス『断片』(紀元前500年頃) + +## あなたが発見したもの あなたは入力クラスを書き、存在クラスを作成し、オブジェクトが変異するのではなく変容するのを見てきました。 diff --git a/manuals/1.0/ja/index.md b/manuals/1.0/ja/index.md index 5f231ef..4571b2c 100644 --- a/manuals/1.0/ja/index.md +++ b/manuals/1.0/ja/index.md @@ -20,7 +20,7 @@ permalink: /manuals/1.0/ja/ ## [4. 最終オブジェクト](04-final-objects.html) 変容の目的地 - 完全に変容した存在 -## [5. 変容パターン](05-metamorphosis-patterns.html) +## [5. 変容パターン](05-metamorphosis.html) 単純な連鎖、分岐する運命、複雑な変容 ## [6. 意味変数](06-semantic-variables.html)