מדוע אפליקציית ריצה מאבדת דיוק במרחקים ארוכים
פיתוח אפליקציית ריצה נתקל בבעיה שמבחינים בה לא בהקפה של ניסוי, אלא בקילומטר העשרים: המסלול מתחיל "לחתוך" עיקולים, הקצב קופץ, והדופק מפגר אחרי המציאות בעשרות שניות.
הסיבה אינה תקלה אחת, אלא הצטברות: אובדן אות GPS בבנייה צפופה או ברצועת יער, סחיפה של החיישן לאחר שינוי קצב, חוסר סנכרון בין זרם הקואורדינטות לזרם קצב הלב, כאשר כל אחד מהם נכתב בטיימר משלו.
לאחר מכן נכנס לתוקף אפקט שני — צריכת הסוללה בעת הקלטת האימון. סקירת GPS מתמדת בתדירות גבוהה, החזקת המסך דלוק, סנכרון ברקע וחישוב מחדש של המסלול בזמן אמת מרוקנים את הסוללה מהר יותר מאורך הריצה עצמה.
המשתמש רואה את המוכר לו: בקילומטרים האחרונים הטלפון נכבה, ואיתו הולך לאיבוד הקטע האחרון, שלשמו בעצם הוקלט הכול.
עבור המוצר זה יקר יותר ממה שנדמה. חוסר דיוק במעקב אחר ריצות שובר את האמון בנתונים: הרץ מפסיק להאמין לקצב ולאזורי הדופק, מפסיק להשוות את הקטעים שלו ולשתף תוצאות. ופריקה באמצע ריצה היא לא "באג קטן", אלא אימון שאבד וסיבה למחוק את האפליקציה.
מפרקים כיצד זה נסגר ברמת הארכיטקטורה של ההקלטה, ולא בתיקונים קוסמטיים.
מה נותנת ארכיטקטורה נכונה: מדדים, מצבים, מגבלות
היכן בדיוק הולכים לאיבוד נתונים וזמן
שלושה צמתים קובעים אם האפליקציה תשרוד אימון אמיתי: מעקב אימונים ברקע כשהמסך נעול, התנהגות האפליקציה בעת ניתוק הרשת ושחזור הסשן לאחר שהמערכת פינתה את התהליך מהזיכרון. טעות באחד מהם מייצרת אותו סוג כשל — "הריצה נרשמה, אבל חצי מהמסלול נעלם".
ארכיטקטורת אפליקציית מובייל פותרת זאת לא ב"אופטימיזציה אחר כך", אלא בבחירת מודל הכתיבה והסנכרון כבר בהתחלה.
מה נותן אפקט מדיד
- יומן נקודות מקומי עם כתיבה מקובצת. קואורדינטות ודופק נכתבים לדיסק מיד, ולא נצברים בזיכרון עד לשליחה. שיעור הנקודות שאבדות בעת פינוי התהליך יורד מעשרות אחוזים לאחוזים בודדים.
- סנכרון נתונים אופליין אידמפוטנטי. כל אימון מקבל מזהה במכשיר; שליחה חוזרת לאחר ניתוק אינה יוצרת כפילויות. זמן שחזור הסשן לאחר כשל רשת — שניות במקום הפעלה מחדש ידנית.
- הפרדה בין כתיבה לרינדור. המפה והגרפים קוראים מהיומן, ולא מכתיבים את קצב הכתיבה. הממשק לא "נתקע" במכשיר חלש, והמסלול ממשיך להיכתב כשהאפליקציה ממוזערת.
- מצבי סשן מפורשים. אימון שהופסק משוחזר מהיומן מהנקודה התקפה האחרונה, ולא מתחיל מחדש.
השוואה בין גישות למעקב
| גישה | מתי מתאימה | מגבלות |
|---|---|---|
| כתיבה לזיכרון עם שליחה בסוף | אימונים קצרים, רשת יציבה | אובדן כל הסשן בעת פינוי התהליך |
| יומן מקומי + שליחה מקובצת | התרחיש העיקרי של אפליקציית ריצה | נדרשת לוגיקת מיזוג ואידמפוטנטיות |
| שליחה בזרימה בזמן אמת | שידורים חיים, ריצות קבוצתיות | צריכת סוללה, רגישות לניתוקים |
בפועל אנחנו משלבים את המצב השני והשלישי: היומן כמקור האמת, הזרימה כתוספת לתרחישים חיים. שכבה כזו של סנכרון נוח לבנות על SQLite עם תור של פעולות יוצאות.
תארו את תרחיש האימונים ואת הסטאק הנוכחי — נחזור עם הערכה ותוכנית לארכיטקטורת הכתיבה והסנכרון.
שלבי פיתוח אפליקציית ריצה: מביקורת ועד מסירה
פיתוח אפליקציית ריצה מתחיל לא בקוד, אלא בניתוח של האופן שבו האפליקציה תתנהג בשטח: ברחוב, ללא חיבור יציב, עם סוללה חלשה ו-GPS פעיל. טעות בארכיטקטורה כבר בהתחלה היא היקרה ביותר — תיקונה נוגע גם בסכימת הנתונים, גם בלוגיקת המעקב וגם בסנכרון. לכן הצעדים הראשונים מוקדשים לדרישות ולמודל הנתונים, ולא לממשק.
מכאן העבודה מתקדמת בשלבים, שכל אחד מהם מסתיים בתוצאה ניתנת לבדיקה:
- ביקורת דרישות — מגדירים את התרחישים: הקלטת מסלול, השהיה/חידוש, השהיה אוטומטית בעצירה, עבודה ברקע, סנכרון לאחר אובדן רשת. בפלט — רשימת פונקציות ומגבלות מוסכמת.
- סכימת נתונים וארכיטקטורה — מתכננים אחסון של נקודות המסלול, מדדים (קצב, דופק, מרחק) ותור שליחה במצב לא מקוון. קובעים מה מחושב במכשיר ומה בשרת.
- הגדרת המעקב — בחירת מצב מיקום גאוגרפי, תדירות הקלטת נקודות, סינון "רעידות" GPS בהתחלה ובסביבה בנויה צפוף. כאן גם — עבודה ברקע והתנהגות נכונה בעת מזעור.
- בדיקה על מסלולים אמיתיים — בודקים לא במשרד, אלא בשטח: יער, מנהרה, סביבה בנויה צפוף, ריצה ממושכת. משווים את המסלול המוקלט למופת, בודקים צריכת סוללה ואובדן נקודות.
- מסירת הפרויקט — קוד מקור, סכימת נתונים, הוראות לבנייה ולהוצאה לאור, גישות לשירותים, תיעוד של המודולים המרכזיים.
שלב נפרד — קבלה: הרצה לפי רשימת תרחישים יחד עם הלקוח, כדי שהתנהגות האפליקציה במסלול תתאים לציפיות לפני ההוצאה לאור, ולא אחריה.
במה שונה מעקב ברקע מהקלטה במצב פעיל?
מצב הקלטה פעיל הוא כאשר המסך דלוק, האפליקציה בחזית, וזרם הנתונים מהחיישנים עובר ברציפות ובתדירות דגימה מקסימלית. במצב זה המערכת נותנת לתהליך עדיפות, המיקום מתעדכן בכל צעד, המדי תאוצה והגירוסקופ פועלים בתדירות מלאה, והמסלול נרשם ללא הפסקות.
המחיר של דיוק כזה הוא עומס מתמיד על המעבד ועל מודול הרדיו: בשעת ריצה מצב כזה מסוגל לצרוך חלק ניכר מהסוללה, ולכן מחזיקים אותו רק בקטעים קצרים שבהם כל שנייה חשובה.
מעקב ברקע בנוי אחרת לחלוטין. כאשר האפליקציה ממוזערת או המסך כבוי, מערכת ההפעלה מעבירה אותה למצב עבודה נפרד ברקע ומתחילה לנהל בעצמה את תדירות העדכונים. במקום זרם רציף מגיעים עדכונים מקובצים — המערכת מעירה את התהליך לעתים רחוקות יותר, מקבצת אירועים ומוסרת אותם בחבילה.
זה חוסך בסוללה, אך בין ההערות עלולות ללכת לאיבוד נקודות ביניים: בפניות חדות, מתחת לגשרים ובבנייה עירונית צפופה המסלול נעשה גס יותר, והמרחק והקצב — פחות מדויקים.
ההבדל המרכזי הוא במי שמקבל את ההחלטה לגבי תדירות הדגימה. במצב פעיל זו האפליקציה, ובמצב רקע — מערכת ההפעלה, בהתאם למדיניות חיסכון באנרגיה ולמצב המכשיר הנוכחי.
מכאן גם תרחישים שונים: מצב פעיל מתאים לאימוני אינטרוולים ולריצות קצרות שבהן נדרש דיוק של שנייה, ומצב רקע — למרחקים ארוכים שבהם חשוב יותר שהטלפון ישרוד עד הסיום.
בפועל, פיתוח נכון של אפליקציית ריצה אינו בוחר מצב אחד, אלא עובר ביניהם לפי תנאי. כל עוד המשתמש מסתכל על המסך — מתבצעת הקלטה פעילה; המסך כבה — האפליקציה עוברת למצב רקע עם תדירות עדכונים סבירה, ובחזרה לפעילות היא משלימה את המסלול לפי החוצץ שנצבר. בנוסף מחליקים את הנתונים במסננים ומסננים חריגות, כדי שקפיצות GPS לא יקלקלו את המרחק הסופי.
בדיוק משום כך עבודה תקינה של האפליקציה ברקע היא לא הגדרה אחת, אלא שילוב של פתרונות: הרשאות למיקום ברקע, טיפול בהשהיות ובהתאוששות לאחר מזעור, חוצץ נקודות וסנכרון מדויק עם השרת. טעות בכל אחת מהחוליות נותנת או מסלול קרוע, או טלפון פרוק באמצע המרחק.
מקרה בוחן: איך צמצמנו את אובדן הנקודות ב-40% והאצנו את הסנכרון
הלקוח הגיע עם אפליקציית ריצה עובדת: מסלול המסלול נכתב במכשיר, ובעת הופעת רשת נשלח לשרת במנות. בריצות ארוכות באזורי יער וברכבת התחתית, ההפעלה נותקה, המאגר התמלא, וחלק מהמסלול אבד ללא אפשרות שחזור — המשתמש ראה "חור" במסלול ועזב למתחרה.
לפי הלוגים, שיעור הנקודות האבודות הגיע עד 12% בריצות ארוכות משעה וחצי, והסנכרון לאחר שחזור הרשת ארך עד 40 שניות, וחסם את הממשק.
מה שינינו בהקלטה ובהעברת המסלול
הפרדנו בין ההקלטה לשליחה: הנקודות נכתבות לאחסון המקומי של המכשיר בזרימה, עם תיעוד כל אחת ביומן לפני אישור הכתיבה לדיסק. השליחה מתבצעת בערוץ נפרד — במנות קטנות עם מזהים אידמפוטנטיים, כך ששליחה חוזרת לאחר ניתוק אינה יוצרת כפילויות. התור מוגבל בגודלו, לא בזמן: בעת הצפה מפונים נקודות שכבר אושרו, ולא נקודות טריות.
מה קרה לפי המדדים
שיעור הנקודות האבודות ירד מ-12% ל-7% — כלומר 40% פחות, וכמעט כל האובדן הנותר נובע ממקרים שבהם המשתמש סוגר את האפליקציה בכפייה. הסנכרון לאחר שחזור הרשת הצטמצם מ-40 ל-6 שניות: המנות נשלחות במקביל, ולא בדיוק אחת-אחת.
יציבות ההפעלה עלתה — ניתוקים בריצות ארוכות משעתיים פחתו פי שלושה, מכיוון שהמצב ברקע אינו תלוי עוד בבקשה ארוכה אחת.
| היה | הפך ל |
|---|---|
| אובדן נקודות — 12% | 7% (−40%) |
| סנכרון — עד 40 שנ' | עד 6 שנ' |
| ניתוקי הפעלה בריצות ארוכות — קו בסיס | פי שלושה פחות |
הכלי המרכזי כאן — התור המקומי עם כתיבה אידמפוטנטית: הוא הופך את "לשלוח ולקוות" ל"לרשום ולשלוח מחדש". לבקרת שלמות המסלול השווינו את המסלולים המשוחזרים עם רשומות ייחוס מהשעון — הפער במרחק הסתכם בשברי אחוז.
WorkManager
ספקות לגבי תאימות, מיגרציה והרשאות — מפרקים לגורמים
לפני תחילת הפיתוח של אפליקציית ריצה כמעט תמיד עולות אותן שאלות: איך השירות החדש יסתדר עם התשתית הקיימת, מה יקרה לסטטיסטיקת האימונים שנצברה, האם ניתן לבצע rollback לשחרור אם משהו ישתבש, ומי יקבל הרשאות לפרודקשן.
אלה לא פורמליות — דווקא כאן האינטגרציות נשברות לרוב, ולכן אנחנו מפרקים כל סעיף עד לשורת הקוד הראשונה.
תאימות עם התשתית הקיימת. הלקוח המובייל מתקשר עם הבקאנד דרך API עם גרסאות, ולכן גרסאות ישנות של האפליקציה ממשיכות לעבוד עד שהמשתמשים יעדכנו. אם כבר יש לכם חשבונות, שער תשלומים או שירות אימות — אנחנו מתחברים אליהם דרך אדפטרים, בלי לשכתב מערכות עובדות. את סכמת התאימות מתעדים במסמך לפני תחילת העבודה.
מיגרציה של נתונים. היסטוריית ריצות, מסלולי GPS, אזורי דופק ופרופילים מועברים לפי תוכנית שסוכמה מראש: תחילה ריצת ניסיון על עותק, השוואת checksums, ואחר כך העברה לנתוני הייצור. גם מיגרציה הפוכה נכללת — אם יהיה צורך לחזור למערכת הקודמת, הנתונים לא יאבדו.
Rollback של שינויים. כל שחרור הוא גרסה נפרדת עם אפשרות לחזור לקודמת. עדכונים מופצים בהדרגה, לחלק מהקהל, כדי לתפוס בעיה לפני שחרור המוני.
מה יקרה לאפליקציה אם המשתמשים לא יעדכנו?
גרסאות ישנות ממשיכות לעבוד עם ה-API הקודם. אנחנו תומכים בתאימות לאחור לפחות למספר שחרורים קדימה, ועדכון כפוי מופעל רק בשינויים קריטיים — ומתריעים למשתמשים מראש.
הרשאות וזכויות. פרודקשן, סטייג'ינג ומאגרי קוד — בשליטתכם: אתם הבעלים של החשבונות, ואנחנו עובדים לפי תפקידים שהוקצו עם הרשאות מוגבלות. כל הפעולות מתועדות ביומן, וניתן לשלול הרשאות בכל רגע.
מה תקבלו לידיים בסיום:
- קוד המקור של האפליקציה ושל צד השרת במאגר שלכם;
- סכמת אינטגרציות עם השירותים הקיימים;
- תיעוד למיגרציה ול-rollback של נתונים;
- סביבות מוגדרות ומדיניות הרשאות;
- הוראות לבנייה, פרסום ועדכון שחרורים;
- נוהל תמיכה והעברת זכויות בעלות.
תארו את התשתית הנוכחית שלכם ואת המשימה — נחזור עם הערכה ותוכנית עבודה.
לוחות זמנים של שלבי ההטמעה: מה קורה ומתי
פיתוח אפליקציית ריצה מתחלק לשלבים עם גבולות ברורים: אחרי כל שלב רואים תוצאה ואפשר לתקן כיוון בלי לעצב מחדש את מה שכבר מוכן. לוחות הזמנים המשוערים שלהלן — עבור טראקר טיפוסי עם הקלטת מסלול, סטטיסטיקה, סנכרון עם התקנים לבישים וחשבון אישי.
תוכנית העבודה המדויקת נקבעת לאחר ביקורת: עליה משפיעים מספר הפלטפורמות, עומק האינטגרציות והדרישות למצב לא מקוון.
לוחות הזמנים של ההטמעה מתקצרים אם משחררים תחילה פלטפורמה אחת ומוסיפים את השנייה לאחר בדיקת השערות על משתמשים חיים. במקביל מכינים את התשתית: בילד, בדיקות אוטומטיות, ערוצי עדכונים — זה מסיר פעולות ידניות בכל שחרור.
מה אם צריך השקה עד תאריך? מרכיבים גרסה ראשונה מצומצמת עם הליבה ודוחים את המשני, בלי לגעת בארכיטקטורה — ההרחבה מתבצעת בלי כתיבה מחדש.
מה אם הדרישות ישתנו בתהליך? את תוכנית העבודה מרכיבים מחדש בגבול השלב, את ההיקף ולוחות הזמנים מתאמים מחדש.
תארו את המשימה — נחזור עם הערכה ותוכנית לפי שלבים.







