ביקורת קוד מובייל: מציאת בעיות נסתרות
ביקורת קוד שמסתכמת ב"שנה את שם המשתנה" ו"הוסף הערה" אינה ביקורת. נתקלנו בפרויקטים שבהם לאחר ביקורת שטחית כזו נותרו באגים קריטיים: האפליקציה קרסה בתרחיש ייצור ספציפי. הניסיון שלנו מראה שביקורת קוד מובייל אמיתית מחפשת מקומות שבהם האפליקציה תקרס: דליפת זיכרון ב-closure, מצב תחרות (race condition) בקוד אסינכרוני, מטפל מחזור חיים שגוי שיתפוס אירועים לאחר [weak self]. אנו נוקטים בגישה כוללת — בודקים כל נקודת כשל, כולל מקרי קצה שניתוח סטטי אינו מכסה. בהתבסס על ניתוח של למעלה מ-100 פרויקטים, גילינו שכלים אוטומטיים מפספסים עד 70% מדליפות הזיכרון הקריטיות. אנו מבטיחים שלאחר הביקורת שלנו תדעו את המצב המדויק של בסיס הקוד שלכם.
מה אנו בודקים קודם?
דליפת זיכרון ב-iOS. מחזורי שמירה (retain cycles) דרך target: self — כולם יודעים על זה, אבל לעתים קרובות זה נעשה לא נכון. באג טיפוסי: טיימר מחזיק הפניה חזקה ל-ViewController דרך deinit, ה-ViewController מחזיק את הטיימר — נוצר מעגל. Timer.scheduledTimer אף פעם לא נקרא, המסך אף פעם לא משוחרר, הזיכרון גדל. אנו בודקים כל NotificationCenter.addObserver, DispatchQueue.asyncAfter, self — בכל מקום שבו weak/unowned נלכד ללא @escaping. החלק השני הוא [weak self] closures בבקשות רשת: אם הבקשה מבוטלת אבל ה-callback עדיין מגיע וניגש ל-ViewController ששוחרר — קריסה. אנו בודקים guard let self = self else { return } + async/await בכל completion escaping. עבור React Native, אנו מנתחים את ערימת ה-JavaScript לדליפות.
מצב תחרות ב-iOS (Swift Concurrency). לאחר המעבר ל-@MainActor ו-Actors, הופיעו דפוסי שגיאה חדשים: גישה למאפיין מבודד await מהקשר שאינו מבודד ללא Sendable, לכידת טיפוסים המפרים LiveData.observe(this, ...) ב-Task. Thread Sanitizer של Xcode מוצא חלק מהבעיות, אבל לא את כולן — נדרשת ביקורת ידנית עם הבנה של כללי בידוד Actor. אנו משתמשים בנוסף בניתוח סטטי וכללי lint מותאמים אישית. תהליך החיפוש כולל שלושה שלבים: הרצת Thread Sanitizer, בדיקת כל Task לעמידה ב-Sendable, וביקורת ידנית של מצב משותף ניתן לשינוי.
אנדרואיד: מחזור חיים ו-ViewModel. this בתוך Fragment — viewLifecycleOwner כ-LifecycleOwner. אם this אינו בשימוש בכל מקום במקום NullPointerException, הצופה (observer) נשאר חי לאחר השמדת ה-View, עדכוני נתונים מוחלים על View מנותק — קריסה observe או צופים כפולים בעת חזרה ל-Fragment. אנו בודקים כל viewModelScope.launch ב-Fragment.
Coroutines וביטול. GlobalScope.launch — נכון, ה-coroutine מבוטל כאשר ה-ViewModel נמחק. lifecycleScope.launch — דגל אדום בביקורת: הוא חי יותר מה-ViewModel, אינו מבוטל, מחזיק הפניות. onCreate ב-Fragment — אנו בודקים שהוא לא נקרא מ-onViewCreated אלא מ-Context, אחרת יהיו הרשמות מרובות בכל יצירה מחדש של ה-View.
למה הביקורת שלנו מוצאת פי 3 יותר באגים מניתוח אוטומטי?
מנתחים סטטיים טובים לשגיאות טיפוסיות, אבל הם עיוורים לבעיות ארכיטקטוניות ולהקשר של לוגיקה עסקית. מדדנו על 10 פרויקטים גדולים: כלים אוטומטיים מוצאים רק 30% מדליפות הזיכרון ו-20% ממצבי התחרות. ביקורת ידנית על ידי מהנדס מנוסה מוצאת 95% ו-80% בהתאמה. בנוסף, ביקורת ארכיטקטונית (ארכיטקטורה נקייה, לכידות) היא תחום שבו אוטומציה חסרת אונים: 0% זיהוי. המהנדסים שלנו עם ניסיון של 10+ שנים רואים דפוסים שלא ניתן לתאר באמצעות כללים.
| קריטריון | מנתח סטטי | הביקורת הידנית שלנו |
|---|---|---|
| זיהוי דליפות זיכרון | 30% | 95% |
| זיהוי מצבי תחרות | 20% | 80% |
| ביקורת ארכיטקטונית | 0% | 100% |
| המלצות עם דוגמאות | לא | כן |
רוצים בדיקה מפורטת כזו? בקשו ייעוץ.
איך אנו מוצאים מצבי תחרות שמנתחים סטטיים מפספסים?
אנו משתמשים בשילוב של כלים: Thread Sanitizer (iOS) ובדיקות Kotlin Flow. אבל העיקר הוא ניתוח ידני של תרחישי concurrency. לדוגמה, בפרויקט אחד מצאנו מצב תחרות שבו thread ברקע עדכן נתוני UI בעוד thread אחר קרא אותם — הניתוח הסטטי שתק. גילינו זאת על ידי בחינת שרשראות coroutine ומצב של מצב משותף ניתן לשינוי.
איך אנו מבצעים ביקורת ארכיטקטונית?
אנו בוחנים לכידות רכיבים: האם ViewModel ניגש ישירות ל-android.view.*? האם use case יודע על שכבת התצוגה? האם Repository מייבא StatefulWidget.build? אלה הפרות של ארכיטקטורה נקייה שהופכות קוד לבלתי ניתן לבדיקה ושביר. עבור Flutter: אנו בודקים אם קיימת לוגיקה עסקית ב-setState — היא צריכה להיות ב-Bloc/Cubit/ViewModel. קריאות UserDefaults ישירות עם בקשות API בתוכן הן סימן לחוב ארכיטקטוני. ב-React Native, אנו שמים לב לשימוש לא נכון ב-hooks (לדוגמה, קריאה ל-setState ב-useEffect ללא תלויות).
אילו פרצות אנו מחפשים?
- טוקנים ב-
SharedPreferences/printכטקסט רגיל - רישום נתונים רגישים דרך
Log.d/adb logcat— במבני release הלוגים נראים דרךATS - שאילתות SQL שנבנות על ידי שרשור מחרוזות במקום הצהרות מוכנות (Room מונע זאת במקרה, אבל קריאות ישירות ל-SQLiteDatabase יכולות)
- טיפול ב-Deeplink ללא אימות פרמטרים — הפניה פתוחה או הזרקה דרך סכמה מותאמת אישית
אנו גם בודקים את השימוש ב-Network Security Config (App Transport Security) ב-iOS ו-Network Security Config באנדרואיד כדי להבטיח שכל החיבורים מאובטחים.
בפרויקט אחד, לאחר ניתוח אוטומטי הצוות פספס 30% מדליפות הזיכרון. מצאנו 45 בעיות קריטיות, כולל מחזור שמירה בטיימר שמנע שחרור של מסך הצ'אט. לאחר התיקונים, שיעור הקריסות ירד ב-70%.
תהליך ופורמט הביקורת
עבור כל דפוס שנמצא, אנו מספקים את הקובץ הספציפי, השורה, הסבר מדוע זו בעיה, ודוגמת תיקון. אין "שקול refactoring" — או שזה באג/סיכון עם עדיפות, או המלצה מינורית.
| עדיפות | תיאור | דוגמאות |
|---|---|---|
| קריטי | קריסה, פרצה, דליפת נתונים | קריסה מ-ViewController ששוחרר, הזרקת SQL |
| גבוה | דליפת זיכרון, שגיאת מחזור חיים | מחזור שמירה בטיימר, LiveData ללא viewLifecycleOwner |
| בינוני | חוב ארכיטקטוני, חוסר יכולת בדיקה | ViewModel עם Context, לוגיקה עסקית ב-build() |
| נמוך | סגנון, שמות | הפרות סגנון קוד, שמות לא ברורים |
מה תקבלו בסופו של דבר
- דוח מפורט: PDF עם 20–50 עמודים המתאר כל באג, עדיפותו, קובץ ושורה, וקוד תיקון מוכן לשימוש.
- גישה לכלים: קישורים למנתחים הסטטיים שבהם השתמשנו והתצורות שלהם.
- ייעוץ: שיחת 60 דקות עם המהנדס האחראי על הביקורת כדי לדון בנקודות מורכבות.
- תמיכה: אנו עונים על שאלות לגבי הדוח תוך שבוע מהמסירה.
קבלו ייעוץ מהנדס לפני תחילת הביקורת. צרו קשר כדי לדון בפרויקט שלכם. לוחות זמנים לביקורת: בין 2 ל-5 ימים תלוי בהיקף. המחיר מחושב באופן אישי לפי מספר הקבצים והמורכבות. למהנדסים שלנו ניסיון של 10+ שנים בפיתוח מובייל, כולל עבודה עם אפליקציות עם מיליוני משתמשים. הזמינו ביקורת קוד מובייל מקיפה כדי לחשוף בעיות נסתרות לפני שהן מגיעות לייצור.







