Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions LEVIT_REVIEW.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Levit Framework Review

**Reviewer Persona:** Senior Flutter Developer (Riverpod/Functional Programming advocate).
**Date:** 2026-01-29

## Executive Summary

Levit is a fascinating "anti-Riverpod" in many ways. While Riverpod chases compile-time safety, immutability, and explicit graphs, Levit doubles down on **runtime performance**, **mutability**, and **implicit "magic" (Observation by Access)**.

It feels like a modern, highly optimized re-imagining of GetX/MobX, stripping away the bloat and focusing purely on speed and clean syntax.

**Verdict:** It is dangerous but incredibly fast. It trades safety for velocity and raw performance.

---

## 1. DX (Developer Experience)

### The Good
* **Zero Code Gen:** This is the killer feature. Riverpod's `riverpod_generator` is great, but the build runner lag is real. Levit gives you a similar "concise" feel (`0.lx`) without the build step.
* **Syntax:** `.lx` extensions and `LWatch` are clean. Writing `count.value++` is undeniably faster than `ref.read(provider.notifier).state++`.
* **Async Pattern Matching:** The `LxStatus` sealed class usage in Dart 3 is beautiful. It feels even more idiomatic than `AsyncValue.when` because it uses standard switch expressions.
* **LWatch:** The "hooks-like" behavior without the "rules of hooks" is a massive DX win. You just use the value, and the widget rebuilds. No `ref.watch` dance.

### The Bad
* **Runtime Dependency Injection:** This is my biggest gripe as a Riverpod user. `Ls.find<MyService>()` throws at *runtime*. Riverpod providers are compile-time safe constants. In a large team, Levit requires strict discipline to avoid "Service Not Found" crashes.
* **Hidden Dependencies:** In Riverpod, looking at a Provider's signature tells you what it needs (via `ref`). In Levit (and GetX), dependencies are pulled from the ether (`Ls.find`). This makes unit testing harder because you have to mock the global scope, rather than just passing arguments.
* **Mutable State:** Mutability is the root of many bugs. Levit embraces it. While it offers "transactional" batching, it still lacks the time-travel debugging and strict state history that immutable state (Freezed/Riverpod) offers by default.

### The Verdict on DX
**8/10.** Faster to write than Riverpod, but "looser" and less safe. It feels like driving a sports car without a seatbelt.

---

## 2. Performance

### Analysis
I dug into `levit_reactive` and the implementation is **impressive**.
* **Fast Paths:** The code is riddled with "Fast Path" checks. If you aren't using middleware, it skips entire blocks of logic.
* **Deduplication:** The "diamond problem" handling in the graph propagation is mathematically correct and optimized.
* **Batching:** The `Lx.batch` implementation is solid.

### Benchmarks
The provided benchmarks claim Levit is ~15x faster than Riverpod in rapid mutations. This checks out conceptually:
* Riverpod: Immutable Copy -> Notify -> Check Families -> Rebuild.
* Levit: Mutate value -> Mark Dirty -> (Batch) -> Notify.
Direct mutation will always beat immutable copy chains in micro-benchmarks.

### The Verdict on Performance
**10/10.** This is clearly designed for 120fps. It might be overkill for a Todo app, but for a high-frequency trading app or a complex dashboard, this engine is a beast.

---

## 3. Will I try it in a new project?

**Yes, but with conditions.**

* **For a personal side project or a rapid prototype:** **Absolutely.** The speed of development without code-gen is intoxicating.
* **For a high-performance visualizer/game UI:** **Yes.** The granular rebuilds (`LWatch`) and raw mutation speed make it perfect for this.
* **For a large-scale Enterprise Banking App:** **No.** I would stick to Riverpod. The compile-time safety, explicit dependency graph, and immutability are non-negotiable when 20 developers are touching the codebase. I need the compiler to yell at them, not a runtime exception in production.

---

## 4. Will I be interested in contributing to it?

**Yes.**

The codebase is clean, modular, and respectful of computer science principles (Topological sort, Graph theory). It's not "hacky" like some other state management solutions in the ecosystem.

**Areas of interest:**
1. **DevTools:** Riverpod has world-class DevTools. Levit needs a visualization of the dependency graph to mitigate the "hidden dependency" issue.
2. **Testing Utilities:** `levit_test` package to make mocking scopes easier would be a huge value add.
3. **Strict Mode:** A compile-time analyzer plugin (custom_lint) to warn about missing `LWatch` or invalid `Ls.find` calls would bridge the safety gap.

---

## Final Thoughts

Levit is the "Un-Riverpod". It is the chaotic good to Riverpod's lawful good. It proves that you can have extremely ergonomic, high-performance state management in Dart without code generation, provided you accept the trade-offs of mutability and runtime scoping.