fa
Feedback
ToCode

ToCode

رفتن به کانال در Telegram

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

نمایش بیشتر
1 419
مشترکین
اطلاعاتی وجود ندارد24 ساعت
-17 روز
+230 روز
آرشیو پست ها
ToCode
1 419
# מהיר, עמיד ומתועד שלוש מילים שאומרות הכל על הפיתרון הבא שעליך לכתוב: מהיר- כי Over Engineering זו בעיה; כי יש לקוח שמחכה; כי הזמן שלך יקר ואין טעם לבזבז אותו על סיבוכים מיותרים. עמיד- כי אנחנו לא רוצים להתמודד עם הבעיה הזאת שוב בשבוע הבא, או בחודש הבא. ואנחנו לא רוצים שהבעיה תחזור בעידכון הגירסה הבא. עמיד זה אומר שהפיתרון מגיע עם בדיקות וללא תהליכים ידניים שיכולים להישכח. ומתועד- כי כשהבעיה כן תחזור אנחנו רוצים לדעת מה עשית, מה ניסית לעשות ולא הצליח וממה להיזהר בפעם הבאה שמתמודדים עם משהו דומה. יש לנו כלים טכנולוגיים ומיומנות כדי לענות על כל שלושת הדרישות. הפער הוא בדרך כלל תרבות ארגונית ונכונות להשקיע במידה הנכונה.

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

ToCode
1 419
# שאלת ראיונות עבודה: הבטחות ב JavaScript (שוב?? כן שוב, נו הכי כיף Promises) נוד 16 הכניסו מודול של timers/promises שמאפשר להפעיל את setTimeout בתור Promise, אז השאלה הפעם תשתמש ב Node.JS. ויהיה גם פיתרון כי תכל'ס זה הדבר המעניין לכתוב עליו. ## השאלה נתונה התוכנית הבאה ב Node.JS:
import {
  setTimeout,
} from 'timers/promises';

async function waitAndSayYay() {
  await setTimeout(1000);
  console.log('yay');
}

for (let i=0; i < 10; i++) {
  waitAndSayYay();
}
התוכנית מחכה 10 שניות ואז מדפיסה על המסך 10 פעמים את המילה yay. וכן צריך Node 16 בשביל להריץ אותה וצריך לשמור את הקוד בקובץ עם סיומת .mjs. האתגר שלכם - מבלי לשנות את לולאת ה for שבסוף התוכנית, עדכנו את הקוד כך שהלולאה תחכה שניה בין הדפסה להדפסה כלומר סך הכל התוכנית תרוץ במשך 10 שניות. ## פיתרון: שימוש ב Promise חיצוני אז קל לראות את הבעיה כאן - כל הפעלה של waitAndSayYay היא עצמאית ולא יודעת שכבר קראו לפונקציה כמה פעמים קודם. הפיתרון הוא להשתמש ב Promise גלובאלי כדי לסנכרן בין הקריאות: 1. אגדיר Promise גלובאלי שלא עושה כלום 2. כל פעם שמפעילים את waitAndSayYay הוא יוסיף בלוק then ל Promise הגלובאלי, וגם יעדכן את ה Promise הגלובאלי שישמור את התוצאה - כלומר עם בלוק then החדש. בתוך אותו בלוק then תהיה פקודה לחכות שניה ואז להדפיס yay. 3. בתוך הפונקציה אפעיל await על ה Promise הגלובאלי, מה שאומר שאני מחכה לכל ה Promise-ים שהיו עד עכשיו ואחריהם לבלוק then החדש שלי. בקוד זה נראה ככה:
import {
  setTimeout,
} from 'timers/promises';

let running = new Promise((resolve, reject) => { resolve() });

async function waitAndSayYay() {
  running = running.then(async () => {
    await setTimeout(1000);
    console.log('yay');
  });
  await running;
}

for (let i=0; i < 10; i++) {
  waitAndSayYay();
}
טריק כזה יכול להועיל כשיש לנו פונקציה אסינכרונית שעושה משהו רגיש ולא היינו רוצים פונקציות אחרות "שיתפרצו" באמצע. לדוגמה פונקציה כותבת מספר קבצים לדיסק ורוצה לוודא שקוד אסינכרוני אחר לא ירוץ לפני שהיא תסיים לכתוב את כל הקבצים. יש לכם רעיונות אחרים איך לממש את המנגנון? מוזמנים כרגיל לשתף בתגובות.

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

ToCode
1 419
# מה יקרה אם? הנה טכניקה טובה שאתם יכולים לנסות בפעם הבאה שתגיעו ללמוד משהו חדש: ניסוי לימודי. המשחק בנוי מ-3 שלבים: ## אני חושב שיקרה X השלב הראשון הוא קל - אתם מסתכלים על משהו שקשור לדבר שאתם לומדים ומנחשים התנהגות חדשה שלו. לדוגמה: 1. אני חושב שאם אכתוב את הקוד הזה הוא ידפיס את התוצאה ההיא. 2. אני חושב שאם אשווה בין המחרוזת "2" למספר 2 בפייתון אקבל שהם שווים. 3. אני חושב ששני קונטיינרים בדוקר יכולים לדבר אחד עם השני, גם אם הפעלתי אותם מקבצי docker-compose שונים, בתנאי שהם יושבים על אותה רשת. 4. אני חושב שהקוד בדוגמה יעבוד גם אם אמחק את השורה הרביעית ממנו. 5. אני חושב שאם אוסיף sleep לפני העליה של בסיס הנתונים אז גם השרת לא יצליח לעלות. אתם יכולים לאתגר את עצמכם כמה שאתם רוצים. אני אוהב כשאני לומד משהו חדש או קורא תיעוד על משהו פשוט לרשום כמה שיותר דברים שאני חושב שיקרו או שלא יקרו. ## קרה Y בשלב השני במשחק גם אין הפתעה גדולה. אנחנו כותבים את הדבר שחשבנו לכתוב ובודקים מה קורה. לפעמים מה שחשבנו שיקרה באמת קרה, ולפעמים יקרה משהו אחר. מה שחשוב הוא לשים לב למה באמת קרה ולא לחפש רק את התוצאה שרציתם. ## למה זה קרה והשלב השלישי הוא החלק הקשה ובו צריך להבין ולהסביר למה קרה מה שקרה. מה חשבתם בהתחלה, מה גיליתם, ומה למדתם בתהליך. אז חזרה לדוגמה - חשבתי ששני קונטיינרים שרצים משני קבצי docker compose שונים יכולים לדבר. הפעלתי וראיתי שהם לא מצליחים לדבר, אפילו שהם מחוברים על אותה רשת. עכשיו בשלב השלישי אני מנסה להבין למה. אני מסתכל על הרשת, מזהה שהשם של הקונטיינרים ברשת שונה ממה שחשבתי שיהיה, משנה את השם ורואה שהם כן מצליחים לדבר כשמשתמשים בשמות הנכונים. מפה אני ממשיך כדי לבדוק איך קובעים את השם ברשת של קונטיינר ורואה שאני יכול להגדיר את השם ולתקשר בין קונטיינרים. או בדוגמה של פייתון - חשבתי שהשוואה בין המחרוזת "2" למספר 2 תתן ערך "אמת"; ניסיתי וראיתי שדווקא פייתון מחזיר תשובה שלילית. אז המשכתי לראות איך לבדוק מה הטיפוס של ערך מסוים, איך להמיר בין טיפוסים ובסוף איך להשוות בין מספר למחרוזת, פעם אחת עם המרה של המספר למחרוזת ופעם שניה עם המרה של המחרוזת למספר. צריך להגיד, הרבה פעמים בשלב השלישי לא תהיה לנו תשובה. חשבתי שהוספה של sleep במקום מסוים בבדיקה תגרום לבדיקה לעבוד, זה הצליח, ועדיין אני לא לגמרי מבין למה זה קרה או איך לגרום לבדיקה לעבוד בדרך אחרת. זה בסדר גמור. אני שומר פתק חדש לתעלומות כאלה. מתישהו יהיה זמן לחזור לזה, אולי כשאכיר טוב יותר את הטכנולוגיה, ואז אמצא את הפיתרון. ## מה טוב בשיטה הזאת רוב מוחלט של תהליכי הלימוד שנכשלים נכשלים בגלל שבשלב מסוים מאבדים מוטיבציה. משהו נראה מעניין, מתחילים ללמוד אותו, לא מצליחים לכתוב אף תוכנית ומתייאשים. שיטת הניסויים עוזרת לשנות את הפוקוס: במקום להתאמץ לפתור תרגילים שמישהו אחר כתב, אנחנו עושים ניסוי על משהו שאנחנו כבר יודעים לעשות. מתחילים עם משהו שעובד, זורקים ניחוש לגבי איך הוא יעבוד עם שינוי קטן ואז מנסים ובודקים את התוצאה. משחק כזה פחות רגיש לתסכולים ואפשר לשחק אותו במנות קטנות. קצת כמו במשחק מטקות, גם ב"מעניין! ומה יקרה אם..." קל לראות את המהלך הבא, וגם אם הפלתם את הכדור תמיד אפשר להרים ולהתחיל מחדש.

ToCode
1 419
      clearInterval(timer);
    });

    return {
      data,
      inc,
    };
  }
};
</script>

<template>
  <div>
    <button @click="inc">{{data.value}}</button>
  </div>
</template>
אוקיי אז בספירת שורות מצבנו לא מאוד שונה אבל הקוד כן נראה אחרת, לפחות חלקית: 1. מפתח props לא השתנה, אבל כל המפתחות האחרים באוביקט המיוצא הוחלפו במפתח אחד בשם setup. 2. הפונקציה setup מקבלת את ה props בתור פרמטר ומבצעת את כל מה שהמפתחות המיוחדים מהגירסה הקודמת היו עושים. 3. בשביל להגדיר את data שעליו נשמר המידע הריאקטיבי השתמשתי בפונקציה של ויו שנקראת reactive. אגב עכשיו אנחנו יכולים לשמור מספר אוביקטי data באותה קומפוננטה. 4. הפונקציה inc יכולה לגשת למשתנים הריאקטיביים של data בזכות JavaScript Closures. 5. המפתחות mounted ו unmounted הפכו לפונקציות onMounted ו onUnmounted, כל אחת מהן מקבלת כקלט פונקציה. שוב זה מלהיב כי עכשיו אנחנו יכולים להוסיף כמה קודי טיפול לכל אירוע (כלומר אפשר לקרוא ל onMounted כמה פעמים עם דברים שונים שצריך לעשות). גם כאן הגישה למשתנים משותפים נעשית באמצעות JavaScript Closures ולא צריך את this. 6. פונקציית setup מחזירה את אותו אוביקט "דבק" שבגירסה הקודמת ויו יצר בשבילנו שכולל את הממשק לגשת לכל המידע המעניין בקומפוננטה. הפעם אנחנו מחליטים מה ייכנס או לא ייכנס לאוביקט זה. אוביקט הדבק שאנחנו מחזירים הוא מה שקוד הטמפלייט יכול לגשת אליו והוא שמחבר בין קוד הטמפלייט לקוד הסקריפט. ## גירסה 3 - setup script המבנה של Composition API מאפשר יותר שליטה על הקומפוננטה בהשוואה לכתיב הקלאסי. אם נרצה לקחת חלק מסוים בהתנהגות ולשתף אותו בין קומפוננטות כל מה שצריך לעשות הוא להוציא את החלק הזה לפונקציה נפרדת. לדוגמה אם הייתי רוצה לקחת את הרעיון של שעון שמוריד 1 מאיזשהו ערך הייתי יכול לכתוב פונקציה כזאת:
function withCountdown(start) {
    const ticks = ref(start);
    let timer;

    onMounted(() => {
      timer = setInterval(() => {
        ticks.value -= 1;
      }, 1000);
    });

    onUnmounted(() => {
      clearInterval(timer);
    });

    return ticks;
}
ואז קומפוננטה היתה יכולה להשתמש בשעון באופן הבא:
export default {
    setup() {
        const ticks = withCountdown(100);
        return { ticks };
    }
};
שיתוף קוד בין קומפוננטות הופך הרבה יותר קל כשיש לנו Composition API. אבל הצד השני של המטבע הוא שהכתיב באמצעות אוביקט הוא קצת מסורבל. השלב הבא באבולוציה הוא להוסיף מנגנון לקומפיילר של ויו כדי שאני אכתוב רק את החלקים המעניינים והוא ישלים כבר לבד את כל השאר. הקוד בגירסה השלישית נראה כך:
<script setup>
import { ref, reactive, onMounted, onUnmounted } from 'vue';

const props = defineProps({
  start: Number,
  step: Number,
});

const data = reactive({ value: props.start });
function inc() {
  console.log(data);
  data.value += props.step;
}

let timer;

onMounted(() => {
  timer = setInterval(() => {
    data.value -= 1;
  }, 1000);
});

onUnmounted(() => {
  clearInterval(timer);
});

</script>

<template>
  <div>
    <button @click="inc">{{data.value}}</button>
  </div>
</template>
פה כבר רואים חיסכון במספר שורות הקוד בתוכנית ולדעתי זו הגירסה הכי נקיה: 1. הקוד כולו שאני כותב באופן אוטומטי יוכנס לתוך פונקציית setup. 2. המקרו defineProps מחליף את המפתח props ואת העברת המשתנה props לפונקציה שהוגדרה ב setup. 3. אין צורך להגדיר אוביקט ולהחזיר אותו, זה יקרה אוטומטית. 4. אין צורך לבחור איזה משתנים ישמרו בתור שדות של אותו אוביקט דבק. הקומפיילר יבחר את כל המשתנים שהגדרתי ב Scope החיצוני ביותר של הסקריפט ויבנה את האוביקט מהם. מבחינת יכולת ופיצ'רים קוד כזה שקול לקוד מהגירסה השניה, אבל מבחינת תחביר החיסכון ב Boilerplate אומר שאני מקבל קוד יותר קצר שיותר נעים לכתוב, לקרוא ולתחזק. בשביל שיהיה קל לשחק עם הקוד העליתי את שלושת הגירסאות של הקומפוננטה למאגר גיט. מוזמנים לשכפל, להריץ ולבעוט בו כמה שתרצו: https://github.com/ynonp/vue-component-evolution.

ToCode
1 419
# תרגומון Vue: שלוש דרכים לכתוב קומפוננטה המעבר ל Composition API ואחריו ל script setup עלול להיות מבלבל כשמתחילים לעבוד ב Vue: דוגמאות באינטרנט יכולות להופיע בכל אחד משלושת הכתיבים ואפילו התיעוד הרשמי לא בחר המלצה ברורה. כך יוצא שמצד אחד כשמתחילים ללמוד את הפריימוורק אנחנו צריכים לבחור כתיב מסוים, אבל לאורך הדרך בכתיבה אם לא ניפתח להכיר את שני הכתיבים האחרים יהיה לנו מאוד קשה. בדיוק בשביל זה אני רוצה להציע תרגומון מהיר בין שלושת הכתיבים - בהמשך הפוסט תמצאו את אותה קומפוננטה כתובה שלוש פעמים, כל פעם בגישה אחרת, וכך תוכלו לראות את הדומה והשונה בין הגישות ואני מקווה שגם להרגיש יותר בנוח לתרגם ביניהן. ## גישה 1 ויו קלאסי בשביל התרגומון שלי אני רוצה לכתוב קומפוננטה של Counter שמציגה כפתור ועליו מספר הפעמים שלחצו עליו, ומדליקה גם שעון כך שכל שניה שעוברת באופן אוטומטי ירד 1 מהערך. תיבול אחרון הוא להוסיף אפשרות לקוד חיצוני להעביר את הערך הראשוני של ה Counter ובכמה להגדיל את הערך בכל לחיצה בתור Properties. בכתיב הקלאסי של Vue אני כותב את הקומפוננטה בקובץ עם סיומת Vue. בלוק הסקריפט בקובץ צריך לייצא אוביקט שיגיד ל Vue איך ליצור את הקומפוננטה באמצעות מתודות עם שמות מיוחדים ש Vue יודע להסתכל עליהם. הנה הקוד:
<script>
export default {
  data() {
    return {
      value: this.start,
    }
  },

  props: {
    start: Number,
    step: Number,
  },

  methods: {
    inc() {
      this.value += this.step;
    }
  },

  mounted() {
    this.timer = setInterval(() => {
      this.value -= 1;
    }, 1000);
  },

  unmounted() {
    clearInterval(this.timer);
  }

};
</script>

<template>
  <div>
    <button @click="inc">{{value}}</button>
  </div>
</template>

<style scoped>
</style>
כל המפתחות באוביקט הם שמות שמורים של Vue: 1. המפתח data מגדיר משתנים ריאקטיביים שקוד הטמפלייט יוכל להשתמש בהם. 2. המפתח props מגדיר איזה מאפיינים יגיעו מבחוץ בתור Properties. 3. המפתח methods מגדיר פונקציות שקוד הטמפלייט יוכל להשתמש בהן. 4. המפתחות mounted, unmounted נקראים Lifecycle Events והם מאפשרים להריץ קוד אוטומטית כשקורה משהו - למשל כשקומפוננטה נכנסת למסך או יוצאת מהמסך (ויש עוד הרבה מהם). בגלל שכל פעולה נכתבת בפונקציה נפרדת, באופן אוטומטי המשתנה המיוחד this מתיחס לאוביקט Vue ש"מאחד" את כל הגישה לקומפוננטה. בפונקציה inc השתמשתי ב this.value כדי לגשת למשתנה value שהוגדר בתוך data. בפונקציה unmounted השתמשתי ב this.timer שהוגדר בפונקציה mounted. בקיצור כל המתודות המיוחדות יכולות לשמור מידע על אותו this. גם ויו עצמו ישמור עליו מידע, למשל הוא ישמור עליו את כל השדות באוביקט data ואת כל ה Properties שעברו לקומפוננטה. ## גירסה 2 - מעבר ל Composition API בעיה אחת שקל לראות עם הכתיב הקלאסי היא שצריך מנגנון מיוחד כדי לשתף "לוגיקה הקשורה ל State" בין מספר קומפוננטות. לוגיקה הקשורה לסטייט זה לוגיקה שמורכבת גם מפונקציות, גם משדות מידע ב data וגם מאירועי מחזור חיים. לדוגמה אם הייתי רוצה לקחת את הרעיון של אינטרוול שכל שניה מוריד ערך של משתנה באחד ולהשתמש בו בקומפוננטה נוספת, אז בכתיב הקלאסי לא ברור איך אני יכול לקחת את החלק הזה בהתנהגות של הקומפוננטה החוצה מהקומפוננטה ולהשתמש בו במקום אחר. היו כל מיני דרכים להתמודד עם הסיפור הזה לאורך השנים אבל הדרך שהתייצבה בתור פיתרון מומלץ נקראת Composition API. הרעיון שלה הוא לתת לנו יותר שליטה על מה שקורה ביצירת הקומפוננטה ולהפוך את כל המפתחות המיוחדים שראינו לפונקציות שאנחנו צריכים לקרוא להן בצורה יזומה. נקודת הכניסה שלנו לקומפוננטה תהיה עכשיו פונקציה בודדת בשם setup. גם ב Composition API עדיין משתמשים במפתח מיוחד בשם props בשביל להגדיר את המאפיינים שאנחנו מקבלים מבחוץ, אבל כל שאר ההתנהגות נכנסת לתוך קוד שאנחנו מריצים בפונקציה שנשמרת במפתח המיוחד setup. הקוד נראה כך:
<script>
import { ref, reactive, onMounted, onUnmounted } from 'vue';

export default {
  props: {
    start: Number,
    step: Number,
  },
  setup(props) {
    const data = reactive({ value: props.start });
    const inc = function() {
      console.log(data);
      data.value += props.step;
    }
    let timer;

    onMounted(() => {
      timer = setInterval(() => {
        data.value -= 1;
      }, 1000);
    });

    onUnmounted(() => {

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

ToCode
1 419
# מה לעשות כשגילית שיש דרך יותר טובה? התשובה הקלה- לשנות. אין שום תירוץ להמשיך להשתמש ב componentDidUpdate, componentWillUnmount ו componentDidMount בריאקט אם אתה יודע איך להשתמש ב useEffect. ואין שום תירוץ להמשיך לכתוב var אחרי שאתה יודע על let ו const. ועדיין- החיים האמיתיים קצת יותר מאתגרים. אי אפשר לרוץ על פרויקט שלם ולהתחיל לשנות את כל המקומות שכתבו בהם var ל let או const, כי בפרויקט מספיק גדול לא נצא מזה. אי אפשר להפוך את כל הקומפוננטות ריאקט מכתיב קלאסים לכתיב פונקציות ו Hooks ביום אחד. המלצה יותר מרוככת היא לעשות את ההתאמות רק על קוד חדש שכותבים, וגם היא לא תמיד ישימה. לפעמים נוח בקוד חדש לעשות שימוש חוזר בקוד ישן, ולטובת העניין צריך לעבוד כמו שעבדו פעם. ולפעמים קוד חדש משתמש ב Data ישן או צריך להיות עקבי עם צורת עבודה ישנה, ואז שוב אי אפשר לשנות ולתקן טעויות. במקום לאכול את הלב כל פעם שגיליתם דרך טובה יותר ולהתעצבן שאי אפשר ליישם אותה, כדאי לבנות לעצמכם מערכת כללי תחזוקה לפרויקט שתעזור מצד אחד לא להתיש את עצמכם אבל מצד שני כן תעודד שכתוב ותנועה קדימה. לדוגמה אפשר להחליט ש: 1. פעם בחודש מקדישים יום לשדרוג תלויות. 2. פעם בשבוע מקדישים שעתיים ל Refactoring של קוד כדי שיהיה קל יותר לשלב אותו בשיטות עבודה חדשות. 3. לפני שמתקנים באג מקדישים שעה לכתיבת בדיקה אוטומטית שמוודאת את הבאג הזה ואת התיקון. אם לא הספקנו בשעה מוותרים על הבדיקה. 4. כל יום מקדישים רבע-שעה לקריאת מאמר מקצועי כדי להיחשף לשיטות עבודה חדשות וטובות יותר. 5. פעם ברבעון הולכים לכנס או לקורס מקצועי כדי להיחשף לשיטות עבודה חדשות וטובות יותר בצורה מרוכזת. כללי עבודה מסודרים שמשלבים את הלימוד וההתמקצעות בתוך היום יום הם המפתח להתפתחות מקצועית שלא תלויה במוטיבציה - והם שיאפשרו לכם ולפרויקט באמת לגדול לאורך זמן.

ToCode
1 419
# מינימליזם איזה מזל, יש HDMI. זאת היתה המחשבה הראשונה שלי כשהגעתי לכיתת ההדרכה עם המחשב ומתאם HDMI יחיד. נכון HDMI זה כבר די סטנדרט אבל עדיין יש קירות עם חיבורי VGA והדבר האחרון שאתה רוצה זה להגיע לקורס בלי המתאם הנכון. מצד שני זה לקח רק כמה שניות אחרי שחיברתי את המחשב בשביל לאבד את המצב רוח. המקרן עם ה HDMI התחיל להבהב. ה IT דווקא היו רגועים ואמרו שכבר תקופה שיש להם בעיות עם המקרן הזה והמליצו לעבור כיתה. עברנו רק בשביל לגלות שגם בכיתה החדשה המקרן מהבהב ואז נפל לי האסימון שאולי הבעיה בכלל בהגדרות המחשב. הורדת ה Refresh Rate ל 30 הרץ תיקנה את הכל, אבל עכשיו כבר היינו בכיתה השניה. מה הצעד הבא? חוזרים למקרן הראשון או נשארים? ה Debugging של המקרן לא היה שונה מהרבה סצינות Debugging שאני עובר בתור מפתח: מנסים משהו קטן, ואז עוד אחד, ואז עוד אחד עד שבסוף מגיעים לגירסה של המערכת שעובדת. אבל עובדת זה לא מספיק. מינימליזם בקוד אומר שאנחנו רוצים להכניס למערכת רק את מה שהמערכת צריכה. הכנסת "ניסויים" שלא באמת עזרו עלולה להוסיף עוד באגים ועוד סיבוך לקוד, שאחרי זה יהיה לנו קשה להיפטר מהם. הנקודה שהמערכת עובדת אינה נקודת הסיום. אחריה צריך לזהות מה בדיוק קרה שם, למה היא לא עבדה קודם ואיזה שינוי בדיוק הוא זה שאחראי לזה שהקוד התחיל לעבוד, ובסוף להמשיך ולחפש את הדרך הפשוטה והמדויקת ביותר לבצע את אותו שינוי. עבודה מדויקת היא מהמאפיינים של מתכנתים טובים ומינימליזם בקוד היא מאפיין טוב של מערכות טובות. אלה שני דברים שלא שווה להתפשר עליהם.