הבלוג של ינון פרק

טיפים קצרים וחדשות למתכנתים

זיהוי נפילות באפליקציה בתוך Docker

28/04/2019

כל מערכת שאתם מפעילים עלולה להגיע למצבים מביכים כשהיא פוגשת את העולם האמיתי. לפעמים עומסים, לפעמים באגים ולרוב שילוב של שניהם יגרמו למערכת שלכם להיתקע או להתרסק. לדוקר יש מנגנון אוטומטי שמזהה נפילות מסוג זה וגם יפעיל מחדש את האפליקציה כשזה קורה כדי שאף אחד לא ישים לב לפאדיחה. זה נקרא Health Check ובוא נראה איך זה עובד.

המשך קריאה

שילוב מספר מיכלים

27/04/2019

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

ההמלצה בקהילת הדוקריסטים היא לכן להפריד את המערכת שלכם למספר מיכלים, כאשר כל מיכל אחראי על חלק אחר במערכת ויכול תיאורטית לרוץ על מכונה נפרדת. כך בסיס הנתונים ישב במיכל משלו, כל Micro Service יקבל מיכל, רדיס במיכל משלו וגם Memcached במיכל נפרד.

אבל כשאנחנו מפרידים את המערכת שלנו למיכלים אנחנו מייצרים סיבוך אחר: הצורך לארגן את המיכלים יחד לריצה בצורה מתואמת, ולהתמודד עם אילוצים של חלקים שונים במערכת.

ב Docker מיכל שאמור לרוץ בסביבת ייצור כחלק ממערכת גדולה יותר נקרא Service. כמו שהקובץ Dockerfile הגדיר מה יש לנו בתוך מיכל, כך יש קובץ מקביל בשם docker-compose.yml שאחראי על הגדרת הסרביסים במערכת. לכל סרביס נרצה להגדיר על איזה מכונות מותר לו לרוץ, מהם מיפויי הפורטים שלו ואילוצים שונים של הסרביס (למשל שסרביס מסוים חייב לרוץ על מכונה מסוימת, או לא יכול לתפוס יותר מכמות מסוימת של זיכרון).

המשך קריאה

לו היה לי פטיש

26/04/2019

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

מקומי מחנה את הרכב, מפעיל פנגו ומתחיל לשלם על חניה. הכל טוב.

תייר מחנה את הרכב, מחפש להוריד את פנגו (שלהם נקרא איזיפארק), מגלה שזה מעל 80 מגה, שורף את החבילת גלישה ומחכה שעות כי הקליטה לא משהו בשביל אותו פינוק. ובשעות האלה אפשר לשאול - למה דווקא אפליקציה? הרי QR Code שמפנה לדף תשלום היה עובד הרבה יותר טוב. פשוט מדביקים את הקוד ליד השלט של איזיפארק, מזינים בטופס מספר רכב ומספר כרטיס אשראי ומשלמים.

ואנחנו הרי יודעים את התשובה- אפליקציה כי ככה כולם עושים, אפליקציה כי כבר יש לנו אחת, אפליקציה כי צריך לאסוף מידע על המשתמשים וזה יותר קל אחרי שהם נרשמים. אפליקציה, אפליקציה כי זה מה שאנחנו מכירים.

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

תסכול

25/04/2019

ילד קטן מנסה להרכיב פאזל שגדול עליו, מתעצבן וזורק את כל החלקים לכל הכיוונים. ואתה רואה את זה ולא מבין - למה רגש כל כך חשוב כמו תסכול צריך להיות משהו שגורם לנו להרגיש כל כך רע.

הדחף לזרוק את החלקים לכל כיוון לא עובר עם הגיל. גם מבוגרים מרגישים תסכול והרבה מאיתנו יתאמצו מאוד כדי להימנע ממנו.

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

אז כן תזרקו בשמחה את כל החלקים של הפאזל לכל הכיוונים, תשברו את הגיטרה (או את מסך המחשב). ואז תקחו אוויר, תאספו הכל ותנסו שוב. זאת בדיוק הדרך.

מכונות דוקר שאתם יכולים לקחת

24/04/2019

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

המשך קריאה

צעד ראשון עם דוקר

23/04/2019

דוקר (Docker) הוא אחד הכלים השימושיים ביותר למפתחים של פרויקטים מכל הגדלים בשלבי הפיתוח, הבדיקות וה Production. בואו ניקח צעד ראשון יחד כדי להכיר את הכלי ולראות אם שווה לשלב אותו גם בפרויקט שלכם.

המשך קריאה

סדרי עדיפויות

22/04/2019

״אם רק היו לי עוד שעתיים ביום...״ ״אם רק היה לי עוד מתכנת בצוות...״

אנחנו אוהבים לדמיין שעם יותר משאבים היינו מספיקים לסיים את כל העבודה בזמן והמוצר היה עובד פיקס. הניסיון מוכיח ההפך - אנחנו תמיד צריכים עוד שעתיים ביום בשביל לסיים את הבאגים האחרונים. וזה בכלל לא משנה כמה זמן יש לך.

בגלל זה הכתבה הזאת של אורנה רודי נשמעה צורמת:

https://www.globes.co.il/news/article.aspx?did=1001282616

הטענה שצריך לעבוד 12 שעות ביום מבוססת על איזה צירוף מקרים מוזר בביולוגיה שלפיו סדר גודל של 12 שעות זה המקסימום שאנחנו מצליחים לעבוד. אבל למה 12 ולא 8? או 4? או 15?

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

הבחירה לעשות את מה שחשוב היא הרבה יותר חשובה להצלחה שלכם מתוספת של עוד שעתיים עבודה ביום.

שיתוף קוד באמצעות גנרטורים

21/04/2019

ג'נרטורים יכולים להציע דרך חשיבה מקורית על בעיות, כולל על בעיות של העולם האמיתי, דרך שבגלל שאנחנו לא רגילים אליה היא לא תהיה הדבר הראשון שיקפוץ לראש אבל לפעמים שווה להתאמץ. הנה דוגמא קטנה שאולי תעזור.

נניח שאנחנו רוצים לכתוב תוכנית שמקבלת 5 מספרים מהמשתמש ומדפיסה את המספר הגדול ביותר. נקודת התחלה טובה היא הפונקציה get_numeric_input שתיקח מספר מהמשתמש:

def get_numeric_input(prompt):
    while True:
        try:
            return int(input(prompt))
        except ValueError as e:
            print("Sorry, only integers are allowed. Please try again")

עכשיו אני יכול להפעיל אותה בלולאה 5 פעמים ולהדפיס את המספר הגדול ביותר:

values = []
for i in range(5):
    values.append(get_numeric_input("Please select a number: "))
print(max(values))

וזה עובד יופי רק הבעיה שכל ה-5 מספרים נשמרים בזיכרון. במספרים גדולים זה סתם בזבזני ומספיק לשמור רק את המספר הגדול ביותר שראינו עד עכשיו. נעדכן את הלולאה ואז הקוד מתחיל להיות מסורבל:

res = get_numeric_input("Please select a number: ")
for i in range(4):
    res = max(get_numeric_input("Please select a number: "), res)

print(res)

יש כאן שם של משתנה שהייתי צריך להמציא (res), והקריאה לפונקצית ה input מופיעה פעמיים.

דרך אחרת להגיע לאותו פיתרון היא לעטוף את הפונקציה ב Generator:

def user_numeric_input(prompt):
    while True:
        yield get_numeric_input(prompt)

עכשיו קריאת 5 מספרים והדפסת הגדול ביניהם הופכת לשורה הבודדת:

print(reduce(max, islice(user_numeric_input("Please select a number: "), 5)))

בצורה כזאת אני לא צריך לשבור את הראש ולהמציא שם מיותר למשתנה וגם פונקציית ה input מופעלת רק ממקום אחד.

באג או פיצ'ר

20/04/2019

בעיה אמיתית בעבודה עם לקוחות היא זיהוי ההבדל בין באג לפיצ'ר, וזה נכון במיוחד לפרילאנסרים. אנחנו נותנים הצעת מחיר גלובאלית לפיתוח ומסכמים עם הלקוח את כל הפיצ'רים, הלקוח בטוח שהוא יקבל בדיוק את מה שכתוב במסמך האיפיון ובפועל משהו לא עובד כמו שהלקוח תכנן.

אם זה "באג" אז הפרילאנסר אשם, וצריך לתקן את המערכת "על חשבונו" ואולי אפילו לפצות את הלקוח שמרגיש מרומה.

אם זה "פיצ'ר" שהלקוח שכח לציין במסמך האיפיון אז הלקוח אשם וצריך להוסיף כסף בשביל לקבל את הפיתוח הנוסף.

הדינמיקה הזאת הרסנית לשני הצדדים.

מודל תשלום אחד יותר חכם לעבודה עם לקוחות הוא ריטיינר, שאומר שהלקוח משלם סכום קבוע כל חודש ובתמורה הפאילנסר עושה מאמץ לתקן כמה שיותר תקלות ולהוסיף כמה שיותר פיצ'רים לפי מה שהלקוח צריך באותו חודש. הבעיה כאן שלקוח יכול ליפול עליכם עם המון פיצ'רים ותיקונים עד שלא תוכלו לעמוד בעומס, או שפרילאנסר יכול לעבוד לאט ולא תקבלו ממנו תוצאות.

אפשר לשפר את זה אם מוסיפים קצת מגבלות, למשל:

  1. אשמח לבנות לך אתר במחיר הקמה של X ש"ח. אנחנו מסכמים על תאריך (דדליין) שבו העבודה מסתיימת והאתר עולה לאוויר לא משנה מה.

  2. אני אקצה לך גם אחרי שהאתר באוויר שעתיים-שלוש בשבוע לעדכונים ותיקונים קטנים באתר אם תצטרך. העלות היא Y ש"ח לחודש.

  3. אני אקצה לך מדי פעם שבוע שלם של עבודה מרוכזת רק על האתר שלך כדי לתקן ולעדכן דברים יותר גדולים. עלות שבוע כזה היא Z ש"ח ואני מוכר שבועות כאלה על בסיס זמינות אז כנראה תצטרך לתאם איתי כמה שבועות מראש.

בצורה כזאת זה לא משנה אם הבעיה היא באג או פי'צר שפספסנו במסמך האיפיון. אנחנו שמים את כל האילוצים של שני הצדדים על השולחן ועושים מאמץ לבנות מערכת תמריצים בריאה יותר.

שאלות מראיונות עבודה: Docker

19/04/2019

מתכנת שלא טורח לקרוא תיעוד כתב את ה Dockerfile הבא:

FROM ubuntu:18.04

RUN apt-get update
RUN apt-get install nodejs
RUN apt-get clean

מה המתכנת ניסה להשיג? למה הוא לא הצליח? ואיך הייתם מתקנים את הבעיה?

רמז? כדאי לקרוא את התיעוד של דוקר על שכבות בקישור:

https://docs.docker.com/v17.09/engine/userguide/storagedriver/imagesandcontainers/#container-and-layers