ToCode
1.41K subscribers
3.31K links
טיפים קצרים למתכנתים מאת ינון פרק
Download Telegram
# בניתי לבד
פעם כמעט בכל דבר היית צריך לפנות לאיש מקצוע, אבל בעולם של היום ממש קל ללמוד משהו מהר ובחינם כדי לפתור לעצמך את הבעיות לבד - החל מתיקון רדיו ישן ועד תיקונים באוטו, הכל נמצא ביוטיוב. ועדיין חשוב לשים לב למטרות כשאנחנו באים לפתור בעיה.

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

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

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

אחרי קצת חיטוט בשרת מצאתי שאחד מתהליכי הרקע התחיל להשתולל ולאכול CPU Time. התהליך רץ ב nice לכן זה לא ממש מפריע לאף אחד, כי אם יש עומס אמיתי על השרת ממילא תהליך זה יוקפא. אבל מסתבר שללינוד זה עדיין מפריע: כשהשרת ב idle אותו תהליך כבד לוקח 99% מזמן המעבד וזה מדליק את נורות האזהרה.

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

$ apt-get install cpulimit


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

sudo cpulimit -b -l 50 -p 27085


המתג -b גורם ל cpulimit לרוץ ברקע, המתג -l מקבל מספר וזה אחוז המעבד המקסימלי שהתהליך יקבל והמתג -p מקבל מזהה תהליך לנטר.

ובשביל להשתמש ב nice וב cpulimit יחד אנחנו יכולים לכתוב סקריפט קצר בסגנון הבא:

nice my_busy_script.py &
pid=$!
cpulimit -b -l 50 -p "$pid"
wait


הפקודה האחרונה wait ממתינה לביצוע כל פעולות הרקע כך שהסקריפט שמריץ יסתיים רק כאשר my_busy_script יסתיים.
# מה פייתון עושה באמת
הרבה פעמים מעניין להסתכל מתחת למכסה המנוע (באוטו וגם בקוד) כדי להבין מה המחשב עושה באמת. בעבודה עם Python יש לנו מודול בשם dis שעוזר לספק את הסקרנות שלנו וגם לפעמים למצוא שגיאות או בעיות ביצועים.

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

def main():
print("Hello World")


נוסיף את המודול dis לתוכנית ונבקש ממנו לפרק את הפונקציה כך שהתוכנית המלאה תיראה כך:

import dis

def main():
print("Hello World")

dis.dis(main)


והפלט:

  4           0 LOAD_GLOBAL              0 (print)
2 LOAD_CONST 1 ('Hello World')
4 CALL_FUNCTION 1
6 POP_TOP
8 LOAD_CONST 0 (None)
10 RETURN_VALUE


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

נראה אחד יותר מורכב:

import dis

def greet(n):
for i in range(n):
print("hello world")


dis.dis(greet)


והפלט:

  4           0 SETUP_LOOP              24 (to 26)
2 LOAD_GLOBAL 0 (range)
4 LOAD_FAST 0 (n)
6 CALL_FUNCTION 1
8 GET_ITER
>> 10 FOR_ITER 12 (to 24)
12 STORE_FAST 1 (i)

5 14 LOAD_GLOBAL 1 (print)
16 LOAD_CONST 1 ('hello world')
18 CALL_FUNCTION 1
20 POP_TOP
22 JUMP_ABSOLUTE 10
>> 24 POP_BLOCK
>> 26 LOAD_CONST 0 (None)
28 RETURN_VALUE


כאן כבר יש לנו שתי שורות קוד שהופכות ל-15 פקודות מכונה. שימו לב לפקודת ה JUMP_ABSOLUTE ול FOR_ITER שיחד מייצרות את הלולאה ולקריאה לפונקציה range בשביל לקבל את הטווח.

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

import dis

counter = 0

def one():
counter += 1
print(counter)

dis.dis(one)


הפונקציה מוסיפה 1 למשתנה גלובאלי, אבל רק כשאנחנו מסתכלים עליה ב dis אפשר לראות שהפעולה += בעצם מורכבת ממספר פעולות:

  6           0 LOAD_FAST                0 (counter)
2 LOAD_CONST 1 (1)
4 INPLACE_ADD
6 STORE_FAST 0 (counter)

7 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (counter)
12 CALL_FUNCTION 1
14 POP_TOP
16 LOAD_CONST 0 (None)
18 RETURN_VALUE


קודם כל טוענים את counter לזיכרון, אחרי זה מוסיפים 1 ובסוף שומרים חזרה את התוצאה. זה מעניין כי עכשיו שראינו את זה אנחנו יודעים להיזהר ולא להפעיל את האופרטור מתוך מספר Threads במקביל, אחרת אנחנו עלולים לקבל Race Condition ולסיים עם תוצאה לא נכונה.

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

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

def main():
print("Hello World")


נוסיף את המודול dis לתוכנית ונבקש ממנו לפרק את הפונקציה כך שהתוכנית המלאה תיראה כך:

import dis

def main():
print("Hello World")

dis.dis(main)


והפלט:

  4           0 LOAD_GLOBAL              0 (print)
2 LOAD_CONST 1 ('Hello World')
4 CALL_FUNCTION 1
6 POP_TOP
8 LOAD_CONST 0 (None)
10 RETURN_VALUE


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

נראה אחד יותר מורכב:

import dis

def greet(n):
for i in range(n):
print("hello world")


dis.dis(greet)


והפלט:

  4           0 SETUP_LOOP              24 (to 26)
2 LOAD_GLOBAL 0 (range)
4 LOAD_FAST 0 (n)
6 CALL_FUNCTION 1
8 GET_ITER
>> 10 FOR_ITER 12 (to 24)
12 STORE_FAST 1 (i)

5 14 LOAD_GLOBAL 1 (print)
16 LOAD_CONST 1 ('hello world')
18 CALL_FUNCTION 1
20 POP_TOP
22 JUMP_ABSOLUTE 10
>> 24 POP_BLOCK
>> 26 LOAD_CONST 0 (None)
28 RETURN_VALUE


כאן כבר יש לנו שתי שורות קוד שהופכות ל-15 פקודות מכונה. שימו לב לפקודת ה JUMP_ABSOLUTE ול FOR_ITER שיחד מייצרות את הלולאה ולקריאה לפונקציה range בשביל לקבל את הטווח.

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

import dis

counter = 0

def one():
counter += 1
print(counter)

dis.dis(one)


הפונקציה מוסיפה 1 למשתנה גלובאלי, אבל רק כשאנחנו מסתכלים עליה ב dis אפשר לראות שהפעולה += בעצם מורכבת ממספר פעולות:

  6           0 LOAD_FAST                0 (counter)
2 LOAD_CONST 1 (1)
4 INPLACE_ADD
6 STORE_FAST 0 (counter)

7 8 LOAD_GLOBAL 0 (print)
10 LOAD_FAST 0 (counter)
12 CALL_FUNCTION 1
14 POP_TOP
16 LOAD_CONST 0 (None)
18 RETURN_VALUE


קודם כל טוענים את counter לזיכרון, אחרי זה מוסיפים 1 ובסוף שומרים חזרה את התוצאה. זה מעניין כי עכשיו שראינו את זה אנחנו יודעים להיזהר ולא להפעיל את האופרטור מתוך מספר Threads במקביל, אחרת אנחנו עלולים לקבל Race Condition ולסיים עם תוצאה לא נכונה.

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

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

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

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

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

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

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

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

1. חומות הגנה בין יישומים שונים ובין Services שונים.

2. מנגנונים של זיהוי אוטומטי כש Service או מכונה מתחילים להתנהג בצורה חשודה.

3. מתודולוגיות של התאוששות מפריצה מרגע שזיהינו אותה - שזה כולל גיבויים, יכולת להחזיר מהר את המערכת לאוויר ויכולת לסגור מהר חשבונות שנפרצו.
# למה בחרת להיות פרילאנסרית?
השאלה הזאת "למה בכלל פרילאנס?" אולי נשמעת בנאלית אבל התשובה אליה עשויה לקבוע את כל המסלול שלך, תחושת ההצלחה שלך המאמץ שתשקיעי וההצלחה עצמה שתגיעי אליה.

האם רצית להרוויח הכי הרבה שאת יכולה?

האם רצית יותר גמישות כדי להיות עם הילדים?

האם חלמת לעבוד מכל מקום בעולם?

האם כדי לקדם נושא שקרוב ללבך?

או שסוג העבודה שאת חולמת לעשות לא זמין לשכירים?

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

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

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

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

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

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

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

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

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

ובכל זאת אחרי כמה חודשים ולאט לאט הוא התחיל למצוא את היתרונות בעבודה עם גיט, ואיתו לאט לאט עוד כמה אנשים בצוות. וכך מצוות של עשרה אנשים מספר האנשים שבחרו להתאמץ עם גיט עלה: מאחד לשניים, משניים לשלושה ובסוף התייצב על שישה. עם המתכנתים גם חלק מהפרויקטים עברו להיות מנוהלים בגיט בלבד (במקום ב SVN), וזה שכנע עוד שניים לעשות מאמץ וללמוד את הכלי.

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

האם אני רוצה להיות החבר שמביא את הכלי החדש?

האם אני רוצה להיות החברה שלומדת ראשונה ועוזרת לו להטמיע את הכלי?

האם אני מוכן להשקיע רק כשאני רואה שהכלי הזה באמת נותן יותר ערך?

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