تصميم أنظمة الواجهات الأمامية

إطار RADIO لتصميم أنظمة الواجهات الأمامية

5 دقيقة للقراءة

مقابلات تصميم أنظمة الواجهات الأمامية تختبر مجموعة مهارات مختلفة تمامًا عن تصميم أنظمة الخلفية. بينما تركز الخلفية على قواعد البيانات وموازنات الحمل والأنظمة الموزعة، يركز تصميم أنظمة الواجهة الأمامية على هندسة المكونات وإدارة الحالة وأداء العرض وتجربة المستخدم.

كيف يختلف تصميم الواجهة الأمامية عن تصميم الخلفية

الجانب تصميم أنظمة الخلفية تصميم أنظمة الواجهة الأمامية
التركيز قابلية التوسع، التخزين، الإنتاجية الاستجابة، العرض، تجربة المستخدم
الحالة قاعدة البيانات، ذاكرة التخزين المؤقت، طوابير الرسائل حالة المكونات، URL، التخزين المحلي
الشبكة اتصال خدمة بخدمة استدعاءات API، اتصالات فورية
الفشل تعطل الخوادم، انقسامات الشبكة وضع عدم الاتصال، الاتصالات البطيئة
المقياس ملايين الطلبات/ثانية عرض 60 إطار/ثانية، حجم الحزمة

إطار RADIO

يمنحك RADIO بنية قابلة للتكرار لأي سؤال تصميم أنظمة واجهة أمامية. امشِ عبر كل خطوة بالترتيب:

R - Requirements (المتطلبات)    → توضيح النطاق والقيود
A - Architecture (الهندسة)      → شجرة المكونات وتخطيط الصفحة
D - Data Model (نموذج البيانات) → شكل الحالة، أين تعيش، كيف تتدفق
I - Interface (الواجهة)         → عقود API بين المكونات والخادم
O - Optimization (التحسين)      → الأداء، إمكانية الوصول، الحالات الطرفية

الخطوة 1: المتطلبات

اقضِ أول 3-5 دقائق في طرح أسئلة توضيحية. قسّم المتطلبات إلى وظيفية وغير وظيفية:

المتطلبات الوظيفية (ماذا يفعل):

  • ما الإجراءات الأساسية للمستخدم؟
  • ما البيانات المعروضة؟
  • ما التفاعلات المدعومة؟

المتطلبات غير الوظيفية (مدى جودة أدائه):

  • كم عدد المستخدمين المتزامنين؟
  • ما الأجهزة والمتصفحات التي يجب دعمها؟
  • ما أهداف زمن الاستجابة؟ (مثلاً، نتائج البحث خلال أقل من 200 مللي ثانية)
  • هل يُحتاج دعم عدم الاتصال؟
  • متطلبات إمكانية الوصول (مستوى WCAG)؟

الخطوة 2: الهندسة

ارسم شجرة المكونات. ابدأ بتخطيط مستوى الصفحة، ثم تعمّق في كل قسم:

<App>
  ├── <Header>
  │    ├── <Logo />
  │    ├── <SearchBar />
  │    └── <UserMenu />
  ├── <Sidebar>
  │    └── <Navigation />
  └── <MainContent>
       ├── <FilterPanel />
       └── <ResultsList>
            └── <ResultCard /> (متكرر)

القرارات الرئيسية لشرحها:

  • أي المكونات ذكية (ذات حالة) مقابل بسيطة (عرضية)؟
  • أين تفصل حدود المكونات؟
  • أي المكونات يتم تحميلها بشكل كسول؟

الخطوة 3: نموذج البيانات

حدد شكل الحالة وأين يعيش كل جزء من الحالة:

// حالة الخادم (مُحضرة، مُخزنة مؤقتًا عبر TanStack Query أو SWR)
interface ServerState {
  products: Product[];
  userProfile: User;
  notifications: Notification[];
}

// حالة العميل (محلية لواجهة المستخدم)
interface ClientState {
  searchQuery: string;
  selectedFilters: Filter[];
  isModalOpen: boolean;
  currentPage: number;
}

// حالة URL (قابلة للمشاركة، قابلة للحفظ في المفضلة)
interface URLState {
  category: string;    // /products?category=electronics
  sortBy: string;      // /products?sort=price-asc
  page: number;        // /products?page=3
}

شجرة قرارات إدارة الحالة:

نوع الحالة أين تعيش الأداة
بيانات الخادم طبقة التخزين المؤقت TanStack Query، SWR
حالة UI عامة مخزن خارجي Zustand، Redux Toolkit
حالة UI محلية المكون useState، useReducer
معتمدة على URL معاملات URL useSearchParams، الموجّه
بيانات النماذج مكتبة النماذج React Hook Form، Formik

الخطوة 4: الواجهة (طبقة API)

حدد العقود بين واجهتك الأمامية والخادم:

// تصميم REST API
GET    /api/products?q=laptop&category=electronics&page=1&limit=20
POST   /api/products          // إنشاء
PATCH  /api/products/:id      // تحديث جزئي
DELETE /api/products/:id      // حذف

// شكل الاستجابة
interface APIResponse<T> {
  data: T;
  pagination: {
    page: number;
    totalPages: number;
    totalItems: number;
  };
  error?: { code: string; message: string };
}

قرار REST مقابل GraphQL:

العامل REST GraphQL
موارد متعددة رحلات متعددة ذهابًا وإيابًا استعلام واحد
جلب زائد يُرجع كائنات كاملة طلب حقول محددة
التخزين المؤقت متوافق مع تخزين HTTP يحتاج تخزين مؤقت مُطبّع
إعداد الفريق أبسط للبدء يحتاج مخطط + أدوات

استراتيجية التحديثات الفورية:

الطريقة متى تُستخدم التعقيد
الاستطلاع تحديثات منخفضة التردد (كل 30+ ثانية) منخفض
SSE الخادم يدفع أحداث باتجاه واحد (إشعارات، خلاصات) متوسط
WebSocket تواصل فوري ثنائي الاتجاه (دردشة، تعاون) الأعلى

الخطوة 5: التحسين

هنا تميّز نفسك. غطِّ:

أداء العرض:

  • قوائم افتراضية للمحتوى الطويل القابل للتمرير (react-window، TanStack Virtual)
  • تقسيم الكود مع React.lazy() وتقسيم على مستوى المسارات
  • تحديثات متفائلة لسرعة مُدركة

أداء الشبكة:

  • إلغاء تكرار الطلبات والتخزين المؤقت
  • الجلب المسبق عند التمرير أو قرب المسار
  • تحسين الصور (التحميل الكسول، srcset، WebP/AVIF)

إمكانية الوصول:

  • التنقل بلوحة المفاتيح لجميع العناصر التفاعلية
  • سمات ARIA للأدوات المخصصة
  • إدارة التركيز عند تغيير المسارات

الحالات الطرفية:

  • وضع عدم الاتصال مع تخزين مؤقت لعامل الخدمة
  • حدود الخطأ للفشل اللطيف
  • الحالات الفارغة، حالات التحميل، حالات الخطأ

مثال عملي: تطبيق RADIO على صفحة بحث

لنمشِ عبر RADIO لصفحة بحث عن منتجات:

R (المتطلبات): المستخدمون يبحثون عن منتجات بالكلمات المفتاحية، يُصفون حسب الفئة والسعر، يُرتبون النتائج، يتنقلون بين الصفحات. يجب أن تعمل على الهاتف. الهدف: النتائج في أقل من 200 مللي ثانية.

A (الهندسة):

<SearchPage>
  ├── <SearchBar />          // إدخال مؤجل
  ├── <ActiveFilters />      // شرائح تُظهر الفلاتر الحالية
  ├── <FilterSidebar />      // الفئة، نطاق السعر
  └── <ResultsPanel>
       ├── <SortControls />  // الصلة، السعر، التقييم
       ├── <ProductGrid>
       │    └── <ProductCard /> (متكرر)
       └── <Pagination />

D (نموذج البيانات): استعلام البحث والفلاتر تعيش في معاملات URL (قابلة للمشاركة). المنتجات هي حالة خادم مُخزنة مؤقتًا بـ TanStack Query مع سلسلة الاستعلام كمفتاح تخزين.

I (الواجهة): GET /api/search?q=laptop&category=electronics&minPrice=500&sort=price-asc&page=1 يُرجع نتائج مُصفحة مع أعداد الجوانب.

O (التحسين): تأجيل إدخال البحث 300 مللي ثانية. جلب مسبق للصفحة التالية. عرض افتراضي لشبكة المنتجات على الهاتف. استخدام <img loading="lazy">. إضافة منطقة aria-live="polite" لإعلانات قارئ الشاشة عند تحديث النتائج.

نصيحة للمقابلات: ارسم دائمًا شجرة المكونات وتدفق الحالة على السبورة. يريد المحاورون رؤية عملية تفكيرك، وليس سماعها فقط.

التالي: سنمشي عبر ثلاث مسائل كلاسيكية في تصميم أنظمة الواجهة الأمامية خطوة بخطوة. :::

اختبار

الوحدة 4: تصميم أنظمة الواجهات الأمامية

خذ الاختبار