GammaCyber

Build, Deployment ו-Code Review

פיתוח Fullstack מתקדם · 4–5 שעות

// סקירה · שיעור הסיום של יחידה 3

Build, Deployment, CI/CD ו-Code Review

שיעור כפול לסיום יחידה 3: חצי ראשון — מהקוד ל-Production (Build, Vercel, GitHub Actions). חצי שני — Code Review: מקוד שעובד לקוד מקצועי (Code Smells, Refactoring, הגנה בראיון).

✓נושאי השיעור
  • Build Process: Bundling, Minification, Tree Shaking, Hashing
  • Environment Variables: .env, VITE_API_URL — הפרדת סביבות
  • Vercel: פריסה ב-3 שלבים + vercel.json ל-SPA Routing
  • GitHub Actions: CI/CD — בדיקות אוטומטיות בכל Push
  • Lazy Loading + Code Splitting: lazy() + Suspense
  • Lighthouse: Performance > 90, Accessibility > 95
  • Docker: Multi-stage Build — builder + nginx
  • Production Checklist — 10 נקודות לפני הסדנה
  • Code Smells: שכפול, פונקציות ארוכות, Magic Numbers
  • Refactoring: Extract Function, Meaningful Names, DRY
  • הגנה בראיון — לדעת לצדק ולבקר את ארכיטקטורת הפרויקט
// פרק 1

Build Process — מה קורה ב-npm run build

בפיתוח, React מריץ Dev Server עם HMR. ב-Production צריך קבצים סטטיים אופטימליים. npm run build מריץ שרשרת שלמה של טרנספורמציות.

שלבמה קורהתוצאה
Bundlingמאחד את כל הקבצים לחבילותכמה קבצי JS/CSS גדולים
TranspilationBabel ממיר JSX ו-TypeScript ל-JSJS שהדפדפן מבין
Minificationמסיר רווחים, מקצר שמותקבצים קטנים ב-70–90%
Tree Shakingמסיר קוד שלא בשימושBundle קטן יותר
Hashingמוסיף hash לשמות הקבציםCache Busting אוטומטי
# הרצת Build npm run build # תוצאה — תיקיית dist/: dist/ index.html assets/ index-3f4a9b2c.js # JS ראשי + Hash index-7d8e1f3a.css # CSS + Hash # Preview לפני פריסה npm run preview # פותח localhost:4173
💡 Hash בשמות הקבצים — למה?
הדפדפן שומר קבצים ב-Cache לפי שם. index.js תמיד יוגש מ-Cache. כשמוסיפים Hash (index-3f4a9b2c.js), כל Build שמשנה את הקוד יוצר שם חדש → ה-Cache הישן מקבל גרסה חדשה אוטומטית.
הרחבה Tree Shaking — למה זה חשוב? ›

Tree Shaking מסיר קוד שלא נמצא בשימוש מה-Bundle. לדוגמה: import { format } from 'date-fns' — רק format נכנס ל-Bundle, לא כל הספרייה.

תנאי: עובד רק עם ES Modules (import/export). CommonJS (require) לא ניתן ל-Tree Shaking.

✏תרגול עצמי2 שאלות
שאלה 1.1
מה המטרה של Hash בשם קובץ כמו index-3f4a9b2c.js?
✓ תשובה: ב) — הדפדפן מאחסן קבצים ב-Cache לפי שמם. אם תמיד יהיה index.js, המשתמש לעולם לא יקבל עדכונים. Hash שמשתנה בכל Build מבטיח שהדפדפן יוריד תמיד את הגרסה העדכנית.
שאלה 1.2
מה ההבדל בין CI ל-CD?
✓ תשובה: ב) — Continuous Integration = כל Push מפעיל בדיקות+Build. Continuous Deployment = אחרי CI מוצלח, הקוד נפרס אוטומטית. ביחד: כל שינוי שעובר בדיקות מגיע למשתמשים אוטומטית.
// פרק 2

Environment Variables — הפרדת סביבות

אפליקציה אמיתית מתחברת לכתובות שונות בפיתוח ו-Production. Environment Variables מאפשרים להגדיר פעם אחת ולהשתמש בכל מקום — בלי לשנות קוד.

# .env.development — נטען ב-npm run dev VITE_API_URL=http://localhost:3000 # .env.production — נטען ב-npm run build VITE_API_URL=https://api.myapp.com # .env.local — override מקומי, לא ב-Git! (הוסף ל-.gitignore) VITE_API_KEY=my-local-key
// שימוש בקוד — import.meta.env (Vite) const apiUrl = import.meta.env.VITE_API_URL; const api = axios.create({ baseURL: import.meta.env.VITE_API_URL, timeout: 5000, }); // בדיקת סביבה if (import.meta.env.DEV) { console.log('מצב פיתוח — Logs מופעלים'); }
! אבטחה קריטית — לעולם לא Secrets ב-Frontend! ›

VITE_API_URL, VITE_APP_NAME — בסדר. כל אחד יכול לראות אותם ב-Browser DevTools → Sources.

VITE_DB_PASSWORD, VITE_API_SECRET_KEY — אסור! הם גלויים לכל גולש, גם אחרי Minification.

כלל: Secrets (מפתחות API, סיסמאות) חיים רק בצד ה-Backend. ה-Frontend מדבר עם Backend, והוא מדבר עם השירות החיצוני.
✏תרגול עצמי2 שאלות
שאלה 2.1
מפתח שם את VITE_STRIPE_SECRET_KEY בקובץ .env ומשתמש בו בקוד React. מה הבעיה?
✓ תשובה: ג) — כל VITE_* variable נכלל ב-Bundle ומגיע לדפדפן המשתמש. Stripe Secret Key שנחשף = גישה לחשבון התשלומים. Secrets חיים ב-Backend בלבד.
שאלה 2.2
ב-Vite, איזה prefix חייב להיות לכל Environment Variable שרוצים לגשת אליו מה-React?
✓ תשובה: ד) — ב-Vite: VITE_*. ב-CRA: REACT_APP_*. Variables ללא ה-prefix לא נחשפים ל-Browser — מנגנון אבטחה מכוון.
// פרק 3

Vercel ו-GitHub Actions — Deployment אוטומטי

Vercel הפלטפורמה הפופולרית ביותר לפריסת React Apps. GitHub Actions מאפשר CI/CD — בדיקות ופריסה אוטומטית בכל Push.

פריסה ב-3 שלבים עם Vercel

שלבפעולהתוצאה
1. Push לGitHubgit push origin mainקוד מעודכן ב-Repo
2. Vercel מזההWebhook מפעיל Build אוטומטיBuild + Tests רצים
3. DeployVercel פורסת ל-CDN גלובליhttps://my-app.vercel.app
// vercel.json — חובה לReact Router (SPA Routing)! // ללא זה, Refresh ב-/about יחזיר 404 { "rewrites": [ { "source": "/(.*)", "destination": "/index.html" } ] }

GitHub Actions — CI Workflow

# .github/workflows/ci.yml name: CI on: push: branches: [main, develop] pull_request: branches: [main] jobs: test-and-build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - run: npm ci # מהיר + דטרמיניסטי - run: npm test -- --watchAll=false - run: npm run build
הרחבה npm ci לעומת npm install ›

npm install: מתקין ויכול לעדכן packages, משנה package-lock.json.

npm ci: מתקין בדיוק לפי package-lock.json ולא משנה אותו — מהיר ודטרמיניסטי.

ב-CI תמיד npm ci — מבטיח שכולם מריצים בדיוק את אותן גרסאות.

✏תרגול עצמי2 שאלות
שאלה 3.1
משתמש רענן את הדף ב-/about ב-React App שפרסתם ב-Vercel וקיבל שגיאת 404. מה הסיבה?
✓ תשובה: א) — React Router מנהל ניווט ב-JavaScript. Refresh שולח בקשה לשרת ל-/about. ללא rewrites, Vercel מחפש about.html שלא קיים. הפתרון: vercel.json שמפנה הכל ל-index.html.
שאלה 3.2
מה הוא needs: test ב-GitHub Actions Workflow?
✓ תשובה: א) — needs: test יוצר תלות: Deploy רץ רק אחרי שה-test Job הסתיים בהצלחה. כך מבטיחים שלא פורסים קוד שנכשל בבדיקות.
// פרק 4

Performance, Lighthouse ו-Docker

לפני הסדנה — מדידה ואופטימיזציה. Lighthouse מודד ביצועים ונגישות. Code Splitting מקטין זמן טעינה. Docker מאפשר פריסה עקבית בכל סביבה.

Code Splitting + Lazy Loading

import { lazy, Suspense } from 'react'; // במקום: import AdminPage from './AdminPage'; // נטען תמיד // עם Lazy: נטען רק כשמנווטים לRoute const AdminPage = lazy(() => import('./AdminPage')); const SettingsPage = lazy(() => import('./SettingsPage')); function App() { return ( <BrowserRouter> {/* Suspense: מה להציג בזמן הטעינה */} <Suspense fallback={<div>טוען...</div>}> <Routes> <Route path='/' element={<Home />} /> <Route path='/admin' element={<AdminPage />} /> <Route path='/settings' element={<SettingsPage />} /> </Routes> </Suspense> </BrowserRouter> ); }

Lighthouse — מדדים לסדנה

קטגוריהמה נמדדיעד
PerformanceFCP, LCP, CLS, TBT> 90
AccessibilityARIA, contrast, labels> 95
Best PracticesHTTPS, Console Errors> 90
SEOmeta tags, robots.txt> 90
הרחבה Docker Multi-stage Build ›
# Dockerfile — Multi-stage Build # Stage 1: Build FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build # Stage 2: Serve (תמונה קטנה ~20MB במקום ~500MB) FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
# nginx.conf — SPA Routing server { listen 80; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; # כל URL → index.html } } # בניה והרצה docker build -t my-react-app . docker run -p 3000:80 my-react-app
✏תרגול עצמי2 שאלות
שאלה 4.1
מה עושה lazy(() => import('./AdminPage'))?
✓ תשובה: ב) — lazy() יוצר Code Split: הדפדפן לא יוריד את AdminPage עד שמישהו מנווט ל-/admin. הטעינה הראשונית של האפליקציה מהירה יותר.
שאלה 4.2
מה היתרון העיקרי של Docker Multi-stage Build?
✓ תשובה: ב) — Stage 1 בונה עם Node.js (גדול). Stage 2 מעתיק רק את הקבצים הסטטיים ל-nginx (קטן). תמונת Production קטנה = העלאה מהירה + שטח Storage קטן.
// פרק 5 · Code Review

Code Review — מקוד שעובד לקוד מקצועי

קוד שעובד הוא רק ההתחלה. קוד שקשה לקרוא ולשנות הוא חוב טכני (Technical Debt) שמאט פיתוח עתידי. בראיון גאמא — בוחנים יצללו לתוך הקוד שלכם.

Code Smells — ריחות רעים

שכפול קוד (Duplication): הפרת עקרון DRY (Don't Repeat Yourself). אם קוד זהה מופיע בשני מקומות — תקלה אחת תצריך תיקון בשניים.

פונקציות ארוכות (Long Functions): פונקציה שאחראית על יותר מדי דברים. קשה להבין, קשה לבדוק.

מספרי קסם (Magic Numbers): מספרים יתומים בקוד ללא הסבר (86400 — מה זה? שניות ביממה?).

Refactoring — לשפץ מבלי להרוס

// ❌ קוד מסריח — Magic Numbers + שמות לא ברורים function calc(p, t) { if (t === 1) return p * 0.9; if (t === 2) return p * 0.8; return p; } // ✅ קוד נקי — קריא ובר תחזוקה const USER_TYPES = { REGULAR: 1, PREMIUM: 2 }; const DISCOUNTS = { REGULAR: 0.9, // 10% הנחה PREMIUM: 0.8 // 20% הנחה }; function calculateFinalPrice(price, userType) { if (userType === USER_TYPES.REGULAR) return price * DISCOUNTS.REGULAR; if (userType === USER_TYPES.PREMIUM) return price * DISCOUNTS.PREMIUM; return price; }
🔑עקרון Single Responsibility (SRP)
  • כל פונקציה ומחלקה צריכה לעשות דבר אחד — ולעשות אותו טוב
  • אם הפונקציה עושה fetch + ולידציה + עדכון UI — פצל לשלוש פונקציות
  • פונקציה קצרה = קל לבדוק, קל להבין, קל לתחזק
✏תרגול עצמי3 שאלות
שאלה 5.1
מהו עיקרון DRY?
✓ תשובה: א) — אם יש לך לוגיקה זהה בשני מקומות ומגיעה תקלה — צריך לתקן פעמיים. אם שכחת לתקן באחד = באג. DRY אומר: חלץ לפונקציה משותפת ורפרנס ממקום אחד.
שאלה 5.2
מה בעיית Magic Number? כגון if (role === 2)
✓ תשובה: ד) — הפתרון: const ROLES = { ADMIN: 2 } ואז if (role === ROLES.ADMIN). עכשיו הקוד מסביר את עצמו ואם הערך משתנה — מעדכנים במקום אחד.
שאלה 5.3 — ראיון
בוחן שואל: "מה החולשה הכי גדולה בארכיטקטורת הפרויקט שלך?" — מה התגובה הנכונה?
✓ תשובה: א) — בוחנים לא מחפשים קוד מושלם, אלא יכולת חשיבה ביקורתית. "הבאתי את כל הנתיבים ב-Component אחד — בפרויקט גדול הייתי מפצל ל-services נפרדים" = תשובה מקצועית ובוגרת.
// פרק 6

Production Checklist — לפני הסדנה

לפני שמציגים פרויקט בסדנה — עוברים על Checklist קצר. לחצו על כל פריט כדי לסמן שביצעתם.

✓
npm run build מצליח ללא שגיאות
הריצו בטרמינל, ראו ש-dist/ נוצר
✓
npm run preview עובד כצפוי
פתחו localhost:4173, בדקו את כל ה-Routes
✓
אין console.errors ב-Production
פתחו DevTools ב-Preview, בדקו Console
✓
Environment Variables הוגדרו ב-Vercel
Dashboard → Settings → Environment Variables
✓
SPA Routing עובד ב-Refresh
פנה ל-/about ישירות, ראה שלא 404
✓
תמונות נטענות (alt + גודל)
Network Tab — Images < 200KB כל אחת
✓
Mobile Responsive
DevTools → Toggle device toolbar
✓
Lighthouse > 85 ב-Performance
Lighthouse Tab ב-DevTools של הURL הפרוס
✓
כל הבדיקות עוברות (npm test)
הריצו npm test — כל הבדיקות ירוקות
✓
README עדכני עם הוראות הרצה
קראו README כאילו אתם חדשים לפרויקט
// אתגר מעשי

אתגר מעשי — פריסה — Env, סודות ו-CI

שיא השיעור: לבנות רכיב עובד עם זווית אבטחה. ההגשה נבדקת אוטומטית.

T2 · בסיסי200 נק'~15 דק'build
פרסור קובץ .env
ממש parse_env(text) שמפרק תוכן קובץ .env למילון. דלג על שורות ריקות ועל הערות (מתחילות ב-#). כל שורה KEY=VALUE: התעלם מקידומת 'export '; קצץ רווחים סביב המפתח והערך; הסר מרכאות עוטפות (' או ") מהערך; פצל על ה-'=' הראשון בלבד (כך ש-'=' בערך נשמר). שורה בלי '=' — דלג.
דוגמאות
'A=1\n# comment\nB="two words"\nexport C=3' → {'A':'1','B':'two words','C':'3'}
'URL=http://x?a=1&b=2' → {'URL':'http://x?a=1&b=2'}
הפתרון נשמר מקומית ומשותף עם עמוד „כתיבת קוד”.
פתרון-ייחוס פרסור קובץ .env ›
def parse_env(text: str) -> dict: env = {} for line in text.splitlines(): line = line.strip() if not line or line.startswith('#'): continue if line.startswith('export '): line = line[7:].strip() if '=' not in line: continue k, v = line.split('=', 1); k = k.strip(); v = v.strip() if len(v) >= 2 and v[0] == v[-1] and v[0] in "\"'": v = v[1:-1] env[k] = v return env
T3 · בינוני350 נק'~22 דק'build
סורק סודות מוקשחים (Pre-commit)
בדיקת production: אף פעם לא מכניסים סודות ל-git. ממש scan_secrets(lines) שמחזיר רשימת (מספר_שורה, סוג) עבור סודות מוקשחים. זהה: (1) מפתח AWS בתבנית AKIA + 16 תווי [0-9A-Z] → 'aws_key'; (2) השמה למשתנה בשם password/secret/api_key/token עם מחרוזת מילולית לא-ריקה → 'secret_assignment'. שורות שקוראות ממשתנה-סביבה (בלי מחרוזת מילולית) אינן סוד. מספור שורות מ-1.
דוגמאות
['x=1', 'password = "hunter2"', 'y=2'] → [(2, 'secret_assignment')]
['key = "AKIAIOSFODNN7EXAMPLE"'] → [(1, 'aws_key')]
הפתרון נשמר מקומית ומשותף עם עמוד „כתיבת קוד”.
פתרון-ייחוס סורק סודות מוקשחים (Pre-commit) ›
import re def scan_secrets(lines: list) -> list: findings = [] aws = re.compile(r'AKIA[0-9A-Z]{16}') assign = re.compile(r'(?i)\b(password|secret|api_?key|token)\b\s*[:=]\s*[\'"][^\'"]+[\'"]') for i, line in enumerate(lines, 1): if aws.search(line): findings.append((i, 'aws_key')) elif assign.search(line): findings.append((i, 'secret_assignment')) return findings
// סיכום · סוף יחידה 3

סיכום — שיעור 22 וסיום יחידה 3

עברנו מ-React עד Production. יחידה 3 הושלמה — אתם מוכנים לבנות ולפרוס פרויקט Fullstack מקצועי.

✓מה למדנו בשיעור 22
  • Build: Bundling → Transpilation → Minification → Tree Shaking → Hashing
  • Environment Variables: VITE_* prefix — Secrets לעולם לא ב-Frontend
  • Vercel: GitHub Integration + vercel.json לSPA Routing
  • GitHub Actions: npm ci + test + build בכל Push
  • Lazy Loading: lazy() + Suspense — Code Splitting לפי Route
  • Lighthouse: Performance > 90, Accessibility > 95 — יעדים לסדנה
  • Docker Multi-stage: builder (~500MB) + nginx serve (~20MB)
  • Code Smells: שכפול, Magic Numbers, פונקציות ארוכות
  • Refactoring: שמות ברורים, DRY, Single Responsibility
  • ראיון: לדעת לזהות ולבקר את ארכיטקטורת הפרויקט שלך
📌 לפני יחידה 4 (שפת C)
  1. פרוס את הפרויקט האישי ל-Vercel — קישור פעיל לסדנה
  2. הגדר GitHub Actions עם CI — Workflow שמריץ בדיקות בכל Push
  3. הרץ Lighthouse, תקן בעיות עד ציון > 85 ב-Performance
  4. יחידה 4: שפת C ו-Assembly — בסיס לכל חולשות האבטחה
שאלות תרגול ותשובות (10)

שאלה 1.1 · מה המטרה של Hash בשם קובץ כמו index-3f4a9b2c.js?

  • א. הצפנת תוכן הקובץ לצורכי אבטחה
  • ב. ניצחון מטמון
  • ג. זיהוי גרסת ספריית React בקובץ
  • ד. קיצור שם הקובץ לחיסכון בנפח האחסון
תשובה: ב

✓ תשובה: ב) — הדפדפן מאחסן קבצים ב-Cache לפי שמם. אם תמיד יהיה index.js, המשתמש לעולם לא יקבל עדכונים. Hash שמשתנה בכל Build מבטיח שהדפדפן יוריד תמיד את הגרסה העדכנית.

שאלה 1.2 · מה ההבדל בין CI ל-CD?

# .env.development — נטען ב-npm run dev
VITE_API_URL=http://localhost:3000

# .env.production — נטען ב-npm run build
VITE_API_URL=https://api.myapp.com

# .env.local — override מקומי, לא ב-Git! (הוסף ל-.gitignore)
VITE_API_KEY=my-local-key
  • א. CI הוא פריסה ו-CD הוא בדיקות
  • ב. CI הוא בדיקות ו-Build אוטומטי בכל Push, ואילו CD הוא פריסה אוטומטית לאחר שה-CI עבר בהצלחה
  • ג. שניהם זהים לחלוטין ורק הקיצורים שונים
  • ד. CI לפרויקטים גדולים ו-CD לפרויקטים קטנים
תשובה: ב

✓ תשובה: ב) — Continuous Integration = כל Push מפעיל בדיקות+Build. Continuous Deployment = אחרי CI מוצלח, הקוד נפרס אוטומטית. ביחד: כל שינוי שעובר בדיקות מגיע למשתמשים אוטומטית.

שאלה 2.1 · מפתח שם את VITE_STRIPE_SECRET_KEY בקובץ .env ומשתמש בו בקוד React. מה הבעיה?

  • א. הקידומת חייבת להיות REACT_APP ולא VITE
  • ב. אין כל בעיה
  • ג. אפליקציית React רצה בדפדפן
  • ד. קובץ ה-env אינו נקלט כלל ב-Vite
תשובה: ג

✓ תשובה: ג) — כל VITE_* variable נכלל ב-Bundle ומגיע לדפדפן המשתמש. Stripe Secret Key שנחשף = גישה לחשבון התשלומים. Secrets חיים ב-Backend בלבד.

שאלה 2.2 · ב-Vite, איזה prefix חייב להיות לכל Environment Variable שרוצים לגשת אליו מה-React?

// vercel.json — חובה לReact Router (SPA Routing)!
// ללא זה, Refresh ב-/about יחזיר 404
{
  "rewrites": [
    { "source": "/(.*)", "destination": "/index.html" }
  ]
}
  • א. REACT_APP כקידומת הנדרשת למשתנה
  • ב. PUBLIC כקידומת הנדרשת למשתנה הסביבה
  • ג. אין צורך בקידומת כלשהי למשתנה הסביבה
  • ד. VITE
תשובה: ד

✓ תשובה: ד) — ב-Vite: VITE_*. ב-CRA: REACT_APP_*. Variables ללא ה-prefix לא נחשפים ל-Browser — מנגנון אבטחה מכוון.

שאלה 3.1 · משתמש רענן את הדף ב-/about ב-React App שפרסתם ב-Vercel וקיבל שגיאת 404. מה הסיבה?

  • א. חסר קובץ vercel.json עם הגדרת rewrites
  • ב. עמוד ה-about אינו קיים כלל בפרויקט
  • ג. React Router אינו תומך בפלטפורמת Vercel
  • ד. צריך להשתמש ב-HashRouter במקום BrowserRouter
תשובה: א

✓ תשובה: א) — React Router מנהל ניווט ב-JavaScript. Refresh שולח בקשה לשרת ל-/about. ללא rewrites, Vercel מחפש about.html שלא קיים. הפתרון: vercel.json שמפנה הכל ל-index.html.

שאלה 3.2 · מה הוא needs: test ב-GitHub Actions Workflow?

import { lazy, Suspense } from 'react';

// במקום: import AdminPage from './AdminPage';  // נטען תמיד
// עם Lazy: נטען רק כשמנווטים לRoute
const AdminPage    = lazy(() => import('./AdminPage'));
const SettingsPage = lazy(() => import('./SettingsPage'));

function App() {
  return (
    <BrowserRouter>
      {/* Suspense: מה להציג בזמן הטעינה */}
      <Suspense fallback={<div>טוען...</div>}>
        <Routes>
          <Route path='/'        element={<Home />} />
          <Route path='/admin'   element={<AdminPage />} />
          <Route path='/settings' element={<SettingsPage />} />
        </Routes>
      </Suspense>
    </BrowserRouter>
  );
}
  • א. תלות בין ה-Jobs
  • ב. פקודה להתקנת ספריית Jest בסביבה
  • ג. הגדרת מספר ה-Runners להרצה במקביל
  • ד. ציון שה-Job זקוק לסביבת Node.js לריצה
תשובה: א

✓ תשובה: א) — needs: test יוצר תלות: Deploy רץ רק אחרי שה-test Job הסתיים בהצלחה. כך מבטיחים שלא פורסים קוד שנכשל בבדיקות.

שאלה 4.1 · מה עושה lazy(() => import('./AdminPage'))?

  • א. מכביד על הטעינה הראשונית של האפליקציה
  • ב. פיצול קוד
  • ג. מגביל את הגישה לדף רק למשתמשים מנהלים
  • ד. מאחד את כל הקומפוננטות לתוך קובץ אחד
תשובה: ב

✓ תשובה: ב) — lazy() יוצר Code Split: הדפדפן לא יוריד את AdminPage עד שמישהו מנווט ל-/admin. הטעינה הראשונית של האפליקציה מהירה יותר.

שאלה 5.1 · מהו עיקרון DRY?

  • א. אל תחזור על עצמך, כלומר כל לוגיקה תופיע במקום אחד בלבד
  • ב. אל תשתמש ב-CSS ישירות אלא השתמש ב-Tailwind
  • ג. כתוב את הקוד קצר ככל האפשר תמיד
  • ד. תמיד כתוב את הבדיקות לפני הקוד עצמו
תשובה: א

✓ תשובה: א) — אם יש לך לוגיקה זהה בשני מקומות ומגיעה תקלה — צריך לתקן פעמיים. אם שכחת לתקן באחד = באג. DRY אומר: חלץ לפונקציה משותפת ורפרנס ממקום אחד.

שאלה 5.2 · מה בעיית Magic Number? כגון if (role === 2)

  • א. מספרים גורמים לביצועים איטיים יותר בהרצה
  • ב. TypeScript אינו תומך בהשוואת מספרים עם שלושה סימנים
  • ג. אין כל בעיה
  • ד. המספר 2 אינו מסביר דבר
תשובה: ד

✓ תשובה: ד) — הפתרון: const ROLES = { ADMIN: 2 } ואז if (role === ROLES.ADMIN). עכשיו הקוד מסביר את עצמו ואם הערך משתנה — מעדכנים במקום אחד. 🎯 דגש למבחן — היסטוריית Git היא כרטיס ביקור מקצועי: הודעות כמו "fix", "asdf" או "update" פוסלות אתכם בעיני בוחן. כתבו הודעה שמתארת מה השתנה ולמה (feat: add user login validation).

שאלה 5.3 — ראיון · בוחן שואל: "מה החולשה הכי גדולה בארכיטקטורת הפרויקט שלך?" — מה התגובה הנכונה?

def parse_env(text: str) -> dict:
    env = {}
    for line in text.splitlines():
        line = line.strip()
        if not line or line.startswith('#'): continue
        if line.startswith('export '): line = line[7:].strip()
        if '=' not in line: continue
        k, v = line.split('=', 1); k = k.strip(); v = v.strip()
        if len(v) >= 2 and v[0] == v[-1] and v[0] in "\"'":
            v = v[1:-1]
        env[k] = v
    return env
  • א. לזהות חולשה אמיתית ולהסביר מדוע היא קיימת וכיצד אפשר לפתור אותה
  • ב. לומר שהפרויקט מושלם ואין בו כל חולשות
  • ג. לומר בפשטות אינני יודע לענות על כך
  • ד. להסיט את הנושא לכיוון נושא אחר לגמרי
תשובה: א

✓ תשובה: א) — בוחנים לא מחפשים קוד מושלם, אלא יכולת חשיבה ביקורתית. "הבאתי את כל הנתיבים ב-Component אחד — בפרויקט גדול הייתי מפצל ל-services נפרדים" = תשובה מקצועית ובוגרת. 🎯 דגש למבחן — הימנעו מ-Over-engineering: במבחן קוד מעשי כתבו את הפתרון הפשוט שעובד. השתמשו במחלקות, ירושה ו-Design Patterns רק כשהמשימה באמת מחייבת זאת.