Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
IT Security NachrichtenKI-Agenten hebeln klassisches IT-Asset-Management aus(24.09.2026 um 07:14 Uhr)
IT Security NachrichtenMicrosoft erneuert Surface Pro und Laptop mit Snapdragon X2 Plus(24.09.2026 um 07:42 Uhr)
IT Security DownloadsGitHub Release: cline/cline vsdk/shared/v0.0.86 (24.09.2026)(24.09.2026 um 07:43 Uhr)
IT Security DownloadsGitHub Release: cline/cline vsdk/llms/v0.0.86 (24.09.2026)(24.09.2026 um 07:43 Uhr)
IT Security DownloadsGitHub Release: cline/cline vsdk/agents/v0.0.86 (24.09.2026)(24.09.2026 um 07:43 Uhr)
IT Security DownloadsGitHub Release: cline/cline vsdk/core/v0.0.86 (24.09.2026)(24.09.2026 um 07:43 Uhr)
IT Security DownloadsGitHub Release: cline/cline vcli-v3.0.65 (24.09.2026)(24.09.2026 um 07:54 Uhr)
IT Security NachrichtenKI-Agenten hebeln klassisches IT-Asset-Management aus(24.09.2026 um 07:14 Uhr)
IT Security NachrichtenMicrosoft erneuert Surface Pro und Laptop mit Snapdragon X2 Plus(24.09.2026 um 07:42 Uhr)
IT Security DownloadsGitHub Release: cline/cline vsdk/shared/v0.0.86 (24.09.2026)(24.09.2026 um 07:43 Uhr)
IT Security DownloadsGitHub Release: cline/cline vsdk/llms/v0.0.86 (24.09.2026)(24.09.2026 um 07:43 Uhr)
IT Security DownloadsGitHub Release: cline/cline vsdk/agents/v0.0.86 (24.09.2026)(24.09.2026 um 07:43 Uhr)
IT Security DownloadsGitHub Release: cline/cline vsdk/core/v0.0.86 (24.09.2026)(24.09.2026 um 07:43 Uhr)
IT Security DownloadsGitHub Release: cline/cline vcli-v3.0.65 (24.09.2026)(24.09.2026 um 07:54 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

MV-VI Pattern: Domain-Centric Design for Frontend Applications

TL;DR React hooks are powerful, but they tend to mix domain logic with implementation details (server state management, caching, loading/error handling). This couples business rules tightly to specific libraries and forces page…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!




TL;DR



React hooks are powerful, but they tend to mix domain logic with implementation details (server state management, caching, loading/error handling). This couples business rules tightly to specific libraries and forces page components to know about implementation concerns.



The MV-VI pattern separates domain interfaces (M) from view implementation (VI), keeping Model and View declarative while isolating runtime complexity in VI.









The Problem



In frontend development, we should be able to design around domain logic and interfaces. However, React's hook pattern makes this difficult.






Code Example



A typical cart hook implementation:




// hooks/useCart.ts
export function useCart() {
const queryClient = useQueryClient();

const { data } = useSuspenseQuery({
queryKey: ['cart'],
queryFn: async () => {
const response = await fetch('/api/cart');
return response.json();
},
});

const addMutation = useMutation({
mutationFn: async ({ productId, qty }: { productId: string; qty?: number }) => {
await fetch('/api/cart', {
method: 'POST',
body: JSON.stringify({ productId, qty }),
});
},
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['cart'] }),
});

const totalPrice = data.items.reduce(
(sum, item) => sum + item.price * item.qty,
0
);

return {
items: data.items,
totalPrice,
add: (productId: string, qty?: number) => addMutation.mutate({ productId, qty }),
isAdding: addMutation.isPending,
};
}









// pages/CartPage.tsx
export function CartPage() {
return (
<Suspense fallback={<div>Loading...</div>}>
<CartContent />
</Suspense>
);
}

function CartContent() {
const cart = useCart();

return (
<div>
{cart.items.map(item => (
<div key={item.id}>{item.name} - ${item.price * item.qty}</div>
))}
<footer>Total: ${cart.totalPrice.toLocaleString()}</footer>
</div>
);
}









Code Smells



From Myers' cohesion perspective, this hook exhibits Logical Cohesion — grouped by "cart-related things" rather than by reason for change.






1. Domain logic and implementation details are interleaved






// Coexisting in the same function
const { data } = useSuspenseQuery({ ... }); // Implementation: React Query
const totalPrice = data.items.reduce(...); // Domain: business logic
return { isAdding: addMutation.isPending }; // Implementation: state management artifact






totalPrice calculation is a pure business rule. It shouldn't change when switching from React Query to SWR. But currently they're mixed together, making separation difficult.






2. "Cart" definition is coupled to the library



The return type of useCart is the cart definition. isAdding comes from React Query's isPending, yet it's part of the domain interface. Change libraries, change the interface.






3. Page components must know implementation details






// Page handles Suspense directly
<Suspense fallback={<div>Loading...</div>}>
<CartContent />
</Suspense>






When using useSuspenseQuery, wrapping with Suspense is the consumer's responsibility. Forget it, get a runtime error. Same for ErrorBoundary.






4. Performance optimizations affect external code



Changing caching strategy, joining multiple queries, or migrating to TanStack DB might change the hook's return type, affecting all consumers.









The Solution: MV-VI Pattern




























Layer Role Cohesion Goal

M (Model)
Domain interface definition Functional

V (View)
Declarative UI rendering Functional

VI (View Implementation)
Absorbs runtime complexity Informational


VI intentionally accepts Informational cohesion (bundling data with everything that operates on it), allowing M and V to achieve Functional cohesion.






Historical Context



Myers' cohesion classifications came from 1974-75, the procedural programming era. Interestingly, what Myers ranked as "second-best" (Informational cohesion — multiple functions operating on a single data structure) became the core principle of OOP encapsulation.



MV-VI leverages this deliberately: VI accepts OOP-style Informational cohesion so that M and V can remain functionally cohesive and declarative.









Step 1: Model — Domain Interface



Pure type definitions that don't know about React. Define "what is a cart."




// domain/cart/types.ts
interface CartItem {
id: string;
productId: string;
name: string;
price: number;
qty: number;
totalPrice: number;
}

interface Cart {
items: CartItem[];
totalPrice: number;
totalQty: number;
add: (productId: string, qty?: number) => void;
remove: (itemId: string) => void;
updateQty: (itemId: string, qty: number) => void;
clear: () => void;
}






It's named Cart, not UseCartReturn or CartHookResult. Hooks are implementation concepts. From domain perspective, it's just "cart."









Step 2: View Implementation — Hook Implementation



Implement domain interface Cart in React environment. Server state, data joining, caching — all here.




// shared/Cart/useCart.ts
import type { Cart } from '@/domain/cart';

// Extend with view concerns
interface CartImpl extends Cart {
isAdding: boolean;
isRemoving: boolean;
isUpdating: boolean;
}

export function useCart(): CartImpl {
const queryClient = useQueryClient();

const { data: cart } = useSuspenseQuery({
queryKey: ['cart'],
queryFn: async () => {
const response = await cartApi.list();
return CartModel.fromResponse(response);
},
staleTime: 1000 * 60, // Performance optimization: external doesn't know
gcTime: 1000 * 60 * 5,
});

const addMutation = useMutation({
mutationFn: ({ productId, qty }: { productId: string; qty?: number }) =>
cartApi.add(productId, qty),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['cart'] }),
});

// ... other mutations

return {
// Domain interface implementation
items: cart.items,
totalPrice: cart.totalPrice,
totalQty: cart.totalQty,
add: (productId, qty) => addMutation.mutate({ productId, qty }),
remove: (itemId) => removeMutation.mutate(itemId),
updateQty: (itemId, qty) => updateQtyMutation.mutate({ itemId, qty }),
clear: () => clearMutation.mutate(),

// View concern extensions (outside domain interface)
isAdding: addMutation.isPending,
isRemoving: removeMutation.isPending,
isUpdating: updateQtyMutation.isPending,
};
}






CartImpl extends Cart. Properties like isAdding, isRemoving are server state management artifacts — not needed from domain perspective, but VI extends them for UI needs.









Step 3: View Implementation — Controller Component



Force Suspense and ErrorBoundary, don't expose hooks directly. This component is the core of MV-VI. It enables page components to express views centered on domain logic.




// shared/Cart/index.tsx
import { Suspense, ReactNode } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { useCart, CartImpl } from './useCart';

interface CartProps {
children: (cart: CartImpl) => ReactNode;
fallback?: ReactNode;
errorFallback?: ReactNode;
}

export function Cart({
children,
fallback = <CartSkeleton />,
errorFallback = <CartError />,
}: CartProps) {
return (
<ErrorBoundary fallback={errorFallback}>
<Suspense fallback={fallback}>
<CartContent children={children} />
</Suspense>
</ErrorBoundary>
);
}

function CartContent({ children }: { children: (cart: CartImpl) => ReactNode }) {
const cart = useCart();
return <>{children(cart)}</>;
}

// Don't export hook directly
// export { useCart } from './useCart'; // ❌






Controller component responsibilities:





  • Force Suspense/ErrorBoundary — consumers can't skip it


  • Hide hook — can't import useCart directly


  • Headless pattern — UI freedom via render prop









Step 4: View — Page Component



Page component only knows domain interface, defines UI declaratively.




// pages/CartPage/index.tsx
import { Cart } from '@/shared/Cart';

export function CartPage() {
return (
<Cart>
{(cart) => (
<div className="cart-page">
<header>
<h1>Cart ({cart.totalQty})</h1>
<button onClick={cart.clear}>Clear All</button>
</header>

{cart.items.length === 0 ? (
<p>Your cart is empty</p>
) : (
<ul>
{cart.items.map(item => (
<li key={item.id}>
<span>{item.name}</span>
<span>${item.totalPrice.toLocaleString()}</span>
<input
type="number"
value={item.qty}
onChange={(e) => cart.updateQty(item.id, Number(e.target.value))}
disabled={cart.isUpdating}
/>
<button
onClick={() => cart.remove(item.id)}
disabled={cart.isRemoving}
>
Remove
</button>
</li>
))}
</ul>
)}

<footer>
<span>Total: ${cart.totalPrice.toLocaleString()}</span>
</footer>
</div>
)}
</Cart>
);
}






What page components don't know:




  • Whether it's React Query or SWR

  • What the caching strategy is

  • How Suspense/ErrorBoundary are handled



What page components know:





  • Cart interface (items, totalPrice, add, remove...)

  • How to render it









VI Freedom



VI internals can change freely. As long as M's interface is satisfied, V is unaffected.




// Before: React Query
const { data } = useSuspenseQuery({
queryKey: ['cart'],
queryFn: cartApi.list,
});

// After: Switch to TanStack DB
const { data } = useQuery({
queryKey: ['cart'],
queryFn: () => db.cart.findMany(),
});

// Change caching strategy
const { data } = useSuspenseQuery({
queryKey: ['cart'],
queryFn: cartApi.list,
staleTime: 1000 * 60 * 5, // Changed to 5 minutes
refetchOnWindowFocus: false, // Disabled refetch on focus
});






These changes happen inside VI, so page components need no modification.









Same VI, Different UIs



Headless pattern allows rendering the same Cart controller with various UIs.




// Header mini cart
function MiniCart() {
return (
<Cart fallback={<span>...</span>}>
{(cart) => (
<button className="mini-cart">
🛒 {cart.totalQty}
</button>
)}
</Cart>
);
}

// Sidebar cart
function SidebarCart() {
return (
<Cart>
{(cart) => (
<aside className="sidebar-cart">
<h2>Cart</h2>
{cart.items.map(item => (
<div key={item.id}>{item.name} - {item.qty}x</div>
))}
<button>Checkout</button>
</aside>
)}
</Cart>
);
}












Folder Structure and Colocation



VI location depends on reuse scope. Structure stays the same.




# Reused across app
shared/
Cart/
index.tsx # Controller component
useCart.ts # Hook implementation
api.ts
model.ts

# Used in single page only
pages/
OrderPage/
index.tsx
_Cart/ # Underscore indicates internal module
index.tsx
useCart.ts






Key point: regardless of location, M-VI-V structure remains identical.









Dependency Direction






pages/ (V)

shared/ (VI: controller + hook)

domain/ (M: interface)






Unstable code (V) depends on stable code (M). No reverse dependencies.









Benefits






































Aspect Before After
Domain definition Tied to hook return type Independent pure interface
Library dependency Spread across domain Isolated in VI
Suspense handling Consumer might forget Controller enforces
Performance optimization Affects external code Free within VI
Testing Requires React Query mocking Test against interface








Summary



MV-VI pattern enables domain-centric design in frontend.





  • M (Model): Domain interface. Doesn't know React. Defines "what."


  • V (View): Page component. Only knows M's interface. Defines UI declaratively.


  • VI (View Implementation): Absorbs runtime complexity. Server state, caching, loading/error handling — all isolated here.



By having VI intentionally accept Informational cohesion, M and V can approach Functional cohesion and remain declarative.









Discussion Points



I'd love to hear thoughts on:





  1. Naming: Is "MV-VI" clear enough? Other suggestions?


  2. Trade-offs: When might this be overkill? What's the minimum complexity threshold?


  3. Testing: How do you currently test hooks with server state? Does this pattern help?


  4. Real-world experience: Anyone using similar patterns? What worked/didn't work?



Looking forward to the discussion!

SOC Incident Playbook: Remote Code Execution (RCE) Defense
title: Detect Exploitation - MV-VI Pattern: Domain-Centric Design for Frontend Applications
id: 43301c60-9ca4-451e-b072-7e223678a0fa
status: experimental
description: Automatisch generierte SIEM-Erkennungsregel basierend auf CTI Intelligence
references:
  - https://tsecurity.de/
author: iShareStuff CTI Automated Detection Engine
date: 2026-09-24
logsource:
  category: network_connection
  product: any
detection:
  selection:
      CommandLine|contains:
        - 'exploit'
  condition: selection
falsepositives:
  - Legitime administrative Zugriffe oder Penetrationstests
level: high
tags:
  - attack.initial_access
rule CTI_Threat_Indicator {
    meta:
        author = "iShareStuff CTI Automated Detection Engine"
        date = "2026-09-24"
        description = "YARA Signature for "
    strings:
        $str = "MV-VI Pattern: Domain-Centric " ascii wide
    condition:
        any of them
}
tsecurity.de Cognitive Threat RAG
Fokus-Vektor:

Kognitive Analyse für identifizierte Bedrohung: Erhöhte Bedrohungslage im Bereich MV-VI Pattern: Domain-Centric Design for.... Basierend auf 368k Vektor-Korrelationen werden sofortige Isolationsmaßnahmen für betroffene Endpunkte empfohlen.

🛡️ Angriffsfläche & Exposure

Netzwerk/Remote-Zugriff ohne Vorauthentifizierung möglich.

Empfohlene Sofortmaßnahmen
  • 1. Perimeter-Inspektion: Relevante Portfreigaben und exponierte Endpunkte unverzüglich scannen.
  • 2. Patch-Applikation: Hersteller-Hotfix einspielen oder betroffene Daemons in isolierte DMZ-Segmente überführen.
  • 3. Telemetrie & EDR-Alerts: Prozessaufrufe und Child-Processes auf anomale Shell-Spawns überwachen.
🔗 Semantisch verwandte Zero-Days MariaDB 11.7 VEC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten MV-VI Pattern: Domain-Centric Design for Frontend Applications

Thematisch verwandte Begriffe: MVVI, Pattern, DomainCentric, Design · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-96676 | A vulnerability was identified in Fast FAC1900R 20190827_2.0.2. The impa…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel TTP ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick