כללים וציטטות על הנדסת תוכנה

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

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

פשטות

פשטות היא תנאי מוקדם לאמינות.1

אדסחר דייקסטרה

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

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

איך מגיעים לפשטות?

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

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

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

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

קריאות

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

ג׳ון וודסמקור

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

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

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

הערות

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

קורי הוס

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

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

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

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

חוויית משתמש

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

ג׳יימי זווינסקי

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

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

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

חוק קונווי

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

מלווין קונווייחוק קונווי

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

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

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

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

תכנון

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

כריסטופר תומפסון

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

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

weeks can save hours

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

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

נשמח לשמוע מה אתם חושבים על המאמר.

1 Simplicity is prerequisite for reliability. – Edsger W. Dijkstra
2 So much complexity in software comes from trying to make one thing do two things. – Ryan Singer
3 Deleted code is debugged code. – Jeff Sickel
4 Simple things should be simple, complex things should be possible. – Alan Kay
5 Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. – John F. Woods
6 Programs must be written for people to read, and only incidentally for machines to execute. – Harold Abelson
7 Any code of your own that you haven’t looked at for six or more months might as well have been written by someone else. – Eagleson’s Law
8 Any damn fool can write code that a computer can understand, the trick is to write code that humans can understand. – Martin Fowler
9 Code is like humor. When you have to explain it, it’s bad. – Cory House
10 Code never lies, comments sometimes do. – Ron Jeffries
11 Every program attempts to expand until it can read mail. Those programs which cannot so expand are replaced by ones which can. – Jamie Zawinski
12 A primary cause of complexity is that software vendors uncritically adopt almost any feature that users want. – Niklaus Wirth
13 The most important property of a program is whether it accomplishes the intention of its user. – C.A.R. Hoare
14 Organizations which design systems […] are constrained to produce designs which are copies of the communication structures of these organizations. – Conway, Melvin E
15 Sometimes it pays to stay in bed on Monday, rather than spending the rest of the week debugging Monday's code. – Christopher Thompson
16 Weeks of programming can save you hours of planning. – Unknown
17 First, solve the problem. Then, write the code. – John Johnson
18 Think twice, code once. – Waseem Latif
19 I'm a programmer. I like programming. And the best way I've found to have a positive impact on code is to write it. – Robert C. Martin

11 תגובות בנושא “כללים וציטטות על הנדסת תוכנה

הוסיפו את שלכם

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

  2. אהבתי ממש! תענוג לקרוא.
    יצירת הרגלים טובים דורשת התבוננות ותרגול, ושוב התבוננות וכו'…
    דרך אגב, חסר לכם באתר scroll bar באתר.

  3. מעולה מעולה מעולה!
    נהניתי מאד מהפוסט הזה.

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

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

    תוכן מצויין, תמשיכו לפרסם!

נשמח לשמוע מה אתם חושבים על המאמר

ערכת עיצוב: Baskerville 2 של Anders Noren.

למעלה ↑

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

נרשמת בהצלח. בתודה, הגמל.

שגיאה בלתי צפויה, אנא נסה שוב.

camelCase will use the information you provide on this form to be in touch with you and to provide updates and marketing.