מה הייתי רוצה לדעת כשהתחלתי לתכנת
לימוד עצמי של תכנות יכול להיות מאתגר - או ע”י קורס ללמידה או מספר.
מצד אחד זה מתאגר מצד שני קיים חסרון - אין סילבוס מסודר או התמקדמות בנושאים החשובים.
בפוסט הזה אציין כמה נושאים מאוד חשובים להתחלה.
ניהול גרסאות
האספקט הראשון שקופץ לי בראש הוא איך לנהל גרסאות בצורה יותר טוב.
האופציה הפשוטה ביותר - וגם המגעילה ביותר - היה פשוט להעתיק קבצים ולמספר אותם:
- work.docx
- work_final.docx
- work_really_final.docx
- work_i_promise_you_this_is_the_end.docx
- work_i_promise_you_this_is_the_end_v2.docx
אז במקום זה מה שצריך ללמוד זה איך לנהל גרסאות קוד בצורה מיטבית בעזרת כלים כמו “git”.
עבודת צוות
לעבוד עם מתכנתים אחרים יכול להיות מאוד מספק וגם מאוד מלמד, זה הופך אותך ליותר טוב ומאתגר אותך - וגם מאתגר אותם.
פעם היה קשה להתמצא עם אנשים אחרים ולעבוד עם אנשים אחרים אך כיום יש מגוון דרכים לעשות את זה:
- Slack
- GitHub
- שרתי Discord
אני רוצה לציין במיוחד את קהילות ה-Discord.
יש הרבה קהילות שמתקדמות בתחומים שונים: בניית משחקים, AI, רנדור, שפות תכנות וכדו’…
לתכנת עם אנשים אחרים ולצפות בקוד של אחרים עוזר לנו, והופך אותנו גם לחבר צוות יותר טוב.
אם אתם רוצים להגיע מהר - לכו לבד, אם אתם רוצים ללכת רחוק, לכו ביחד
תחום אחריות אחד בלבד
אני מזכיר את כללי “SOLID” במגוון מאמרים, אך עבורי העקרון הראשון הוא חשוב ביותר:
על יישות לוגית להיות אחראית על תחום אחריות אחד בלבד
העקרון הזה גורם לנו לפצל קוד לישויות נוספות כאשר כל אחת מהן מנהלת את תחומה בלבד.
היתרון העיקרי הוא מציאת באגים בצורה פשוטה יותר.
אני כבר עבדתי על קבצים גדולים של 6 אלף שורות קוד - כן הם קיימים שם בחוץ.
אתם יכולים לתאר לעצמכם את הסבל שעובר כאשר אתם מחפשים באג קטן בכל הערימה הזו.
אם הקובץ הזה היה מפוצל ללוגיקות יותר קטנות, היה אפשר לזהות את הבאג בצורה יותר פשוטה.
כי היינו יודעים איזו לוגיקה לא באמת עובדת כמו שצריך.
תלותיות וקישוריות
Coupling- הרמה שבהן שני רכיבים תלויים אחד בשני.
Cohesion - הרמה שבהן שני רכיבים קשורים אחד לשני.
האידיאל שצריך לשאוף אליו זה:
- Coupling נמוך
- Cohesion גבוה
דוגמא לתלותיות גבוה
1 | public class FruitSlicer |
תלותיות נמוכה
1 | public interface ISlicer |
התלותיות הגבוה מתבטאת בכך שהרכיב B
יודע על הרכיב FruitSlicer
.
אם היינו צריך סוג אחר של סכין היינו צריכים ידנית להוסיף אותו, להמיר או להחליף לגמרי.
חשיבה אבסטרקטית יותר תעזור לנו ליצור קוד שפחות תלוי אחד בשני.
אם היינו רוצים חותך בשר במקום חותך פירות, היינו יכולים לבצע את זה מאוד בקלות.
תתכנתו ממשקים ולא מחלקות
קישוריות גבוה
1 | public interface ILogger |
הממשק מגדיר בצורה ברורה מה ההתנהגות שיש לנו כאן - פונקציות לוג.
והן אחראיות על תחום אחד בלבד - להדפיס לוג.
קישוריות נמוכה
1 | public interface ILogManager |
בכללי מחלקות Manager הן Anti-pattern וצריך לדעת להשתמש בהן כראוי.
הבעיה הנפוצה איתן שמתכנתים מגדירים פונקציות עם קישוריות נמוכה מדי וזה גורם לתחום אחריות גדול מדי.
בדוגמא הזו ניתן לראות שני תחומים נוספים ללוג: שמירה לקובץ ושליחה לכתובת אינטרנטית.
אולי השליחה והכתיבה קשורות ללוג אך הפעולות עצמן לא קשורות לכתיבה אלה לממד IO אחר.
המשמעות האמיתית מאחורי “תכנות מונחה X”
עד שלמדתי את המשמעות האמיתית מאחורי המושג “תכנות מונחה” לא באמת הבנתי כיצד לעצב קוד בעזרתו.
הנחייה אומר מה האלמנט הבסיסי שיש לנו כדי להגדיר קוד.
בתכנות מונחה פונקציות אנחנו צריכים לחשוב בעזרת - פונקציות.
בתכנות מונחה עצמים הערך הבסיסי שלנו הוא - העצם.
בתכנות מונחה מידע מה העצם שלנו? המידע!
אתם יכולים להבין את התבנית פה.
אז מהי המשמעות
דוגמא מאוד קלילה זה תהיה מערכת התראה לבית - כי זה משהו פיזי שניתן לייצג בעזרת אובייקטים.
בתכנות מונחה עצמים אנחנו צריכים לחשוב על האובייקטים השונים שיכולים להיות לנו.
ומה יש לאובייקט? מידע והתנהגות.
יש אובייקטים שיש להם מידע בלבד - להם אנחנו קוראים מודלים.
ויש כאלו שיש להם התנהגות בלבד - להם אנחנו קוראים נותני שירות.
בואו נתחיל עם בקר:
1 | public interface IAlarmController |
בקר יש לו את יכולת הניהול הכללית, ולכן יש לו:
- שליטה ובקרה
- התראות
- מיקומים
- תפריט להוספה והורדה של רכיבים
מיקום הוא איזשהו מימד פיזי שבו מוגדר חיישנים:
1 | public class Location |
חיישן הוא רכיב פיזי שיודע ליצור התראות ודיווח.
אם נחשוב על כמה חיישנים שיכולים להיות לנו:
- חיישן חום
- חיישון תנועה
- חיישן אור
- חיישן מוטורי
מקווה שהדוגמא הקטנה הזו הבהירה את הנקודה!
אל תהיו נינג’ות
אולם זה בסדר להיות סמוראים ולעשות חרקירי במידה ומצאו אצלכם באג בפרודקשן
אל:
1 | var stringified = (isFlag? mResults["Yes"].Active? "The result is active" : "The result is not active" : mResults["No"].Active? "Active result is denied" : "Request denied"); |
כן:
1 | var result = isFlag ? mResults["Yes"] : mResults["No"]; |
לא הייתי קורא לזה הדוגמא הכי מוצלחת אך היא מבהירה את הנקודה שלי.
יותר מזה, כשכתבתי את הדוגמא הראשונה היה לי ממש קשה לפצל את זה לדוגמא השנייה שזה בדיוק מה שאני רוצה להוכיח.
לפני שנה כתבתי קוד, אני ואלוהים ידענו מה הוא עושה.
היום? רק אלוהים יודע מה הוא עושה!
בלי כוונה לפעמים הקוד שאנחנו כותבים לא ברור לנו מספיק.
תחשבו קודם - תעצבו ואז רק תבנו
הרבה יותר קל למחוק משפט שכתוב עם עפרון מאשר לכתוב קוד מחדש
אני זוכר שלימדתי בחור איך להתחיל פרוייקט.
ביקשתי ממנו לפתוח וורד או כל תוכנה אחרת לפני שהוא פותח את ה-IDE כדי לתכנת.
לא התפלאתי שהוא בכלל לא הצליח ואחרי כמה זמן הוא אמר לי “אני חייב את הIDE” - אז נתתי לו להשתמש בו.
המוסר השכל - מתכנתים לא מנוסים מתמקדים בפרטים הקטנים שהם לא מצליחים לחשוב קודם כל על פתרון הולם.
לפעמים גם זה לא אשמתם - אולי הם לא מכירים את ה-API כמו שצריך.
בשביל זה יש לי 30 פרוייקטי צד שכולם נקראים “TestX”, “ConsoleApp” וכדו’…
זה בסדר לבדוק קוד איך הוא עובד ומה קורה בפועל - אך צריך להשתמש בזה רק כדי לעצב ולא לכתוב את כל הקוד לפתרון.
תמיד תעצבו את הקוד שלכם לפני הבנייה שלו - זה יחסוך לכם זמן בעתיד
זהו לא המדריך המלא למתכנתים חדשים,
רק כמה נקודות ממש חשובות שאני מקווה שכל מי שלומד תוכנה יבין אותם לעומק.
תודה על הקריאה!