באג ריפורט: מחיקה מרובה וחיפוש
פעמיים בתקופה האחרונה נתקלתי באותו באג בשתי מערכות שונות ובשני המקרים עם תוצאה הרסנית, וזה לבד מצדיק פוסט קטן בתקווה שיעזור גם לכן להימנע מבעיות דומות.
טיפים קצרים וחדשות למתכנתים
פעמיים בתקופה האחרונה נתקלתי באותו באג בשתי מערכות שונות ובשני המקרים עם תוצאה הרסנית, וזה לבד מצדיק פוסט קטן בתקווה שיעזור גם לכן להימנע מבעיות דומות.
איך ללמוד Java? איך מתחילים ללמוד React? איך אני הופך למתכנת Node.JS? איך אני לומד להיות מתכנת אוטומציה? כל שאלה כאן היא שאלה ענקית כי היא מסתכלת על יעד רחוק שיש המון דרכים להגיע אליו, ועל כזה שאין מסלול ברור אליו.
אם אני מחליט לקחת את "איך בתור בודק ידני אני עובר ללמוד לכתוב בדיקות אוטומציה למערכות ווב" בתור דוגמה, אני מגלה שאני צריך:
ללמוד איך בנויה אפליקציית Web (כולל HTML, CSS וקצת JavaScript)
ללמוד איך עובד קוד צד שרת ומה הקשר בין Front End ל Back End
ללמוד על פרוטוקולי תקשורת ובמיוחד HTTP
ללמוד שפת תכנות כלשהי איתה אכתוב את הבדיקות
ללמוד איך להשתמש ב Selenium ולכתוב בדיקות בשפת התכנות שבחרתי
וכל סעיף פה ברשימה נפתח לתת רשימה נפרדת משלו - והכי גרוע, האורך של כל רשימה משתנה לפי הדברים שאני היום יודע והזמן שיש לי. אז בדוגמה של בדיקות אוטומטיות יכול להיות שאני אצטרך להשקיע יותר זמן בהכרת המבנה של Web Applications, ומישהו אחר יצטרך להשקיע את עיקר הזמן בלימוד Python ומישהו שלישי בכלל יסתבך עם ה Selenium.
דרך טובה להתחיל ללמוד נושא חדש היא לא להסתכל על הנושאים אלא לבנות רשימה (או למצוא רשימה מוכנה או להיעזר בחבר לצורך הבניה) שמכילה 7 מטלות ספציפיות שיקדמו אתכם ליעד. דברים כמו-
לכתוב ולהריץ תוכנית Hello World בשפת פייתון.
לכתוב תוכנית בשפת Python שמדפיסה את כל המספרים הזוגיים.
לכתוב דף אינטרנט שמציג מידע עליי.
לכתוב תוכנית פייתון שמושכת מידע משרת מרוחק.
לכתוב תוכנית פייתון שמפעילה דפדפן ובודקת מה הטקסט שמופיע בכותרת של הדף.
להריץ את התוכנית שכתבתי בצורה אוטומטית בתור משימה מתוזמנת.
לקבל אימייל מהתוכנית בסוף ההרצה אם הטקסט הוא לא מה שחשבתי.
אלה 7 משימות שבתור איש QA אני יכול להבין בכל משימה בדיוק מה אני צריך והן נותנות לי משהו להתעסק איתו בשבוע הקרוב. סיכוי טוב שאצליח לבצע חלק מהמשימות שבחרתי, וכמעט בטוח שיהיו כאן משימות "גדולות" עליי, כלומר דברים שחשבתי שאני יכול לעשות אבל אז אני בא לכתוב אותם ומגלה שהם הרבה יותר מסובכים. זה בסדר גמור. מה שחשוב זה שבסוף העבודה על הרשימה יהיה לי מספיק חומר למחשבה לרשימת שבע המשימות הבאות.
כשבוחרים יעד רחוק אי אפשר לראות את סוף הדרך - אנחנו רואים רק עד כמה שהפנס שלנו מגיע. ככל שנתקדם יותר עמוק לתוך המערה נוכל לראות יותר דברים ולמצוא רשימות יותר מעניינות. וכן, בסוף גם ללמוד את הדבר ההוא שבגללו נכנסנו למערה, אם הוא עדיין יהיה מעניין בעוד שלושה או ארבעה חודשים.
יש לי חבר שעובד כבר שנים בהייטק ועד לאחרונה תמיד היה מאוד מתוסכל: הוא אחד המתכנתים המהירים שפגשתי ובעיקרון היה יכול לסיים כל יום עבודה בחצי מהזמן של יום עבודה רגיל, אבל "בשביל מה?" הוא אומר לי מדי פעם, "היית צריך לראות איך מסתכלים עליי אם אני מעז יום אחד לצאת קודם".
וחברה אחרת שמה לב שלא משנה מה היא עושה היא אף פעם לא מצליחה לעמוד בזמנים. זה נראה כאילו תמיד יש יותר עבודה ממה שהיא מספיקה לעשות, לא משנה כמה היא מתאמצת. יומיים בשבוע היא נשארת לעבוד לתוך הלילה לרוקן את הערימה, ולמחרת רשימת המשימות כאילו מתמלאת מעצמה.
למרות ששני המקרים נראים הפוכים, לשני החברים שלי יש בעיה דומה - שניהם מרגישים שאין להם שליטה על הזמן שלהם. שניהם "לא יכולים" לקחת שעה ביום ללמוד טכנולוגיות חדשות כי הבוס מחליט מה מותר ומה אסור.
והסוד? מסתבר שבתקופת הקורונה שניהם גילו שיש להם הרבה יותר שליטה ממה שהם חשבו, וכנראה תמיד היתה. החבר שעובד מהר למד לנצל את הזמן שהוא מרוויח, והחברה שעובדת לאט למדה להתעלם מחלק מההודעות הנכנסות. שניהם בילו בשנה האחרונה הרבה יותר זמן עם המשפחה ממה שאי פעם חשבו שאפשרי.
בואו לא ניתן לסוד הזה להישכח- גם כשאנחנו מתקרבים לחזרה למשרד לפחות לחלק מהשבוע. יש לכם הרבה יותר שליטה על הזמן שלכם ממה שתמיד היה נדמה, וכמו שאפשר לנצל אותה כדי לבלות יותר זמן משפחה, אפשר יהיה (כשהילדים חוזרים למסגרות) לנצל אותה כדי ללמוד טכנולוגיות חדשות, להתחיל לכתוב בדיקות אוטומטיות ולבנות תהליכי עבודה טובים יותר בחברה שלכם.
לפני כמה ימים כתבתי כאן על פיתוח משחק סיימון ב React. בפוסט הצבעתי על הקושי בכתיבת קומפוננטות ריאקט הכוללות אלמנט של זמן או מעבר מורכב בין מצבים. במקרה של סיימון היו לנו את המצבים הבאים:
הקומפוננטה יכולה להיות במהלך הצגת רצף הצבעים האקראי שהמחשב בחר
במהלך הצגת צבע מהרצף יכול להיות שמשתמש ילחץ על אחד הכפתורים ואז נפסיק להציג את הרצף וניתן למשתמש להקליד את הרצף שלדעתו הוא הנכון
אפשרות שניה במהלך הצגת צבע מהרצף היא שאף אחד לא נוגע ואז צריך להמשיך להציג את הצבע הבא
אבל אם אנחנו מציגים את הצבע האחרון ברצף צריך לעצור ולחכות שמשתמש יתחיל להקליד את הרצף שלו או ילחץ על כפתור "הצג שוב"
בנוסף במהלך הצגת הצבעים מהרצף האקראי ובין כל שני צבעים צריך לכבות את כל המנורות לכמה מאיות שניה כדי לתת למשתמש להבדיל בין הצבעים.
אם פספסתם את אותו פוסט אתם מוזמנים לחזור אליו ולראות את המימוש שכתבתי בריאקט למעברי המצבים האלה. אם אתם זוכרים מה הלך שם ומחפשים גישה נוספת לכתיבת קומפוננטות מסוג זה הגעתם למקום הנכון. בפוסט זה אציג את ספריית xstate למימוש מכונת מצבים בסביבת JavaScript ונראה איך היא תעזור לנו בכתיבת משחק סיימון.
אחת הפקודות הפחות מוכרות ב git תוכל לעזור לכם כשתחזרו למשרד, או לפחות לאלה מכם שמחזיקים במשרד מסך גדול ומחפשים סטטיסטיקות להציג עליו. אני מדבר על הפקודה git shortlog שמראה לנו את הקומיטים האחרונים לפי הכותב. פלט לדוגמה בהפעלה ללא מתגים עשוי להיראות כך:
$ git shortlog
ynonp (4)
do stuff
add more stuff
fix the tests of stuff
break some stuff
johndoe (2)
break stuff
fix stuff
בעוד ש log רגיל מתמקד ברצף הקומיטים, ה shortlog מתמקד במתכנתים מאחורי הקומיטים, או לפחות מארגן את הקומיטים לפי מי שכתב אותם.
והתחרות שלנו? הפקודה הבאה מציגה רק את המספרים (בלי פרטי הקומיטים עצמם) של קומיטים מהשבוע האחרון בכל הענפים:
git shortlog -s --branches --since="1 week ago"
ואם אתם מקרינים את זה על המסך הגדול תוכלו להשתמש ב watch כדי לרענן את הפלט פעם ביום בצורה אוטומטית:
watch -n 86400 'git shortlog -s --branches --since="1 week ago"'
אחד האתגרים בכתיב הקומפוננטות של ריאקט הוא יצירת קומפוננטות המושפעות מזמן. ברוב הפעמים זה הגיוני, כי לא היית רוצה שפתאום דברים ישתנו על המסך בלי שמשתמש עשה איזושהי פעולה - זה רק מבלבל. ועדיין, כשאנחנו כן רוצים לכתוב קוד שקשור לזמן כדאי שנדע איך לגשת לזה בלי להתבלבל.
ישבתי היום עם הבת שלי על משחק אותיות פשוט: לקחנו 5 כרטיסיות, כתבנו עליהם את האותיות "ג", "ד", "ו", "ל" ו-"ה" ולימדתי אותה איך להרכיב את המילה "גדולה" (כי היא כבר ילדה גדולה שיודעת אותיות). זה לקח כמה ניסיונות אבל בסוף היא הצליחה ממש טוב להרכיב את המילה, לא משנה כמה ערבבתי את הכרטיסיות ואפילו כשהוספתי כרטיסיות עם אותיות לא קשורות למילה זה לא הפריע לה.
היא הסכימה לכל טריק שרציתי להוסיף למשחק מלבד אחד - רק לא להחליף מילה.
מרגע שהיא קלטה שהיא יודעת להרכיב את המילה "גדולה" היא לא היתה מוכנה לוותר על התחושה של לעשות משהו כמו שצריך. המחשבה על החזרה אחורה לטעויות, לבלבול, לחוסר וודאות פשוט הוציאה לה את החשק ללמוד.
אותו פחד מהחזרה לבלבול, לטעויות ולחוסר הוודאות לא נעלם עם הגיל ולא משתנה כשעוברים ללמוד דברים יותר קשים מאותיות ומילים. הוא שם כשאני מתלבט אם זה זמן טוב עכשיו להיכנס לעולם ה Front End, או אם שווה ללמוד איך עובדים חוזרים חכמים ויודע שכבר מהצעד הראשון בתחום החדש ארגיש את אותו תסכול, אותו בלבול ואותו חוסר וודאות.
הלאה.
למילה הבאה. לטכנולוגיה הבאה. לתחום הבא. כמו שלמדנו את הדבר שאנחנו עכשיו טובים בו, נצליח ללמוד גם את הדבר הבא. ואחרי? נמשיך למילה הבאה כמובן.
אחד הדברים שאנחנו יודעים על תכנות זה שלא תמיד הרעיון הראשון שנגיע אליו יהיה הכי טוב האפשרי, ויותר גרוע, לא תמיד הרעיון הראשון שנגיע אליו יהיה בכלל ישים. זאת אחת הסיבות שלפעמים מביך לצפות ב Live Coding - אתה מסתכל על בן אדם מנסה להתקדם בכיוון שלא יכול לעבוד בגלל מגבלה שהוא עדיין לא הבין אותה, ואתה יודע שעוד רגע הוא הולך להתנגש בקיר וזה הולך לכאוב.
אבל מחוץ ל Live Coding, בעולם האמיתי, החוויה של להתקדם עם רעיון עד שמתנגשים בקיר היא חלק בלתי נפרד מתהליך הלימוד במיוחד של טכנולוגיות חדשות. יש לי איזה כיוון לגבי בחירה טכנולוגית, אני כותב סביבו את הקוד, מכניס למערכת נתונים אמיתיים ורואה איך היא מתרסקת. חלק מהפעמים היא תתרסק בגלל ששכחתי משהו קטן ואני מיד יכול לתקן ולהתקדם, ופעמים אחרות היא תתרסק כי חשבתי שהמידע יעבור ברשת מספיק מהר וראיתי שבעולם האמיתי המערכת עובדת הרבה יותר לאט מאשר בתוכנית שלי.
"לא, אתה לא יכול לכתוב סקריפט שמושך את הנתונים מהאתר ההוא כי יש שם מנגנוני הגנה חזקים" זה לקח טוב שעוזר לנו בפעם הבאה להתחיל מבדיקת מנגנוני ההגנה לפני שרצים לכתוב את הסקריפט. וברגע שהורדתי את הרעיון הזה מהשולחן אני פותח את הדלת לרעיונות חדשים שאולי כן יעבדו טוב יותר.
רוב הפעמים שנצטרך לעשות עבודה על שרת מרוחק נעדיף להשתמש בממשק טקסטואלי כי הוא מהיר ויציב יותר בעבודה ברשת. אבל מדי פעם כן נצטרך לעבוד על תוכנית גרפית או אפילו על שולחן עבודה שלם שרצים על שרת מרוחק. בפוסט זה אציג את שתי הדרכים המרכזיות לעשות את זה.
אתמול פירסמתי מדריך על העלאת קונטיינר דוקר לענן של Microsoft, וכבר כמה אנשים שאלו איך אפשר לפרסם את אותו קונטיינר בענן הגדול יותר של AWS. אז פתחתי את ה AWS CLI וציפיתי להתפנק עם כל הכלים המושקעים של אמזון. לצערי זאת לא היתה החוויה שקיבלתי אבל בכל זאת הצלחתי להגיע לענן וגם לשרוד כדי לספר.
גירסאות עדכניות של docker כוללות מנגנון שנקרא Context. הקונטקסט מספר לדוקר איפה המכונות שצריכות להפעיל את הקונטיינרים יושבות ובאיזה מנגנון אנחנו מדברים עם מכונות אלה (מי ה Orchestrator). לדוקר יש אינטגרציה מובנית עם AWS ועם Azure Devops כך שכל מה שצריך בשביל להעלות קונטיינרים לענן הוא:
ליצור Context ולחבר אותו ל Azure Devops או ל AWS.
להשתמש בפקודות Docker רגילות כדי להפעיל קונטיינרים.
באופן אוטומטי הקונטיינרים ישתמשו בקונטקסט שהגדרנו ויעלו בענן במקום אצלי על המכונה.
ניסוי? בשמחה. אבל קודם נצטרך לעבור את מדיניות האבטחה הדרקונית של אמזון. בתוך קונסולת הניהול יש להיכנס לשירות שנקרא IAM וליצור משתמש חדש. יש במדריך כאן רשימה של כל ההרשאות שאותו משתמש צריך. אני לא מצאתי איך לעשות copy/paste בקלות להרשאות אז בחרתי מרשימת ה Policies מה שנראה לי קשור. סך הכל בשביל משתמש שמצליח להעלות קונטיינרים לענן שלהם הוספתי את ה Policies הבאים:
AmazonEC2FullAccess
IAMFullAccess
AWSAgentlessDiscoveryService
ElasticLoadBalancingFullAccess
AmazonEC2ContainerRegistryFullAccess
AWSCloudMapFullAccess
CloudWatchLogsFullAccess
AmazonECS_FullAccess
AmazonRoute53FullAccess
AWSCloudFormationFullAccess
השיטה של להוסיף הרשאות עד שזה עובד מתאימה לפוסט, אבל לאפליקציה אמיתית כן שווה להתאמץ ולמצוא את ההרשאות המינימליות שאתם צריכים.
אחרי יצירת המשתמש וההרשאות אתם צריכים לחבר אותו לדוקר קומפוז שלכם ובשביל זה נכנסים (עדיין ב IAM) לטאב Security Credentials, בוחרים Create Access Key ומשאירים את החלון עם ה Access Key ID וה Secret פתוח.
משם פותחים בחלון חדש מסוף שורת פקודה ומפעילים משם:
docker context create ecs myawscontext
המילה האחרונה בשורה היא שם ה Context ואפשר לשנות אותה לכל שם שאתם רוצים. בתגובה דוקר ישאל אתכם איך להתחבר ל AWS ואתם תוכלו להגיד לו שיש לכם אסימון גישה ותדביקו את המזהה והסוד במסוף.
בסיום התהליך יהיה לכם Context חדש עבור AWS ואפשר לוודא שזה עבד עם:
$ docker context ls
NAME TYPE DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR
default moby Current DOCKER_HOST based configuration unix:///var/run/docker.sock swarm
myawscontext * ecs (eu-north-1)
שימו לב לשורה השניה מסוג ecs ועם האזור שבחרתם ליצור בו את המכונות.
ההבדל השני בין AWS ל Azure הוא שבעבודה עם AWS חייבים להשתמש ב Docker Compose ולא ניתן להעלות קונטיינר בודד. זה לא סוף העולם כי תמיד אפשר ליצור קובץ docker-compose.yml שמתאים לקונטיינר בודד. הנה הדמו שאני העליתי:
version: "3.9"
services:
web:
image: "nginxdemos/hello"
ports:
- "80:80"
את התוכן שמרתי בקובץ בשם docker-compose.yml
בתיקיה חדשה (זה הקובץ היחיד בתיקיה) והמשכתי להעלות אותו לאמזון עם הפקודה:
$ docker compose up
הפקודה נכשלה באקראי מדי פעם על Timeout-ים, אבל גם לפעמים הצליחה, אז אם אתם מפעילים ומקבלים שגיאה שווה להפעיל פעם שניה בשביל לוודא שזו שגיאה אמיתית. כשהכל עובד תוכלו לראות את התוצאה עם:
$ docker compose ps
NAME SERVICE STATUS PORTS
task/mydockerdemo/cdf554598aab4f1fb3f1685bc074de98 web Running mydoc-LoadB-13SBJMOZQ5M30-224910942.us-east-1.elb.amazonaws.com:80->80/http
שכבר נותן לנו את כתובת המכונה שמריצה את הדמו. גלישה לנתיב שמופיע שם תציג דף פתיחה משרת nginx.
אחרי שהכל עבד אפשר להשתמש ב:
$ docker compose down
כדי להוריד את הסרביסים שיצרתם, או להפעיל מחדש docker compose up
כדי להעלות גירסה חדשה.
ממש שמחתי לראות את העבודה הטובה שעשו ב Docker כדי לייצר ממשק זהה להעלאת קונטיינרים למספר ספקי ענן. למרות זאת קשה להתעלם מהעובדה שהגישה לשרתים של Azure היתה קלה ומהירה יותר. גם אם נתעלם מנושא בחירת ההרשאות - ב Azure היה לי הרבה יותר קל למצוא את ה Instances שנוצרו בממשק הבקרה שלהם ולראות סטטוס של המכונות דרך ממשק ה Web. זמני המתנה לפקודות docker היו קצרים יותר ולא נתקלתי בכישלונות אקראיים שהסתדרו מעצמם. אם היתה תחרות בין עננים אז לפחות בצד של ממשק עם דוקר הענן של מייקרוסופט מנצח בגדול.