ch
Feedback
ToCode

ToCode

前往频道在 Telegram

טיפים קצרים למתכנתים מאת ינון פרק

显示更多
1 419
订阅者
无数据24 小时
-17
+230
帖子存档
ToCode
1 419
# מקום ריק כשהתחלתי ללמד קורסים הפחד הכי גדול שלי היה לסיים את המצגת לפני הזמן. להספיק את כל החומר של הקורס חמש שעות לפני שהקורס אמור להסתיים, ולהיתקע חמש שעות בלי אף שקף. ומאחר והמוח האנושי איפה שרואה בעיות מיד ממציא אינסוף פיתרונות, גם המוח שלי החליט שמה שחייבים לעשות הוא לכתוב עוד שקפים. כמה שיותר שקפים. מספיק שקפים ככה שלא משנה כמה מהר אני אדבר בשיעור, כמה מעט שאלות יהיו או כמה מהר כולם יסיימו את התרגילים - תמיד יהיה עוד נושא שאפשר ללמד. לקח לי זמן להבין שהפיתרון הזה היה יותר גרוע מהבעיה. כי עכשיו במקום שתלמידים יצאו מהשיעור עם הרגשה טובה שהם הספיקו והבינו הכל, כולם תמיד יצאו עם הרגשה שהם לא הספיקו משהו. לכל אחד היה איזה נושא שהוא מצב במצגת האינסופית שלי שדווקא מאוד עניין אותו, והוא לא הבין למה השיעור נגמר בלי שהספקנו לדבר על הדבר המאוד חשוב הזה. לימים למדתי שבעיה דומה קיימת גם בתעשיה. מנהלי פיתוח שפוחדים ממתכנתים שיסיימו לפני הזמן (משאב מבוזבז), מרכזים יותר מדי משימות בכל ספרינט ומתעדפים את המשימות, מתוך כוונה ברורה שלא הכל יבוצע, אבל אם כן יהיה יותר זמן עדיף שתהיה לנו תוכנית מאשר שאנשים ישתעממו. אז בואו נדמיין רגע - מה באמת קורה כשאנשים משתעממים? מה באמת קורה כשאנחנו מרשים לעצמנו לתכנן קצת פחות ממה שאפשר לבצע? בקורסים עשיתי את הניסוי הזה כמה פעמים והתוצאות הפתיעו לטובה. בין הדברים שקרו: 1. אנשים שאלו יותר שאלות - פשוט כי הם הרגישו שהאווירה הרגועה יותר מאפשרת את זה (אין שום חומר שהם "אמורים" להספיק) 2. כשבאמת נשאר זמן פנוי לקראת סוף היום, אנשים העלו נושאים שמעניינים אותם ורצו לשמוע יותר עליהם. 3. וכן לפעמים גם אנשים הלכו הביתה חצי שעה קודם. לפעמים תלמיד אחד או שניים ניצלו את זה שהכיתה התרוקנה ונשארו לשאול אותי שאלות שרלוונטיות לעבודה הספציפית שלהם. בעבודה שוטפת של תכנות, אם יש פחות מדי משימות בספרינט אני יכול לדמיין שמתכנתים יכתבו קוד איכותי יותר, שישקיעו יותר זמן בהתמודדות עם תקלות, בתכנות בדיקות נכונות, בכתיבת תיעוד ובפיתוח תשתיות שיאפשרו המשך פיתוח מהיר. אם יש יותר מדי משימות בספרינט, גם אם משימות מסוימות מוגדרות בתיעדוף נמוך, אנחנו נעדיף לסיים כמה שיותר מהמשימות ברשימה גם על חשבון האיכות. ככה המוח האנושי עובד. נ.ב. אם עשיתם ניסוי כזה בצוות שלכם ונתתם לאנשים יותר חופש פעולה, אשמח לשמוע מה היו התוצאות - מוזמנים לשתף בתגובות פה מתחת לפוסט.

ToCode
1 419
# למה לא לקחתי את דן אברמוב לעבודה לא מזמן ראיתי את הוידאו של בן עוואד שעושה ראיון עבודה פיקטיבי לדן אברמוב. אם לא ראיתם עדיין ובא לכם לראות את דן אברמוב נאבק עם CSS שווה להיכנס לכאן: https://www.youtube.com/watch?v=XEt09iK8IXs. אבל הוויכוח שלי עם דן אברמוב לא היה על CSS אלא על נקודה יותר עדינה של אבטחת מידע. באותו ראיון עוואד שואל את אברמוב מה דעתו על dangerouslySetInnerHTML ואברמוב מגיב באי נחת ניכרת. שניהם מסכימים שמשהו ב API הזה מסורבל וההסבר של אברמוב הוא מעניין. נזכיר רק שב API של ריאקט הם רצו להיות מאוד ברורים כשמישהו פותח דלת לפירצת XSS ולכן במקום לקרוא למאפיין שמעדכן את ה innerHTML של אלמנט במשהו פשוט כמו setInnerHTML הם הוסיפו את המילה dangerously. אבל זה לא הכל. כי בשביל להגדיר את ה innerHTML צריך להעביר למאפיין dangerouslySetInnerHTML אוביקט עם מפתח בשם מיוחד __html, כלומר משהו כזה:
<div dangerouslySetInnerHTML={{ __html: "Hello" }}></div>
הטענה של אברמוב היתה שהבעיה ב API הזה היא שהמילה dangerous היא במקום הלא נכון, ועדיף היה לשים אותה בתור המפתח באוביקט שהמאפיין מקבל, כלומר הוא היה רוצה לראות קריאה כזאת:
<div html={{ __dangerousHTML: "Hello" }}></div>
והסיבה לטענתו היא אבטחה טובה יותר כששני החלקים רחוקים אחד מהשני. לדוגמה נדמיין שבקובץ אחד יש לנו את הפונקציה:
// file utils.js
export function alertHtml() {
    return { __html: "<b>alert</b>" };
}
ובקובץ שני הקטע:
import { alertHtml } from './utils.js';

<div dangerouslySetInnerHTML={alertHtml()}></div>
אם חוקרי אבטחה יריצו grep ויחפשו את המילה dangerouslySetInnerHTML - אז בגירסה הנוכחית של הממשק הם יגיעו לחלק השני, אבל לפי דן אברמוב זה לא החלק שחשוב לחקור, כי החלק הראשון הוא זה שכולל את ה HTML המקורי ושם צריך להסתכל ולראות שה HTML אכן בטוח לשימוש. ואז הבנתי שדן ואני כנראה לא נעבוד יחד. או לפחות לא נסכים על נושאי אבטחת מידע. אחד הכללים החשובים בכתיבת קוד מאובטח הוא לבדוק את הקלט כמה שיותר קרוב לפעולה המסוכנת, כי כמה שתבדוק יותר רחוק דברים רעים יכולים לקרות בין הפונקציה שבה בדקת לבין המקום שבו משתמשים בקלט כדי לעשות איתו פעולה מסוכנת. לדוגמה: 1. אם אני צריך למחוק קובץ, אני אוודא ששם הקובץ מתאים לתבנית שאני רוצה למחוק ושהתיקיה מתאימה לתיקיה שבה אני מוחק קבצים בדיוק לפני המחיקה, ולא כשאני מקבל את הפרמטר מהמשתמש. 2. אם אני צריך לפנות לבסיס הנתונים, אני אעשה Quoting לקלט החיצוני ממש לפני שליחת השאילתה לבסיס הנתונים (רצוי באמצעות שימוש ב Bound Variables). 3. ואם אני צריך לכתוב HTML למסך, אני אוודא שה HTML הזה נקי כמה שיותר קרוב לפקודה שכותבת אותו למסך, כלומר הפוקוס שלי באמת מתחיל בקטע השני במאפיין dangerouslySetInnerHTML.

ToCode
1 419
בדרך כלל pull עושה fetch ואז merge; אבל המתג --rebase גורם ל pull לעשות fetch ואז rebase. וזה מלהיב כי הוא בעצם ייקח את כל השינויים מהענף origin/main אלינו ואז יריץ עליו רק את השינויים שאני עשיתי בענף main שלי. במקרה הראשון הפקודה תזהה שאצלי אין קומיטים בענף ולכן רק תזיז את main למקום הנכון. במקרה השני הפקודה תזיז את main לאן ש origin/main נמצא ואז תנסה "להפעיל מחדש" את השינויים מהקומיטים החדשים יותר. גיט מספיק חכם בשביל לזהות שהקומיט היחיד שיש אצלי שלא נמצא בענף של origin/main הוא היסטורי ויתעלם ממנו והתוצאה תהיה יישור של המאגר המקומי שלי עם המאגר המרוחק. ובמקרה השלישי שוב הפקודה תזיז את main לאן ש origin/main נמצא ואז תפעיל מחדש את הקומיט החדש שאני יצרתי. השינוי יישמר ויקבל מזהה קומיט חדש והמאגר המקומי שלי יישאר לינארי לגמרי.

ToCode
1 419
# מה קורה כשמושכים מאגר שמישהו שינה מרחוק לא מזמן ראיתי חבר מושך מאגר מרוחק ולפני שהפעיל git pull הוא מחק את הענף שאותו הוא רצה למשוך. כששאלתי למה הוא הסביר שהוא יודע שמישהו דחף שינויים עם force ולכן דברים רעים יקרו אם הוא יפעיל pull רגיל (הוא צודק בזה). בסוף הפוסט אראה פיתרון יותר פשוט ממחיקת הענף, אבל בינתיים בואו נדבר קצת על הדברים הרעים שקורים כשמישהו משנה היסטוריה מרחוק: ## אם רק מחקו קומיטים השאלה מה קורה כשאני מושך שינויים לא צפויים קשורה לאיזה שינויים נעשו. נתחיל עם המקרה הפשוט בו מתכנת אחד ביטל את הקומיט האחרון שבענף ודחף את השינוי עם force, ומתכנת אחר מושך את השינויים. כלומר במחשב אחד מריצים:
$ git reset --hard HEAD~
$ git push --force
ושימו לב שאין צורך להפעיל commit כי אני לא יוצר שום שינוי חדש אלא רק דוחף את הענף המרוחק לקומיט אחד אחורה. במחשב השני מריצים:
$ git pull
במצב כזה הפלט של המשיכה יהיה:
From github.com:ynonp/pull-after-change
 + 4db20b1...8ef1cf5 main       -> origin/main  (forced update)
Already up to date.
והלוג יראה בערך כך:
* 4db20b1 (HEAD -> main) add g.txt
* 8ef1cf5 (origin/main, origin/HEAD) replaced e with f
* 2d31fbd replaced c with d
* 24d6085 (dev) initial commit
אנחנו רואים ש origin/main זז קומיט אחד אחורה, והקומיט main עדיין נמצא במחשב השני. אם הקומיט origin/main היה קדימה יותר כמו במצב רגיל, אז גיט היה מבצע Fast Forward Merge ומזיז קדימה את main; אבל לגיט אין מנגנון של Fast Backwards Merge וככה נתקענו שהמחשב שלנו "יותר קדימה" מהקומיט העדכני ביותר בשרת. אם היינו מוחקים מראש את הענף הכל היה מסתדר, ועוד דרך לצאת מזה היא:
$ git reset --hard origin/main
(ובשביל הדרך הכי טובה לצאת מזה תצטרכו להמשיך לקרוא עד לסוף הפוסט). ## אם גם הוסיפו קומיט חדש מצב יותר מבלבל קורה כשהמתכנת במחשב הראשון לא רק מבטל את הקומיט האחרון אלא גם מוסיף קומיט חדש. כלומר משהו כזה:
$ git reset --hard HEAD~

$ date > newfile.txt
$ git add newfile.txt
$ git commit -m 'yay'

$ git push --force
הפעם כשהמתכנת במחשב השני ימשוך את המאגר הוא יגלה שהקומיט העדכני ביותר אינו מוכר לו. נפעיל git fetch מהמחשב השני בשביל להבין את הדוגמה לאט. הלוג נראה כך:
$ git log --oneline --graph
* 2d31fbd (HEAD -> main) replaced c with d
* 24d6085 (dev) initial commit
ולא כולל את origin/master, והלוג מ origin/master נראה כך:
$ git log --oneline --graph
* a346d40 (origin/main, origin/HEAD) add f.txt
* 24d6085 (dev) initial commit
אפשר לראות שהקומיט המשותף לשני הלוגים הוא 24d6085. הצעד הבא של pull הוא merge, וניסיון לעשות merge לשני הענפים יהיה כמו כל merge רגיל, כלומר גיט יזהה את השינויים שכל אחד עשה מ 24d6085 וישלב אותם לקומיט חדש. וזה ממש לא מה שצריך לעשות. כי merge כזה בעצם משלב את השינויים שיש אצלי (שב remote נמחקו) עם הקומיט החדש מה remote, ויכניס בחזרה את אותם קבצים או שינויים שמישהו מרחוק ניסה למחוק. אנחנו לא צריכים כאן merge אלא reset - להעביר את הענף main שלנו שיהיה מיושר עם origin/main, ולהעיף את הקומיט 2d31fbd גם מהמכונה שלי. ## ואם גם המתכנת השני הוסיף קומיט חדש הסיפור יכול להסתבך עוד יותר אם המתכנת במחשב השני גם מוסיף קומיטים חדשים לפני שמבצע pull. הנה לוג של סימולציה זריזה של מצב כזה, קודם כל מהענף main המקומי:
$ git log --oneline --graph
* d96ebe5 (HEAD -> main) changed a.txt
* a346d40 add f.txt
* 24d6085 (dev) initial commit
ומהענף origin/main:
$ git log --oneline --graph origin/main
* 6b84f15 (origin/main, origin/HEAD) add g.txt
* 24d6085 (dev) initial commit
הפעם יש לנו שני קומיטים חדשים בענף main המקומי וקומיט אחד חדש ב origin/main. פעולת merge תנסה לשלב את שני הקומיטים ותתן לנו גם את השינויים ב a.txt אותם אנחנו רוצים, וגם את השינויים ב f.txt אותם אנחנו לא רוצים. בשביל לצאת מזה אי אפשר לעשות git reset כי אז נאבד את הקומיט d96ebe5. נוכל להשתמש ב reset ואחריו cherry pick, או בקסם של הסעיף הבא. ## פיתרון: git pull --rebase עכשיו שאנחנו מבינים מה יכול להשתבש אפשר לדבר על הפיתרון של גיט לעניין ומסתבר שהוא מאוד פשוט. זו הפקודה המובנית:
$ git pull --rebase

ToCode
1 419
# שלוש סיבות שהתוכנית שלך לא עובדת מחשבים הם יצורים מאוד ממושמעים. תגיד למחשב לעשות משהו והוא יעשה בדיוק את זה. ובכל זאת בני אדם מבלים חלק ניכר מהחיים שלהם בלמצוא "באגים", כלומר בלהבין למה המחשב לא עשה את מה שאמרנו לו לעשות. איך זה קורה? יש לי שלושה רעיונות- ## כי אתה לא יודע איך לבקש סיבה ראשונה היא שאנחנו פשוט מבקשים לא נכון. אם אני רוצה לגרום ל Node.JS ליצור עץ תיקיות מתוך תיקיית /tmp שמתחיל בתיקיה שנקראת foo, ממשיך בתיקיה בשם bar ומסתיים בתיקיה בשם buz ואני מפעיל את הפקודה הבאה בשביל זה:
const fs = require('fs');
fs.mkdirSync('/tmp/foo/bar/buz');
אז זה לא יעבוד כי mkdir כברירת מחדל לא יוצר מספר תיקיות אחת בתוך השניה וצריך להעביר אופציה מיוחדת שתאפשר את ההתנהגות הזאת. אלה סוג הבעיות שהכי קל למצוא והכי קל לתקן. רוב הזמן מחשבים די טובים בלהגיד לך כשאתה עושה משהו לא בסדר. ## כי אתה לא יודע מה לבקש צעד אחד קדימה עם הטעויות שלנו ואנחנו מגיעים לבעיות שנובעות מכך שלא תמיד אנחנו יודעים מה לבקש. מחשבים צריכים הרבה יותר אינפורמציה מאנשים בשביל לפעול ולאנשים יש נטיה מרגיזה לדלג בראש על שלבים קריטיים לפיתרון כשחושבים על בעיה. אם בסיפור מקודם נרצה לייצר את עץ התיקיות "במקום הרגיל" במקום בתוך תיקיית /tmp אנחנו עלולים להתפתות לכתוב קוד שנראה ככה:
const fs = require('fs');
fs.mkdirSync('foo/bar/buz');
ובכך שוויתרנו על להיות ספציפיים אמרנו למחשב שאנחנו בעצם לא ממש יודעים מה אנחנו רוצים. האם זה יחסי לספריה הנוכחית או לספריה שבה נמצא הקובץ? ומה אמורה להיות לדעתכם הספריה הנוכחית? ומה אם מישהו מריץ מספריה אחרת? המחשב יודע בדיוק את התשובות לכל השאלות האלה, אבל אם אתם לא בטוחים שאתם יודעים זה אומר שביקשתם משהו בלי להבין מה אתם מבקשים - והתוצאה תהיה שתקבלו משהו שאולי לא ציפיתם לו. ## כי אתה מבקש דברים לא הגיוניים אפשרות שלישית בגללה התוכנית תישבר היא כשאתם מנסים לבקש דברים שמחשב פשוט לא יכול לעשות. זה כמו שננסה ללחוץ על מתג האור בבית בצורה מסוימת שתגרום למנורה לדלוק בצבע אחר. אם למנורה אין את היכולת להידלק באור סגול שום לחיצה על המתג לא תגרום לזה לקרות. אם תבקשו מ Node ליצור תיקיה איפה שכבר יש קובץ הוא יגיד לכם בנימוס שזה לא אפשרי ליצור שני דברים שונים עם אותו שם על הדיסק. אם תנסו להזיז קובץ לכונן אחר Node יסרב בנימוס גם לזה. ורק תנסו להציע לו ליצור קובץ בתיקיה שהיא לקריאה בלבד. ואז יש את המגבלות הטכניות של השפה והחומרה - אם זה מגבלות מהירות, מגבלות של נעילות ומקביליות, מגבלות של פריימוורק שבחרתם להשתמש בו או כל מגבלה אחרת שאתם אולי לא מודעים אליה אבל המחשב דווקא כן. מה עושים? מתאמנים על איתור ותיקון תקלות ב-3 ערוצים: 1. לומדים טוב יותר את שפת התכנות וה API שאתם עובדים בהם כדי להבין איך לבקש את מה שאתם באמת רוצים. 2. לומדים להסתכל טוב יותר על המכונה והאלגוריתם כדי להבין מה לבקש. שואלים את עצמנו כמה שיותר שאלות בזמן כתיבת הקוד כדי לוודא שכיסינו את כל המצבים. 3. לומדים לראות מראש איזה דברים המחשב לא יכול לעשות, ומפסיקים לבזבז זמן על לבקש ממנו לעשות את אותם דברים לא הגיוניים.

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

ToCode
1 419
# טיפ JavaScript: בדיקת פרמטרים והודעות שגיאה קוד טוב הוא כזה שעוזר לנו למצוא באגים מהר, גם אם הבאגים לא נמצאים באותו קוד עצמו. בדוגמה של JavaScript תבנית פופולרית שיכולה לגרום לבעיות מסוג זה היא קבלת אוביקט פרמטרים לפונקציה. נדמיין פונקציה שצריכה להתחבר ל redis, ברירת המחדל שלה תהיה להתחבר ל redis שרץ על המחשב המקומי אבל באוביקט הפרמטרים היא יכולה לקבל מפתח בשם redis ובתוכו כל מיני אופציות לחיבור של redis כמו host ו port. הפונקציה עשויה להיראות כך:
function init(options={}) {
  let redisHost = 'localhost', redisPort = 6379;

  if (options.redis && options.redis.host) {
    redisHost = options.redis.host;
  }
  if (options.redis && options.redis.port) {
    redisPort = options.redis.port;
  }
  console.log(`Connecting to redis at ${redisHost}:${redisPort}`);
}

init();
init({ redis: { host: 'my-redis' } });
הקוד עובד ומשתמש בערכים הנכונים לכל המצבים, אבל הוא עלול לסבך אותנו אם נשתמש בו לא נכון. נדמיין ששם המכונה מגיע ממשתנה סביבה בשם REDIS_HOST אבל בקוד טעיתי באיות וכתבתי משהו כמו REDS_HOST - כלומר הפעלתי:
init({ redis: { host: process.env.REDS_HOST } });
במצב כזה למרות שהעברתי ערך למשתנה redis.host הפונקציה תתעלם מהערך בגלל שהוא undefined ותשתמש בערך ברירת המחדל. שום הודעת שגיאה לא תופיע ולא יהיה לנו שום רמז שכתבנו משתנה בשגיאת כתיב. קוד טוב יותר לפונקציה הראשונה היה יכול בקלות לזהות שמישהו ניסה להעביר ערך אבל העביר undefined, ולציין את זה באזהרה או שגיאה:
function init(options={}) {
  let redisHost = 'localhost', redisPort = 6379;

  if (options.redis) {
    if ('host' in options.redis) {
      if (options.redis.host) {
        redisHost = options.redis.host;
      } else {
        throw 'Error: options.redis.host is undefined';
      }
    }
    if ('port' in options.redis) {
      if (options.redis.port) {
        redisPort = options.redis.port;
      } else {
        throw 'options.redis.port is undefined';
      }
    }
  }

  console.log(`Connecting to redis at ${redisHost}:${redisPort}`);
}
בכתיבת פונקציה שאחרים הולכים להשתמש בה - שווה לחשוב גם איך אותם אנשים אחרים שישתמשו בפונקציה הולכים לטעות, ולעזור להם למצוא את הטעויות מהר יותר.

ToCode
1 419
# למי קראת בינוני? בציוץ שעורר סערה לא קטנה בשעתו לורי ווס כתב את הדברים הבאים: 1. אני, במקרה הכי טוב, מתכנת עם יכולות בינוניות. הלוואי שזה לא היה נכון, הלוואי שהייתי אחד הגאונים, אבל אני לא אז מנסה לעבוד עם מה שיש. 2. אני מקבל את זה שלעולם לא אמציא אלגוריתם חדש שמשנה את העולם וכנראה אפילו לא פריימוורק חדש שאנשים אוהבים. אני משתמש בדברים האלה - פשוט לא זה שממציא אותם. 3. מה שכן יש לי זה ניסיון. נו וזה ברור - אם אתה מפשל מספיק פעמים בסוף תלמד איך עושים דברים נכון. אם תכתוב מספיק באגים בסוף תשתפר בלמצוא אותם. זה לא טוב כמו להיות גאון אבל האפקט מצטבר. ניסיון הוא דבר מאוד מועיל. 4. הדבר השני שאני מצליח לעשות זה לחבר בין רעיונות. אני סופג מידע מכל מיני מקורות, מזהה תבניות ובונה סביב זה הסבר. אפשר להגיד שאם יש משהו שאני מעל-הממוצע בו זה להסביר. 5. ברור שלהסביר דברים זה לא מרשים כמו להמציא אותם, אבל זה גם לא פופולרי באותה מידה. כישרון להסביר מה קורה זה מה שאני מביא לשולחן. 6. ובהינתן שזו העיסקה העובדה שאני מתכנת בינוני דווקא עוזרת. אני מצליח לראות דברים מנקודת המבט של המתכנת הממוצע, אני אוהב את מה שממילא פופולרי, אני אף פעם לא רוצה לעשות דברים בדרך הקשה-אבל-חכמה. 7. וכמובן שניסיון הוא גם דבר מאוד מועיל. אחרי מספיק שנים בתעשיה אתה מתחיל ללמוד להבדיל בין רעיונות טובים שיישארו לאורך זמן לבין אופנות שעוד שבוע יעלמו. 8. זאת לא מיומנות נוצצת, אני אף פעם לא אהיה מפורסם וזה די מבאס. אבל זאת מיומנות מועילה לי ולאחרים וכך למדתי להיות מרוצה ולהסתפק בהיותי מתכנת בינוני שמצליח רק להסביר דברים. --- קראתם? עכשיו בואו נפתח את זה. לפני שנדבר על מי זה לורי ווס ומה הוא עשה, אפילו אם הציוץ הזה היה אנונימי היה קשה להתעלם מהבעיותיות פה. הכותב מתעקש שהוא מתכנת בינוני אבל כל התיאור שלו את עצמו ואת סט המיומנויות שלו הוא ההיפך הגמור מבינוני. בהנחה שווס מתאר את עצמו בצורה אמינה אלה המיומנויות שיש לו שבעיניי הופכות אותו למתכנת מעולה: 1. הוא לומד מטעויות ומשתמש בניסיון לטובתו. 2. הוא בעל יכולת אבחנה טובה ומצליח לראות דברים בקוד שאחרים לא רואים. 3. הוא בעל מיומנות תקשורת טובה ומצליח לתקשר את הדברים שהוא רואה בקוד למתכנתים אחרים. 4. הוא מסוגל להבין בעיה ולהציע פיתרון שאנשים אחרים יוכלו אחר כך לקרוא ולתחזק אותו. אלה ארבע תכונות שהייתי שמח למצוא בכל מתכנת שאעבוד איתו. תכונות ששווה להשקיע בהן ותכונות שבכל מקצוע אחר היו מזכות אותו בתואר "בעל מקצוע מעולה". אם אני צריך לבחור בין רופא שממציא שיטות טיפול חדשות לבין רופא אמין, מנוסה, בעל יכולת תקשורת טובה ויכולת פיתרון בעיות - הייתי בוחר ברופא השני בלי להתבלבל. אם אני צריך לבחור בין אדריכל שממציא בניינים חדשים לבין אדריכל שמראה Track Record של בניינים אמינים שבנה ומצליח לתקשר לי את כל השיקולים והבחירות בבניה - אני בוחר את השני לבנות כל בניין שאני צריך. ואצלנו בתכנות? קן תומפסון, הממציא האגדי של יוניקס, מספר בראיונות שאת העבודה על יוניקס הוא עשה אחרי שהמנהלים שלו החליטו לבטל את הפרויקט וחלק גדול ממנה נעשה בלי לספר למנהלים על מה הוא עובד. ברנדון איי, הממציא של JavaScript, התעקש להכניס מאפיינים משפות אזוטריות לתוך השפה וגרם למתכנתים להתבלבל במשך עשרות שנים. טוב שיש מתכנתים גאונים בתעשיה אבל צריך לזכור שרוב הזמן הם לא האנשים שהכי קל לעבוד איתם. המחשבה כאילו הדרך להיות מתכנת מעולה היא רק להמציא אלגוריתם חדש או לבנות פריימוורקים מאפס היא הרסנית לביטחון העצמי שלכם ולקהילה כולה. --- נ.ב. אחרון בגיזרת הקונטקסט. למי שלא מכיר אז הבחור המצייץ הוא Co-Founder של npm (כן מערכת ניהול החבילות ל Node.JS, זאת שמחזיקה את מאגר החבילות הגדול בעולם). הוא מתכנת ווב מאז 1996 ולפני npm הקים חברה בשם awe.sm שנמכרה ל Unified. הוא הרצה ב JS Conf וכנסים נוספים וכותב בלוג טכני מוצלח כבר 20 שנה. יום אחד נצטרך לשאול את עצמנו איך אנשים מעולים מהתעשיה נתקעים עם רגשי נחיתות לא מוצדקים.

ToCode
1 419
אף אחד לא יודע כמה זמן ייקח לך ללמוד React Hooks או Redux Middlewares, וזה בסדר. בתהליך לימוד מומלץ להסתכל על כמה שעות לימוד יש לי בשבוע ואיך אני מנצל בצורה יעילה את השעות האלה. אין דרך לתכנן או לשלוט בכמה שבועות ייקח לי ללמוד נושא מסוים וזה גם בכלל לא משנה. אנחנו לא שולטים בקצב. ## לסיכום: איך להימנע מכל הטעויות בתהליך הלימוד נניח שהחלטתם ללמוד פיתוח Full Stack בלי ליפול לאף אחת מארבעת המלכודות שראינו. הנה מה שאפשר לעשות: 1. לומדים את הטכנולוגיות לפי הסדר, אחת אחרי השניה. כדאי לעבוד לפי סילבוס מסודר שיעזור להישאר ממוקדים. 2. להחליט על "הישגים" סוביקטיביים שתלויים בכל וקשורים לסילבוס ולנקודות מרכזיות בו. זה יכול להיות האתר הראשון שהעליתם לאוויר, הקוד האינטרקטיבי הראשון שכתבתם, הפעם הראשונה שכתבתם ברכה אינטרנטית לחבר או חברה, או אפילו סיום תרגילי הסיכום של פרק מסוים בסילבוס. כשיש לכם מול העיניים רשימה של הישגים סוביקטיביים ופרסים קטנים שמתאימים לכל הישג הרבה יותר קל להתקדם. 3. לחלק את הזמן לזמן לימוד וזמן תרגול ובזמן התרגול לעבוד על פרויקטים או רעיונות שלכם. אם יש לכם 10 שעות בשבוע של לימוד אז תחלקו אותן שעה לראות וידאו, עוד שעתיים-שלוש לפיתרון תרגילים קטנים על הנושא שהיה בוידאו ועוד שבע-שמונה שעות לבניה של רעיון שלכם באותם הכלים. בשביל לא לגלוש עם הטכנולוגיה אפשר להיעזר בפרילאנסרים שיבנו בשבילכם את החלקים שאתם עדיין לא שולטים בהם (לדוגמה לקחת פרילאנסר שיבנה לכם את ה CSS ואתם תכתבו את ה JavaScript, או לקחת פרילאנסר שיבנה את קוד צד השרת ואתם תתמקדו בקוד צד הלקוח). 4. להתחיל את הלימוד כמה שיותר מוקדם ולא כשיש לכם דד-ליין. אם יש לכם ראיון עבודה על ריאקט בעוד שבועיים אז יהיה מאוד קשה לבנות תהליך לימוד מהנה לשבועיים הקרובים עד הראיון; אבל אם התחלתם ללמוד Full Stack תוך כדי עבודה במשרה חלקית בתור מתכנתי Java אז הלימוד לא "תוקע" אתכם בחיים ואתם יכולים להשקיע את הזמן שצריך כדי להגיע לרמה אליה אתם שואפים. נ.ב. תודה לקלות'ילד על ההשראה לפוסט זה ורבים נוספים.

ToCode
1 419
# ארבע טעויות שהורסות לנו את הלימוד תהליך לימוד טכנולוגיה חדשה יכול להיות מהנה ומספק, אבל גם יכול להיות מלחיץ ולא יעיל. ברוב המקרים כשהתהליך נכשל זה בגלל שעשינו אחת או יותר מ-4 הטעויות הבאות: ## ללמוד יותר מדי דברים ביחד טעות מספר אחת והיא הנפוצה ביותר היא הרצון ללמוד יותר מדי דברים במכה אחת. זה בולט במיוחד בתחום של פיתוח Full Stack בגלל הכמות ההזויה של טכנולוגיות שנתקלים בהן. זה לא נדיר לראות מישהו שמנסה להיכנס לריאקט מנסה ללמוד גם Next.JS, גם JavaScript, גם React, גם Redux, גם MobX, גם CSS Modules, גם CSS In JS, גם Webpack, גם Material UI, וגם וגם וגם. עכשיו מצד אחד יש פה הגיון כי במודעת דרושים או איפה שלא תסתכלו באמת יש רשימה ארוכה ומתישה של טכנולוגיות. אבל מהצד הפרקטי זה פשוט בלתי אפשרי להשתלט על כל כך הרבה חומר במכה אחת. כל פעם שאנחנו יורדים מהשביל כדי ללמוד עוד טכנולוגיה אנחנו רק מתרחקים מהיעד של היכרות טובה עם הטכנולוגיה אותה רצינו ללמוד מההתחלה. במקום לרוץ לכל הכיוונים יותר משתלם להתמקד: לבחור רק טכנולוגיה אחת וללמוד אותה לעומק. אחרי זה להמשיך לשניה, ולשלישית ולרביעית. בזכות היכולת להתמקד כל פעם בטכנולוגיה אחת, הלימוד של כל טכנולוגיה יהיה מהיר יותר וזמן הלימוד הכולל יהיה קצר יותר - ובנוסף אתם תרגישו הרבה פחות מתוסכלים מהתהליך. ## לחגוג הישגים אוביקטיביים הישג אוביקטיבי הוא משהו שאפשר לראות ולהראות לאחרים. לדוגמה אם החלטתי ללמוד לכתוב אפליקציות לאייפון אז הישג אובייקטיבי יהיה אפליקציה שאנשים מורידים אותה ונהנים ממנה, ועדיף אחת בתשלום כך שגם נראה הכנסה מהעבודה. או אם אתם לומדים פיתוח Full Stack אז הישג אוביקטי יהיה לבנות מערכת שתרשים מראיינים פוטנציאליים כדי שיזמינו אתכם לראיון עבודה או יותר טוב למצוא ממש עבודה בתחום. אם המוח שלכם עובד קצת כמו שלי אז כל יום שעובר בלי הישג אוביקטיבי מוסיף לחץ בצורה של: "אולי אני לא בכיוון", "אולי לעולם לא אצליח לכתוב אפליקציה שאנשים ירצו", "אולי התחרות קשה מדי", "אולי בחרתי תחום שלא מתאים לי" ועוד אינספור מחשבות ופחדים מסוג זה. הבעיה עם הישגים אוביקטים היא שהם באמת קשים להשגה. זה יכול לקחת שנה ללמוד Full Stack ברמה שתכניס אתכם לעבודה. זה יכול לקחת שלוש שנים להתאמן על פיתוח אפליקציות עד שתפתחו אחת שאנשים ירצו לשלם עליה ולספר עליה לחבריהם. המתנה להישגים אוביקטיביים אומרת שאתם מעבירים את רוב תהליך הלימוד בחששות ובלחץ שאולי אתם לא בכיוון הנכון ושאולי זה אף פעם לא יצליח. באקלים רגשי כזה מאוד קשה להנות מהלימוד ולהגיע לנקודת הסיום. במקום לחכות להישג אוביקטיבי הרבה יותר מומלץ לחגוג הישגים סוביקטיביים. כשהתחלתי ללמוד פיתוח אפליקציות לאייפון כתבתי את האפליקציות הראשונות שלי רק על סימולטור והחלטתי שברגע שאני מסיים לכתוב משהו שעובד אני קונה לעצמי מכשיר אמיתי (אז היה דבר בשם ipod touch). הנקודה שלבנות משהו שעובד זה הישג שתלוי רק בי והוא הרבה יותר מהיר מלבנות משהו שאנשים ירצו לקנות. ואחרי שקניתי את ה ipod touch קיבלתי חיזוק למוטיבציה שעזר לי להמשיך עד ההישג הסוביקטיבי הבא. כשאנחנו חוגגים הישגים סוביקטיביים אנחנו לא פוגעים בסיכוי שלנו להגיע להצלחה - בדיוק להיפך. אנחנו מעודדים השקעה מתוך הבנה שההצלחה היא תוצאה של תהליך והדבר החשוב הוא לבנות תהליכים נכונים. ## ללמוד יותר מדי תיאוריה טעות מספר שלוש היא להיתקע על תיאוריה ואצלנו בתכנות היא מאוד בולטת. זה מה שקורה כשאנשים לוקחים עוד קורס ועוד קורס ונתקעים על פרויקטים של קורסים ותרגילים קטנים במקום ליישם את הידע ולהתקדם לפרויקטים יותר ויותר גדולים. חלוקת העבודה בין לימוד מקורס לבין עבודה אמיתית בקורס תכנותי צריכה לעמוד על חמש-אחד, כלומר כל שעה שהשקעתם בלימוד אתם צריכים להשקיע 5 שעות בכתיבת קוד אמיתי. זה אומר שמי שלוקח קורס וידאו שהאורך שלו הוא 8 שעות וידאו צריך להשקיע בנוסף ל-8 שעות צפיה בוידאו עוד 40 שעות בכתיבת קוד אמיתי על הנושאים שנלמדו בוידאו. ## לנסות לשלוט בקצב טעות רביעית שיוצרת תסכול בתהליך הלימוד היא הניסיון לשלוט בקצב הלימוד או יותר נכון בקצב הקליטה. לימוד הוא לא לינארי והרבה מאוד פעמים אני נתקע המון שעות על איזה נושא מסוים שנראה ממש קטן ולא חשוב, כשפעמים אחרות אני רץ ומבין מהר המון נושאים אחרים. הניסיון לסדר את הלימוד בתוך סילבוס ולהחליט שייקח לי שלוש שעות ללמוד להשתמש ב React Hooks תורם רק תסכול.

ToCode
1 419
# לא שמתי לב לא שמתי לב לגודל של ה Docker Image ... עד שהתחיל להיגמר לי המקום על הדיסק. לא שמתי לב לזמני הטעינה של האתר ... עד שהתחילו להגיע תלונות מגולשים שלא מצליחים להתחבר. לא שמתי לב לאיטיות השאילתות ב DB ... עד שקוד התחיל להיכשל על Timeouts בדיוק בשיא העומס על המערכת. לא שמתי לב לבעיות האבטחה בקוד ... עד הפריצה שהפילה לי את כל המערכת לשבועות. לא שמתי לב שהקוד כל כך מבולגן ... עד שהגיע מתכנת חדש לצוות שלא הצליח למצוא את הידיים והרגליים שם. בתוכנה לא לשים לב זה סוג של בחירה. יש לא מעט כלים טובים שעוזרים לנו לזהות הרבה בעיות לפני שמגיעים לפרודקשן. הבחירה לשים לב עוזרת לבנות מערכות טובות יותר, ויותר מזה היא פותחת דלתות לאזורי לימוד חדשים ועוזרת לנו להתקדם כמתכנתים.