From 544052f12aa56928652a20020d524b1badcc82da Mon Sep 17 00:00:00 2001 From: NickSeagullBot Date: Mon, 21 Sep 2026 18:56:56 +0100 Subject: [PATCH] Explain NeoHaskell through commands, events, and views --- docs/docs-intro/index.mdx | 64 --- docusaurus.config.js | 19 +- drafts/new-project.mdx | 2 +- src/pages/index.module.css | 471 ++++++++++++++++++++- src/pages/index.tsx | 846 ++++++++++++++++++------------------- 5 files changed, 869 insertions(+), 533 deletions(-) delete mode 100644 docs/docs-intro/index.mdx diff --git a/docs/docs-intro/index.mdx b/docs/docs-intro/index.mdx deleted file mode 100644 index ad2539e..0000000 --- a/docs/docs-intro/index.mdx +++ /dev/null @@ -1,64 +0,0 @@ ---- -sidebar_position: 1 ---- - -import Badge from "@site/src/components/Badge"; - -# Support NeoHaskell - -## Building the Future, One Event at a Time - -Hi, this is Nick, the creator of NeoHaskell. - -NeoHaskell exists because we believe software development doesn't have to be painful. That adding your 100th feature should be as easy as your first. That teams should stay small and happy even as systems grow massive. - -Right now, I'm working on NeoHaskell full-time, living off my savings to make this vision real. Every contribution—whether financial, technical, or spreading the word—directly impacts how fast we can deliver a world where technical debt becomes obsolete. - -## Ways to Support - -### Financial Support - -Choose the platform that works best for you: - -- **[GitHub Sponsors](https://github.com/sponsors/NickSeagull)** - Direct support through GitHub -- **[OpenCollective](https://opencollective.com/neohaskell)** - Transparent collective funding -- **[Ko-fi](https://ko-fi.com/nickseagull)** - One-time or monthly contributions - -Every dollar extends the runway. Every month of runway means more features, better documentation, and a stronger foundation for the companies that will build their future on NeoHaskell. - -### Hire Me - -The best way to support NeoHaskell? **Use it in production.** - -I'm available for consulting to help your team: -- Architect event-driven systems that actually work -- Transition from CRUD to event sourcing without the pain -- Build your next product with NeoHaskell -- Train your team on event modeling and domain-driven design - -When you hire me, you're not just getting consulting—you're funding NeoHaskell's development while solving your own technical challenges. Every production use case makes NeoHaskell stronger. - -**[Contact me for consulting](mailto:consulting@nickseagull.dev)** - -### Other Ways to Help - -**Use It**: Build something with NeoHaskell. Your feedback shapes what we build next. - -**Share It**: Tell others who are suffering from exponential complexity. Write about your experience. Show what you've built. - -**Contribute**: Code, documentation, examples—every contribution matters. We're building this together. - -**Star It**: Give us a star on [GitHub](https://github.com/neohaskell/neohaskell). It helps others discover the project. - -## Why This Matters - -Your support isn't just funding a programming language. You're investing in a future where: - -- Startups don't fail from technical bankruptcy -- Developers don't burn out from complexity -- Companies scale without suffering -- Software development becomes humane again - -Together, we're proving that software can get better, not worse, over time. - -**Thank you for believing in this vision.** diff --git a/docusaurus.config.js b/docusaurus.config.js index 26ae00b..8a16e0d 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -8,7 +8,8 @@ const lightCodeTheme = require("prism-react-renderer/themes/shadesOfPurple"); /** @type {import('@docusaurus/types').Config} */ const config = { title: "NeoHaskell", - tagline: "A Haskell dialect to think less and do more", + tagline: + "Model requests, decisions, events, and views so current state has an explainable history.", favicon: "img/favicon.ico", // Set the production url of your site here @@ -71,15 +72,7 @@ const config = { "classic", /** @type {import('@docusaurus/preset-classic').Options} */ ({ - docs: { - sidebarPath: require.resolve("./sidebars.js"), - // Please change this to your repo. - // Remove this to remove the "edit this page" links. - editUrl: - "https://github.com/neohaskell/neohaskell.github.io/tree/main/", - remarkPlugins: [math], - rehypePlugins: [katex], - }, + docs: false, blog: { path: "blog/nhep/nhep", exclude: ["README.md"], @@ -115,12 +108,6 @@ const config = { src: "img/logo.svg", }, items: [ - { - type: "docSidebar", - sidebarId: "tutorialSidebar", - position: "left", - label: "Support Us!", - }, { href: "https://github.com/neohaskell/", label: "GitHub", diff --git a/drafts/new-project.mdx b/drafts/new-project.mdx index f8abdf5..3ad3ebf 100644 --- a/drafts/new-project.mdx +++ b/drafts/new-project.mdx @@ -10,7 +10,7 @@ import Badge from "@site/src/components/Badge"; :::caution The documentation that you're reading is a design document where most of -the features you're reading are yet to be implemented. Check the [Note on the Docs](/docs/docs-intro) +the features described are yet to be implemented. ::: Trying stuff in the REPL is cool and all that, but if you want to build something diff --git a/src/pages/index.module.css b/src/pages/index.module.css index 9f71a5d..6a09234 100644 --- a/src/pages/index.module.css +++ b/src/pages/index.module.css @@ -1,23 +1,470 @@ -/** - * CSS files with the .module.css suffix will be treated as CSS modules - * and scoped locally. - */ +.hero { + margin: 0 auto; + max-width: 92rem; + padding: 6rem 2rem 2rem; + text-align: center; +} + +.hero h1 { + letter-spacing: -0.035em; + margin: 0 auto; + max-width: 16ch; +} + +.heroLead { + font-size: clamp(1.125rem, 2vw, 1.5rem); + line-height: 1.6; + margin: 2rem auto 0; + max-width: 68ch; +} -.heroBanner { - padding: 4rem 0; +.heroDiagram { + margin: 4rem auto 0; + max-width: 74rem; + text-align: left; +} + +.content { + margin: 0 auto; + max-width: 78rem; + padding: 0 2rem 6rem; +} + +.section { + margin: 8rem auto 0; +} + +.sectionText { + max-width: 72ch; +} + +.sectionText h2, +.closing h2 { + font-size: clamp(2rem, 4vw, 3.5rem); + letter-spacing: -0.03em; + line-height: 1.15; + margin: 0 0 1.5rem; +} + +.sectionText p, +.closing p { + font-size: clamp(1.05rem, 1.5vw, 1.3rem); + line-height: 1.7; + margin: 1.25rem 0 0; +} + +.diagram { + background: white; + border: 4px solid black; + box-shadow: 8px 8px 0 black; + margin: 3rem 0 0; + padding: clamp(1.25rem, 3vw, 2.5rem); +} + +.heroDiagram .diagram { + border: 0; + box-shadow: none; + margin: 0; + padding: 1rem 0; +} + +.caption { + border-top: 2px solid black; + display: block; + font-family: "Ubuntu", sans-serif; + font-size: 1rem; + line-height: 1.55; + margin-top: 2rem; + padding-top: 1rem; +} + +.flow { + align-items: stretch; + display: flex; + justify-content: center; +} + +.flowStep { + align-items: center; + border: 3px solid black; + display: flex; + flex: 1 1 0; + flex-direction: column; + justify-content: center; + min-height: 7.5rem; + padding: 1rem; text-align: center; +} + +.flowStep strong { + font-family: "Lexend Mega", sans-serif; + font-size: clamp(0.9rem, 1.4vw, 1.15rem); + line-height: 1.25; +} + +.flowStep span { + font-family: "Ubuntu", sans-serif; + line-height: 1.35; + margin-top: 0.45rem; +} + +.cyan { + background: #cffafe; +} + +.yellow { + background: #fef9c3; +} + +.violet { + background: #ede9fe; +} + +.flowConnector, +.transitionConnector { + align-self: center; + background: black; + flex: 0 0 2rem; + height: 4px; position: relative; - overflow: hidden; } -@media screen and (max-width: 996px) { - .heroBanner { - padding: 2rem; - } +.flowConnector::after, +.transitionConnector::after { + border-bottom: 8px solid transparent; + border-left: 11px solid black; + border-top: 8px solid transparent; + content: ""; + position: absolute; + right: -2px; + top: -6px; +} + +.comparisonGrid { + display: grid; + gap: 2rem; + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +.comparisonPanel h3 { + font-size: 1.15rem; + letter-spacing: -0.02em; + margin: 0 0 1.5rem; + text-transform: uppercase; +} + +.comparisonPanel > p { + font-size: 1rem; + line-height: 1.55; + margin: 1.5rem 0 0; +} + +.stateTransition { + align-items: center; + display: flex; +} + +.valueBlock { + border: 3px solid black; + display: flex; + flex: 1 1 0; + flex-direction: column; + min-width: 0; + padding: 1.25rem 0.75rem; + text-align: center; +} + +.valueBlock span { + font-family: "Ubuntu", sans-serif; +} + +.valueBlock strong { + font-family: "Lexend Mega", sans-serif; + font-size: clamp(1.8rem, 4vw, 3rem); + line-height: 1.1; + margin-top: 0.4rem; } -.buttons { +.timeline { + align-items: stretch; display: flex; + flex-direction: column; +} + +.timelineItem { + align-items: center; + border: 3px solid black; + display: flex; + justify-content: space-between; + min-height: 3.75rem; + padding: 0.85rem 1rem; +} + +.timelineItem strong, +.timelineItem span { + font-family: "Comic Mono", monospace; +} + +.timelineConnector { + align-self: center; + background: black; + height: 1rem; + width: 4px; +} + +.foundationMap { + margin: 0; +} + +.foundationRow { + align-items: center; + border-bottom: 2px solid black; + display: grid; + gap: 1.5rem; + grid-template-columns: minmax(12rem, 0.8fr) 2fr; + padding: 1rem 0; +} + +.foundationRow:first-child { + padding-top: 0; +} + +.foundationRow:last-child { + border-bottom: 0; + padding-bottom: 0; +} + +.foundationRow dt { align-items: center; + display: flex; + font-family: "Lexend Mega", sans-serif; + font-size: 1.05rem; + font-weight: 600; + gap: 0.8rem; +} + +.foundationRow dt span { + align-items: center; + background: #cffafe; + border: 2px solid black; + border-radius: 999px; + display: inline-flex; + flex: 0 0 2.25rem; + height: 2.25rem; justify-content: center; } + +.foundationRow dd { + font-family: "Ubuntu", sans-serif; + font-size: 1.1rem; + margin: 0; +} + +.costFigures { + display: grid; + gap: 2rem; + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +.costFigure h3 { + font-size: 1.15rem; + letter-spacing: -0.02em; + margin: 0 0 1.25rem; + text-transform: uppercase; +} + +.costFigure > p { + font-size: 1rem; + line-height: 1.55; + margin: 1rem 0 0; +} + +.costChart { + display: block; + height: auto; + overflow: visible; + width: 100%; +} + +.chartAxis { + fill: none; + stroke: black; + stroke-width: 3; +} + +.featureBlock { + fill: #cffafe; + stroke: black; + stroke-width: 2; +} + +.reworkBlock { + fill: #fecaca; + stroke: black; + stroke-width: 2; +} + +.blockLabel { + fill: black; + font-family: "Comic Mono", monospace; + font-size: 16px; + text-anchor: middle; +} + +.risingCurve { + fill: none; + stroke: #ef4444; + stroke-width: 4; +} + +.boundedCurve { + fill: none; + stroke: #0ea5e9; + stroke-width: 4; +} + +.redArrow { + fill: #ef4444; +} + +.blueArrow { + fill: #0ea5e9; +} + +.curveLabel, +.boundedLabel, +.sharedLabel, +.axisLabel { + fill: black; + font-family: "Comic Mono", monospace; + text-anchor: middle; +} + +.curveLabel, +.boundedLabel { + font-size: 14px; +} + +.axisLabel, +.sharedLabel { + font-size: 12px; +} + +.sharedContract { + fill: none; + stroke: #9723c9; + stroke-width: 4; +} + +.callout { + border-bottom: 3px solid black; + border-top: 3px solid black; + font-family: "Ubuntu", sans-serif; + font-size: clamp(1.2rem, 2vw, 1.6rem); + line-height: 1.6; + margin: 3.5rem 0 0; + max-width: 72ch; + padding: 1.5rem 0; +} + +.closing { + margin-bottom: 2rem; +} + +.closingContent { + padding: clamp(1rem, 3vw, 2rem); +} + +.closingContent p { + max-width: 62ch; +} + +.actions { + display: flex; + flex-wrap: wrap; + gap: 1rem; + margin-top: 2rem; +} + +.actions span { + font-family: "Lexend Mega", sans-serif; + font-size: 0.9rem; +} + +@media screen and (max-width: 760px) { + .hero { + padding: 4rem 1rem 1rem; + } + + .heroLead { + font-size: 1.1rem; + } + + .heroDiagram { + margin-top: 2.5rem; + } + + .content { + padding: 0 1rem 4rem; + } + + .section { + margin-top: 5rem; + } + + .flow { + align-items: stretch; + flex-direction: column; + } + + .flowConnector, + .transitionConnector { + flex-basis: auto; + height: 2rem; + width: 4px; + } + + .flowConnector::after, + .transitionConnector::after { + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 11px solid black; + bottom: -2px; + left: -6px; + right: auto; + top: auto; + } + + .comparisonGrid { + grid-template-columns: 1fr; + } + + .costFigures { + grid-template-columns: 1fr; + } + + .comparisonPanel + .comparisonPanel { + border-top: 3px solid black; + padding-top: 2rem; + } + + .stateTransition { + flex-direction: column; + } + + .valueBlock { + width: 100%; + } + + .foundationRow { + align-items: start; + gap: 0.75rem; + grid-template-columns: 1fr; + } + + .actions, + .actions a, + .actions button { + width: 100%; + } +} diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 727b691..cd65175 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,399 +1,431 @@ import React from "react"; -import clsx from "clsx"; import Link from "@docusaurus/Link"; import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import Layout from "@theme/Layout"; -import HomepageFeatures from "@site/src/components/HomepageFeatures"; -import CodeBlock from "@theme/CodeBlock"; -import styles from "./index.module.css"; -import Frame from "../components/Frame"; import Button from "../components/Button"; -import CodeFrame from "../components/CodeFrame"; -import Dialog from "../components/Dialog"; -import Modal from "../components/Modal"; -import Disclaimer from "../components/Disclaimer"; +import Frame from "../components/Frame"; +import styles from "./index.module.css"; -const dynC = (className: string, color: string) => `${className}-light${color}`; +const flowSteps = [ + { label: "Request", detail: "What should happen?", tone: "cyan" }, + { label: "Decision", detail: "Accept or refuse", tone: "yellow" }, + { label: "Accepted event", detail: "What happened", tone: "violet" }, + { label: "Useful view", detail: "What is needed next", tone: "cyan" }, +] as const; -function HomepageHeader() { - const { siteConfig } = useDocusaurusContext(); +function BehaviorFlow() { + return ( +
+
+ {flowSteps.map((step, index) => ( + +
+ {step.label} + {step.detail} +
+ {index < flowSteps.length - 1 ? ( +
+ ))} +
+
+ A request is checked against the rules before an event is accepted. + Views are derived from accepted history. +
+
+ ); +} + +function HistoryComparison() { return ( -
-
-
-
-

- Software Development Is Broken.{" "} - - We're Fixing It From The Language Up. - -

+
+
+
+

Current value only

+
+
+ Balance + €100 +
+
+

The new value replaces the old one. The reason is elsewhere.

+
+ +
+

Accepted history

+
+
+ AccountOpened + +€100 +
+
+

The current value is reconstructed from the recorded facts.

-
- -

- Every successful software company follows the same tragic arc: -

-

- - Day one: pure creativity, features ship in hours, - everyone understands everything. -

-

- - Year one: velocity slows, meetings multiply, "technical debt" - enters the vocabulary. -

-

- - Year three: the rewrite discussions begin. -

-

- - Year five: half your budget maintains what the other half tries to - replace. -

-

- This isn't incompetence. It's not bad management. It's the - inevitable result of building on foundations that turn human - thoughts into machine instructions through layers of mistranslation. -

-

The Broken Telephone Architecture

-

- Watch how a simple business need travels through your organization: -

-

- The CEO says: "When customers upgrade, we should celebrate with - them." -

-

- The CTO interprets: "Upon plan upgrade, trigger celebration - workflow." -

-

- The Product Manager writes: "Implement upgrade handler with - notification service integration." -

-

- The Developer codes:{" "} -

-              
-                UPDATE users SET plan = 'premium'; INSERT INTO notifications...
-              
-            
-

-

- Six months later, nobody remembers why that code exists. The - celebration feature breaks. The developer who wrote it left. The new - developer is afraid to touch it. The cycle of decay has begun. -

-

- This isn't a people problem. It's a technology problem. We're - forcing humans to speak machine when machines should speak human. -

-

Technology Shapes Thought

-

- The tools we use shape how we think. When your language forces you - to express everything as CREATE, READ, UPDATE, DELETE, you start - seeing the world as records to manipulate rather than events that - happen. You stop thinking "customer upgraded" and start thinking - "update customer record." -

-

- This subtle shift is poison. It disconnects your code from your - business. It makes simple things complex. It makes change dangerous. - It makes your software brittle where it should be antifragile. -

-

- The oldest ideas survive because everything unnecessary has been - stripped away. Double-entry bookkeeping has worked for 700 years. - Event ledgers are how humans naturally think about change. Banks - don't UPDATE your balance; they record deposits and withdrawals. - History doesn't UPDATE the past; it records what happened. -

-

- Why did we abandon this natural model for CRUD? -

-

- Because storage was expensive. Because computers were slow. Because - we optimized for machines instead of humans. -

-

- Those constraints are gone. It's time for software development to - become human again. -

-

- Enter NeoHaskell: Where Business Events Become Code -

-

- NeoHaskell isn't just another programming language. It's a - fundamental rethinking of how human intention becomes running - software. -

-

- When your business team says "customer plan upgraded" that's - literally how you write it: -

+
+ Illustrative account history. The application must explicitly model the + facts, reasons, authority, and evidence it needs to retain. +
+
+ ); +} + +function FoundationMap() { + const foundations = [ + ["Command / request", "Represents an intended change"], + ["Entity", "Reconstructs current state from prior events"], + ["Decision", "Accepts or refuses the request"], + ["Event", "Records an accepted domain fact"], + ["Query", "Builds a view for a particular question"], + ]; + + return ( +
+
+ {foundations.map(([term, description], index) => ( +
+
+ {index + 1} + {term} +
+
{description}
+
+ ))} +
+
+ These are explicit structures in the program, and the Neo IDE can show + their relationships. +
+
+ ); +} + +function GrowthComparison() { + const features = ["A", "B", "C", "D", "E", "F", "G"]; + const reworkLayers = [0, 0, 0, 1, 1, 2, 3]; + + return ( +
+
+
+

Implicit dependencies

+ + Implicit dependencies increase rework + + + + + + + + + widening change surface + + {features.map((feature, index) => { + const x = 56 + index * 51; + const layers = reworkLayers[index]; + return ( + + {Array.from({ length: layers }).map((_, layer) => ( + + + + R + + + ))} + + + {feature} + + + ); + })} + + behaviors in the system + + + relative change effort + +

- - {`data CustomerPlanUpgraded = CustomerPlanUpgraded - { customer :: CustomerId, - fromPlan :: Plan, - toPlan :: Plan, - upgradeDate :: DateTime - } -`} - -

-

- No translation. No abstraction. No impedance mismatch. Your business - logic reads like a business conversation. -

-

What Makes NeoHaskell Different

-

- Event Sourcing Is The Language, Not A Library -

-

- Other languages make you fight for event sourcing. You need - frameworks, libraries, careful discipline. One mistake and you're - back in CRUD hell. -

-

- In NeoHaskell, event sourcing isn't something you add. It's - something you'd have to work to avoid. Every state change is an - event. Every event is immutable. Every system is automatically - auditable, replayable, debuggable.{" "} - - The compiler doesn't let you store something in the database where - you're not supposed to. - -

-

- Mathematical Guarantees, Human Expression -

-

- From Haskell, we inherit something profound: if it compiles, it - works. This isn't marketing, it's math. Entire categories of errors - become impossible. Race conditions, null pointer exceptions, type - mismatches, all gone. -

-

- But unlike Haskell, we've optimized for developer happiness, and we - chase your success at all costs. The standard library feels - familiar. There are no millions of operators to memorize. The - concepts map to how you already think. The error messages actually - help. -

-

- Linear Complexity In A Exponential World -

-

- In traditional systems, feature #100 might take 10x longer than - feature #10. Dependencies tangle. Side effects multiply. Fear creeps - in. -

-

- In NeoHaskell, feature #1000 takes the same effort as feature #1. - New events don't break old ones. New handlers don't destabilize - existing ones. Your system grows by addition, never by modification. -

-

Where We Are Today

-

- NeoHaskell is not complete. We're building this in public, with real - production users, solving real problems. -

-

What's Already Working:

-

- - A Beautiful Standard Library: Carefully crafted APIs that make - simple things trivial and complex things possible. Every function - documented, every pattern thoughtful. -

-

- - Production-Ready Concurrency: Channels for message passing. Locks - when you need them. Thread-safe variables that actually work. These - are the primitives NeoHaskell is built on top of, ensuring your - system is not only correct, but also blazing fast. -

-

- - In-Memory Event Store: Perfect for development and testing. Your - events are safe, queryable, replayable. -

-

- - PostgreSQL Event Store (In Progress): Because production needs - production databases. Built on boring, bulletproof technology. - Coming together beautifully. -

-

What's Coming:

-

- We're building toward a complete platform that generates everything - you need from your event model. Automatic API generation. - Infrastructure that scales. Deployment that just works. The ease of - low-code with the power of real programming. -

-

- Imagine describing your business events and getting: -

-

- - A GraphQL (or Swagger, or gRPC, or...!) API that updates in - real-time -

-

- - A scalable infrastructure that handles millions of events + Hidden shared assumptions widen the change surface. Red blocks + represent rework in earlier behavior.

-

- - Complete observability—know everything that ever happened -

-

- - Time travel debugging—replay any scenario instantly -

-

- - The ability to fork a stream of events from your production - environment to your development environment for debugging -

-

- - Perfect audit trails—compliance becomes trivial -

-

- This isn't fantasy. We've already done parts of this in the past. - With every release, more becomes automatic. -

-

- The Philosophy: Remove Everything That Gets In The Way -

-

- We're not adding features for their own sake. Every decision follows - a simple principle: does this remove friction between human - intention and running software? -

-

- - Configuration files? Removed. Your code should express intent - clearly enough. -

-

- - Dependency hell? Removed. One tool, one purpose, one way that - works. -

-

- - DevOps complexity? Removed. From code to cloud in one command. -

-

- - The fear of change? Removed. If it compiles, it works. -

-

Who This Is For

-

- You're a startup founder who knows that initial technical decisions - determine your company's fate. You can't afford to be rewriting in - two years when you should be scaling. -

-

- You're an enterprise architect tired of managing complexity instead - of creating value. You want systems that grow gracefully, not ones - that calcify. -

-

- You're a developer who came to this field to build, not to debug. - You want to write business logic, not boilerplate. -

-

- You're a product manager exhausted by "technical limitations." You - want your ideas to become features, not tickets that languish in - backlogs. -

-

- You're a CEO who suspects you're spending too much on engineering - for too little output. You're right. And it's not your team's fault. -

-

The Invitation

-

- We're not asking you to trust us blindly. We're building this with - real companies, solving real problems, in production, today. -

-

- If you're tired of: -

-

- - Features that get exponentially harder to implement -

-

- - Teams that grow faster than output -

-

- - Systems that everyone fears to change +

+ +
+

Visible slices and contracts

+ + Visible slices keep changes local + + + + + + + + + Event Modeled + + {features.map((feature, index) => { + const x = 56 + index * 51; + return ( + + + + {feature} + + + ); + })} + + + shared contracts remain visible + + + behaviors in the system + + + relative change effort + + +

+ Each slice gives the team a boundary to implement and test. + Shared contracts remain explicit coordination points.

-

- - The constant specter of "the rewrite" +

+
+
+ Event Modeling gives each behavior a visible blueprint. NeoHaskell + turns that blueprint into typed Commands, Decisions, Events, Entities, + and Queries. +
+
+ ); +} + +function HomepageHeader() { + return ( +
+

+ Know what your software does.{" "} + Explain why it did it. +

+

+ NeoHaskell helps teams model a change as a request, a decision, a + recorded event, and a view. Those concepts stay visible from design + through implementation, so the current state has a history and the next + change has a place to start. +

+
+ + + +
+
+ ); +} + +function HomepageBody() { + return ( +
+
+
+

A Current Value Is A Summary

+

+ A balance of €70 tells you where an account ended, but not how it + got there. In an application backed by a persistent event store, + accepted events can provide the history from which current state is + reconstructed.

-

- Join us. +

+ +

+ History answers only the questions the application was designed to + preserve. Reasons, evidence, attribution, privacy, and retention are + still explicit design choices. +

+
+ +
+
+

One Model, Carried Through The Toolchain

+

+ Event sourcing and domain modeling can be implemented in many + languages. NeoHaskell is designed to make their core concepts part + of the application model rather than conventions every team must + recreate.

-

- Software development should be joyful, not painful. Systems should - become more valuable over time, not more dangerous. Technology - should amplify human creativity, not constrain it. Your 1000th day - of development should feel like your first. +

+ +

+ Types can make some invalid combinations unrepresentable. The + compiler catches type mismatches and can require exhaustive handling + where code uses closed alternatives. Tests exercise the policies and + boundary cases they cover. None of these checks can decide whether a + business rule is fair, complete, or right for the real world. +

+
+ +
+
+

Add Behavior In Visible Slices

+

+ A behavior slice follows one useful change from request through + decision and accepted event to the view needed next. Stable + boundaries keep change local instead of forcing contributors to + reinterpret the whole system.

-

Start Today

-

- NeoHaskell is ready for pioneers. If you're building something new, - if you're ready to escape the rewrite trap, if you believe software - can be better: We're waiting for you. +

+ +
+ +
+
+

Correct Mistakes Without Erasing Them

+

+ If a withdrawal is recorded twice, changing the balance repairs the + number but not the history. A domain can instead define a request + to reverse the duplicate, a decision that checks whether it is + allowed, and a compensating event that records the correction.

-

- The revolution isn't coming. It's being typed right now, one event - at a time, by developers who refuse to accept that suffering is the - price of scale. +

+ Human- and agent-initiated changes can be routed through the same + request and authorization path. Automation can assist + implementation or submit a request; the team still owns the rule, + the authority to apply it, and the evidence that must be retained.

-

- - Welcome to NeoHaskell. Welcome to software development as it - should be. - +

+
+ +
+
+

Use It Where History Earns Its Cost

+

+ This approach is strongest in domains with meaningful lifecycles: + orders, accounts, approvals, grants, projects, memberships, and + other systems where disputes, audit, or accountability matter.

-

- - The old world optimizes for machines. We're optimizing for humans. - Join us. - +

+ Simple content sites, disposable prototypes, static lookup data, + and workflows with no meaningful history may be better served by + conventional tools. Event sourcing introduces modeling and + operational costs; those costs should solve a real problem.

- -
- -
-
- - - - - -
-
-
- ); -} + -function VideoPlayer({ enabled }: { enabled?: boolean }) { - return enabled ? ( -
-
-