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

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

איך הפסקתי לדאוג וזרקתי את כל ה Mock-ים לפח

20/06/2019

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

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

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

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

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

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

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

בנוסף הרבה מערכות היום מספקות מצב בדיקה שמיועד בדיוק בשביל שלא תצטרכו לכתוב עבורן Mock. מיילגאן מאפשרת לכם לשלוח מיילים לא במסגרת החבילה לנמעני בדיקות שהוגדרו מראש. כך גם Twilio שמאפשרת לעבוד עם כל ה API במצב בדיקה. בתשלומים פייפאל כוללת מצב Sandbox בו כל כרטיס אשראי עובר כדי שתוכלו לבדוק את מערכת התשלומים שלכם, ובפייסבוק אתם יכולים לפתוח Test User על פייסבוק עצמה כדי לבדוק את הקוד שלכם מול המערכת האמיתית.

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

הבחירה שהכי קשה להתמיד בה

19/06/2019

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

  1. הזרקות קוד - רובן מזוהות אוטומטית על ידי הכלי Brakeman

  2. מתקפות XSS - רובן מזוהות אוטומטית על ידי הכלי Brakeman, ונפתרות אוטומטית על ידי שימוש ב CSP.

  3. ניהול שבור של Sessions

  4. בעיית Insecure Direct Object Reference - נפתרת אוטומטית על ידי הג'ם cancancan וניהול הרשאות מסודר

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

  6. הגדרות אבטחה לא נכונות (לדוגמא בסיס נתונים בלי סיסמא וכו'). ניתן לזהות בעזרת כלים אוטומטיים.

  7. איחסון לא מאובטח של סודות - ריילס כולל מנגנון לניהול סודות שמצפין אוטומטית את כל הסיסמאות.

  8. יצירת URL-ים סודיים שהכניסה אליהם לא מוגבלת - נפתר על ידי הג'ם cancancan וניהול נרשאות מסודר.

  9. הגנת HTTPS שלא מוגדרת טוב - ניתן לזהות באמצעות כלים אוטומטיים שרתים פגיעים.

  10. ביצוע Redirect לפי ערך שהגיע מהמשתמש - מזוהה אוטומטית באמצעות brakeman.

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

אנחנו יודעים טוב למה.

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

למי אכפת מה Critical Rendering Path

18/06/2019

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

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

הנה דוגמא קצרה להמחשה - נניח שיש לנו קובץ HTML שנראה כך:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <link href="https://fonts.googleapis.com/css?family=Rubik&display=swap" rel="stylesheet">

        <title>Demo</title>
<style>
p { font-family: 'Rubik', sans-serif; display: none; }
</style>
    </head>
    <body>
    <script src="demo.js"></script>
    </body>
</html>

והוא טוען קובץ JavaScript בשם demo.js שנראה כך:

setTimeout(function() {
  const div = document.createElement('div');
  div.style.fontFamily = 'Rubik';
  div.textContent = "hello world";
  document.body.appendChild(div);
}, 1000);

אני יודע שהדוגמא נראית קצת מומצאת אבל תזרמו איתי ותכף נראה איך היא מתקשרת לחיים האמיתיים. הקובץ מחכה שניה ואז שם בלוק של טקסט על המסך בגופן בשם Rubik. את הגופן טענו מתוך קובץ ה HTML באמצעות Google Fonts.

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

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

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

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

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

https://www.tocode.co.il/workshops/79

בביצועים צריך גם לדעת לוותר

17/06/2019

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

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

הנה דוגמא קצרה מהאתר היום - לאחרונה שמתי לב שלוקח לאתר המון זמן להיפתח. מבט מהיר בלוגים הראה שהבעיה במנגנון ה Server Side Rendering. זה המנגנון שגורם לזה שכשאתם פותחים דף באתר השרת ישלח לכם קובץ HTML תקני שייפתח גם אם ה JavaScript מבוטל אצלכם על המכונה. אני מאוד אוהב את הרעיון שהפוסטים נפתחים גם בלי JavaScript ומנגנון ה SSR היה תנאי סף מבחינתי לשילוב React במערכת. והנה המשחק של התקציב נותן את המכה שלו, כי עכשיו האפשרויות הן:

  1. למצוא למה SSR עובד לאט ולתקן אותו (לא בטוח שאפשר, בטוח שהחיפוש ייקח זמן).

  2. להוסיף מנגנון Caching בצד השרת לתוצאה של ה SSR (יעבוד אבל ייקח יותר זיכרון בשרת, ייקח זמן למימוש ואולי יביא בעיות אחרות)

  3. לוותר על SSR

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

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

אגב ביום חמישי הקרוב אעביר כאן וובינר על ביצועים ביישומי ווב בדגש על Front End. נדבר על Critical Rendering Path, נראה איך לזהות אותו באמצעות כלי הפיתוח של הדפדפן ואיך להשתמש במידע כדי לשפר את החוויה של רוב הגולשים שלכם. אולי אפילו נצליח למצוא יחד עוד כמה דרכים לשפר את מהירות הטעינה של טוקוד. אם בא לכם להצטרף רק צריך ללחוץ על הקישור:

https://www.tocode.co.il/workshops/79

הזמן הנכון ללמוד מונחים מקצועיים

16/06/2019

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

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

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

מחירים שלא רואים

15/06/2019

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

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

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

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

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

ידע שנשאר

14/06/2019

לפני עשרים שנה הייתי בראיון עבודה והתמודדתי עם שאלות בנושא SQL. זה היה בדיוק כמה ימים אחרי שקראתי את הספר "למד את עצמך SQL ב 24 שעות", או במילים אחרות לא ידעתי כלום. דמיינו כמה הייתי מופתע אם מישהו היה אומר לי אז באותו ראיון שעשרים שנה אחרי עוד אמשיך לעבוד ב SQL, ללמד SQL ולהתבלבל בין Outer Joins ל Inner Joins.

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

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

  2. ה SQL שלמדתי לפני עשרים שנה ממשיך להיות חלק בלתי נפרד מהחיים שלי כמתכנת.

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

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

פיתרון בעיות באמצעות אלגוריתם רקורסיבי

13/06/2019

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

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

המשך קריאה

הפעלת קוד בכל כניסה לתיקיה ב Bash

12/06/2019

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

$ rvm list

   ruby-2.0.0-p247 [ x86_64 ]
   ruby-2.1.2 [ x86_64 ]
   ruby-2.3.1 [ x86_64 ]
 * ruby-2.4.4 [ x86_64 ]
   ruby-2.5.0 [ x86_64 ]
=> ruby-2.6.3 [ x86_64 ]

# => - current
# =* - current && default
#  * - default

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

$ rvm use 2.1.2

ונוודא שאכן הגירסא הוחלפה עם:

$ ruby --version
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin13.0]

אז איפה הטריק? מסתבר שאם נשים בתוך תיקיה קובץ בשם .ruby-version, באופן אוטומטי בכניסה לתיקיה גירסת הרובי תשתנה כדי להתאים לקובץ זה. זה נראה ככה:

$ mkdir test
$ cd test
$ echo ruby-2.1.2 > .ruby-version
$ cd ..
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin18]

$ cd test
$ ruby --version
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin13.0]

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

$ type cd
cd is a function
cd () 
{ 
    __zsh_like_cd cd "$@"
}

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

cd()
{
    echo "wow"
    cd "$@"
}

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

cd()
{
    echo "wow"
    builtin cd "$@"
}

החלק שאני הכי אוהב בפיתוח מערכת

11/06/2019

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

כי מיד כשמתחילים לכתוב את הקוד מתחילות הצרות - ה HTML לא נראה בדיוק כמו שדמיינתי, את ה CSS לוקח לכתוב כפול זמן ממה שהיה לי בראש ואל תתחילו לדבר איתי על בסיס הנתונים, קוד צד השרת, ה Ajax וה API. בקיצור כשהחלומות מתנגשים על ריצפת המציאות אתם יודעים שהולך להיות לכם יום (או חודש) ש

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