1 419
订阅者
-124 小时
-17 天
-130 天
帖子存档
1 420
# הייתי רוצה להיות טבח
בחיים לא שמעתי על טבח שקם בבוקר ואומר "היום אני הולך לנסות לבשל פסטה. אני אתחיל - אולי זה יהיה מוכן לארוחת צהריים, אולי לארוחת ערב, ואולי רק לשבוע הבא". וגם אין מצב כשהפסטה כבר על האש שהטבח יסתכל עליה בקטע של "טוב זה נראה שעוד 5 דקות היא תהיה מוכנה, אבל גם יש מצב שזה ייקח עוד שעתיים או עוד שבועיים, אי אפשר לדעת".
כשאתה מתיישב להכין פסטה יש לוח זמנים ברור מה הולך לקרות מתי. אתה יכול לפשל עם הפסטה, אבל אין מצב להסתכל על הסיר ולהתלבט מה הדבר הבא שצריך לעשות.
ואנחנו? איפה. בן אדם קם בבוקר לכתוב פיצ'ר למערכת, עוברות שעתיים ואין לך מושג אם הפיצ'ר הולך להיות מוכן עד הצהריים, עד הערב או עד שבוע הבא. ובשום שלב בתהליך (אפילו אחרי שהפיצ'ר כבר מוכן ועובד) אתה לא יודע אם עוד שניה לא יתגלה איזה באג שישלח אותך לעוד שבוע עבודה.
תסכול בצד - חוסר היכולת לקבוע לוחות זמנים לעבודה הוא חלק מובנה בעבודה של מתכנתים. או כמו שאומרים אצלנו "זה לא באג, זה פיצ'ר". עכשיו כדאי שנתחיל להתרגל ולבנות לעצמנו שיטות עבודה שמחבקות את חוסר הידיעה.
1 420
# ידע חוצה שפות
ביטויים רגולאריים יעבדו כמעט בלי שינוי בכל שפת תכנות שתגיעו אליה. גם כשתנסו לפתוח קובץ בכל שפת תכנות תמצאו את עצמכם מעבירים פרמטר בשם Open Mode שיכול לקבל תמיד את אותו סט של ערכים. הפקודה strftime של Python מקבלת מחרוזת שמייצגת פורמט תאריך ומורכבת מאחוזים ואותיות, וזהה לגמרי לזו של strftime של רובי וגם של C++, perl ושפות רבות נוספות.
מי שיודע לעבוד עם Promises ב JavaScript יקלוט מהר מאוד איך להשתמש ב asyncio ב Python ואפילו ב std::async של C++ (למרות שבינינו שום דבר ב C++ לא נקלט מהר מאוד).
אותו דבר לגבי עבודה עם REST ו GraphQL, כתיבת שאילתות SQL, פיענוח של קבצי XML, ואפילו Multi Threaded Programming. הרבה מאוד מהידע שלנו יכול להיות בעל ערך במעבר לשפה חדשה.
בהתלבטות אם כדאי ללמוד נושא מסוים, כדאי לקחת בחשבון את מספר שפות התכנות שנושא זה מופיע בהן בצורה כזו או אחרת. ככל שנשקיע באיסוף מיומנויות חוצות שפות כך זה הולך להשתלם ולהחזיר את ההשקעה ברווח גדול בעתיד.
1 420
# יוניקוד כל הדרך ב Python2
אחד הדברים שמבלבלים ב Python2 הוא שמחרוזות אינן Unicode כברירת מחדל. הדבר מייצר המון טעויות של מתכנתים עם המון הודעות שגיאה שונות ומשונות. הנה כמה דוגמאות ופיתרונות שלהן.
## השוואה בין יוניקוד למחרוזת
ב Python2 יש שני סוגים של אוביקטים לייצוג טקסט: יש את str שמייצג רצף של בתים ואת unicode שמייצג רצף של אותיות. ההבדל ביניהן הוא קריטי, האורך של המילה "שלום" כמחרוזת בתים הוא 8, אבל בתור רצף אותיות הוא 4. או בפייתון:
>>> len('שלום')
8
>>> len(u'שלום')
4
גם השוואה בין יוניקוד למחרוזת לא תעבוד לכם כי מדובר בשני אוביקטים שונים, והנה הניסיון עם הודעת השגיאה:
>>> 'שלום' == u'לשום'
__main__:1: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal
False
כשאתם רואים את ההודעה לכו לבדוק מה נמצא בתוך המשתנים שלכם וחפשו איזה מהם הוא מהטיפוס הלא נכון.
## פורמט בין יוניקוד למחרוזת
עוד הודעה מוזרה מתקבלת כשמנסים להפעיל את format ולערבב בין יוניקוד למחרוזות רגילות. זה נראה כך:
>>> print('{} / {}'.format(u'א', u'ב'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u05d0' in position 0: ordinal not in range(128)
או בכיוון ההפוך:
>>> print(u'{} / {}'.format('א', 'ב'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd7 in position 0: ordinal not in range(128)
בשני המקרים מדובר באותה בעיה - ניסינו לערבב מחרוזות str עם unicode, מה שפשוט לא עובד. הפיתרון? יוניקוד כל הדרך:
>>> print(u'{} / {}'.format(u'א', u'ב'))
## בלבול בין encode ל decode
טעות שלישית היא בלבול בין encode ל decode בשביל להמיר בין str ל unicode. צריך לזכור שהמעבר מ unicode ל str נקרא Encode, והמעבר ההפוך מ str ל Unicode נקרא decode. אנחנו מפענחים קלט שהגיע מבחוץ ולכן הוא בפורמט str כדי לשמור אותו בזיכרון, ואנחנו מקודדים מידע מהזיכרון כדי שנוכל להעביר אותו לאחרים.
לכן הקוד הזה לא עובד כי צריך לפענח מידע שמגיע מבחוץ (ולא לקודד אותו):
>>> s = codecs.encode('שלום', 'utf8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd7 in position 0: ordinal not in range(128)
וזה לא עובד כי צריך לקודד מידע מהזיכרון כדי להוציא אותו לפורמט שבחרתם (ולא לפענח אותו):
>>> s = codecs.decode(u'שלום', 'utf8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/encodings/utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
וכאילו שזה לא מספיק מוזר צריך לזכור שה Exceptions האלה הן דווקא הדבר הטוב שקורה. ספריות רבות יחליפו חלק מהאותיות בסימני שאלה במקום לזרוק לכם Exceptions ואז הרבה יותר קשה לגלות איפה הטעות.1 420
# המכשול
מה שמפריד בין אנשים שמצליחים להרים פרויקטים לאנשים שנתקעים הוא לא העובדה שהראשונים יודעים מה הם עושים ותמיד הכל הולך להם, אלא מה כל קבוצה עושה אל מול המכשול.
המכשול זה הקוד שכתבת בדיוק כמו בתיעוד אבל משום מה אצלך לא עובד.
זה הדבר המוזר הזה שאתה מנסה לעשות שלא מופיע בתיעוד ושנראה שאף אחד באינטרנט לא עשה קודם.
זה הגילוי שהספריה שרצית לבחור בה בעצם לא יכולה לעשות את הדבר הזה שרצית.
זו ההבנה שמה שנראה כמו יומיים עבודה הולך לקחת חודש במקרה הטוב.
בכל פרויקט יש מכשול והרבה פעמים יש יותר מאחד. המכשול זאת הנקודה בה אנשים מתייאשים, זה החודש הראשון בחדר כושר, או השנה הראשונה בעבודה כעצמאי. אבל המכשול הוא גם מה שהופך את הדבר שאתה מנסה לבנות לבעל ערך, והוא הסיבה שלא כולם עושים את הפרויקט הזה. והדרך היחידה להתמודד עם המכשול היא להגביר מהירות, להשקיע יותר שעות, להיכנס לעובי הקורה ולפתור את הבעיה בכלים שאפילו לא חשבת שיש לך.
התגברות על מכשולים ובניה מוצלחת של הפרויקטים שהתחלתם הם הדברים שלאורך זמן הופכים אתכם למתכנתים טובים יותר.
1 420
# הקשר (context)
הסיבה המרכזית שקשה לנו ללמוד וליישם דברים חדשים נקראת "הקשר" או באנגלית Context. בשביל להבין את זה צריך להיזכר רגע איך המוח שלנו עובד.
אפשר לדמיין את המוח בתור רשת של כבישים שמחברים בין אתרים שונים. האתרים הם הדברים שאנחנו יודעים למשל חתימה של פונקציה מסוימת בשפת תכנות או איך להשתמש בפקודת for; הכבישים הם ההזדמנויות השונות בהן השתמשנו באותו פריט ידע. ככל שאתר מסוים מחובר ביותר כבישים, כלומר ככל שזה משהו שאנחנו משתמשים בו לעתים יותר קרובות בחיים וביותר הקשרים, כך נזכור את זה טוב יותר. עם הזמן כבישים שלא נוסעים בהם נמחקים ואתרים הופכים ללא נגישים וגם ההיפך - ככל שאנחנו מגיעים לאותם אתרים בדרכים חדשות ונוצרים כבישים חדשים כך הזיכרון הופך יותר חי.
קל לראות את האנלוגיה הזאת בפעולה כשמנסים לזכור בעל פה מילה או משפט. אם תנסו לזכור בעל פה מילה בודדת בשפה זרה תראו שזה ממש קשה ואחרי שעתיים אתם שוכחים אותה. מה שמפתיע שדווקא כשמנסים לזכור בעל פה משפט או אפילו סיפור קצר, המילה הראשונה במשפט "מזכירה" לנו את המילים שבאות אחריה וכך קל לנו יותר לזכור.
באותו האופן כשיש לי רשת כבישים טובה סביב נושא שאני לא מכיר, יהיה לי ממש קל ללמוד את הנושא החדש הזה. בגלל זה מתכנתי Java מצליחים ללמוד יחסית מהר C# - ההתנהגות ממופה כמעט אחד לאחד בין השפות, ואפשר להשתמש מחדש באותה רשת כבישים ורק להלביש עליה עוד כמה אתרים.
לעומת זאת המעבר מתכנות Back End לתכנות Front End הוא כבר הרבה יותר מסובך. הכל חדש וצריך לבנות רשת כבישים חדשה סביב אינספור מושגים ורעיונות חדשים. זה פשוט לא דומה לשום דבר שאנחנו כבר מכירים.
מה עושים עם זה? קל- כדאי להבין שלימוד נושא חדש כרוך הרבה פעמים בבניית רשת כבישים חדשה במוח, וככל שנוסיף עוד הצטלבויות, פריטי מידע וקשרים בין הדברים שאנחנו לומדים כך נצליח לזכור אותם טוב יותר. לכן כדאי מאוד גם לקרוא, גם לראות הרצאות ביוטיוב, גם לכתוב קוד, גם לשמוע פודקסט, גם להעתיק קוד מאחרים ולשנות אותו, גם לשמוע רכילויות על האנשים מאחורי הטכנולוגיה ואפילו לחפש את התמונות שלהם ברשת. כמה שאתם יודעים יותר מ"המסביב" של הטכנולוגיה כך תבנו יותר חיבורים במוח לרעיונות החדשים ותוכלו לזכור אותם טוב יותר.
1 420
# רידאקס הוקס
לפני כמה שבועות הסברתי לאנשים בקורס React על Redux ועל כל הדברים המדליקים שאפשר לעשות איתה. ההתחלה היתה מלהיבה וכולם אפילו הצליחו לשרוד את הסיפור על ה Stores והפונקציה reducer. ואז הגענו לחבר את כל העסק הזה ל React ויכולתי לראות קבוצה שלמה של תלמידים מרוכזים נעלמת והופכת לאוסף של מבטים מיואשים. והאמת? אני די מבין אותם.
נניח שיש לי State של אפליקציה שנראה ככה:
const initialState = {
home: [
{ id: 1, text: "buy stuff", done: false },
{ id: 2, text: "clean the kitchen", done: false },
{ id: 3, text: "cook dinner", done: true }
],
work: [
{ id: 4, text: "prepare webinar text", done: true },
{ id: 5, text: "write daily post", done: false },
{ id: 6, text: "prepare slides for talk", done: false }
],
hobbies: [{ id: 7, text: "write a cool tetris game", done: false }]
};
ואני רוצה לכתוב קומפוננטת ריאקט שתציג את כל המשימות בקבוצה מסוימת, עד לא מזמן הייתי צריך לכתוב קוד שנראה כך:
const TaskGroup = connect((state, ownProps) => ({
tasks: state[ownProps.group],
group: ownProps.group
}))(function TaskGroup({ tasks, group }) {
return (
<div>
<h2>{group}</h2>
<ul>
{tasks.map(task => (
<li>{task.text}</li>
))}
</ul>
</div>
);
});
ואני כותב את זה על הלוח ובעצמי לא מבין למה דברים צריכים להיראות ככה, מאיפה כל הסוגריים האלה ומי יום אחד יצטרך לתחזק את הטירוף הזה. וניסיתי, באמת שניסיתי - הצעתי להם להוציא החוצה את הפוקנציה mapStateToProps לפונקציה נפרדת כמו שכולם עושים, או לעצום עיניים בזמן שכותבים את הקוד כמו שכולם עושים, אבל כלום לא עזר.
והנה בזמן שאני כותב את הפוסט הזה ומקטר יושבים אנשים ב react-redux ועושים עבודה. עבודה נפלאה, עבודה שעושה את העבודה שלי הרבה יותר קלה. בקיצור גם הם עברו ל React Hooks. עכשיו אנחנו כבר יכולים לוותר על connect ועל החתימה המביכה שלו ולכתוב קוד שנראה כך:
function TaskGroup({ group }) {
const tasks = useSelector(state => state[group]);
return (
<div>
<h2>{group}</h2>
<ul>
{tasks.map(task => (
<li>{task.text}</li>
))}
</ul>
</div>
);
}
הפקודה useSelector מושכת מידע מה State ומחזירה אותו, וחוסכת לנו את כל העבודה המעיקה עם connect. וכן יש גם useDispatch שמחזירה את הפונקציה dispatch. פרטים נוספים ודוגמאות בתיעוד https://react-redux.js.org/api/hooks.1 420
# פיתוח משחק צוללות ב React, TypeScript ו MobX. חלק 2.
בחלק הקודם של המדריך פיתחנו את הלוגיקה של משחק הצוללות. היום נוסיף את הפונקציה repr וגם מספר בדיקות אוטומטיות כדי לוודא שהקוד שלנו לא נשבר.
## הפונקציה repr
בסוף הפוסט אתמול הצעתי לכם לכתוב את הפונקציה BoardSquare.repr שמחזירה מה יש במשבצת. זה תרגיל נחמד בפיתוח מונחה עצמים כי במשבצת יכולים להיות כמה סוגים של דברים, וכל דבר יכול להציג את עצמו בצורה קצת אחרת.
במקום לשים את כל הלוגיקה במקום אחד אני מוסיף פונקציה בשם repr לכל אחד מהפריטים שיכולים להיות במשבצת. כך הצוללת:
abstract class Submarine extends Sea {
// ...
repr() {
if (this.sank) {
return "X";
} else {
return "/";
}
}
}
הים:
class Sea {
// ...
repr() {
return "0";
}
}
וכמובן המשבצת עצמה:
class BoardSquare {
// ...
repr() {
if (this.revealed) {
return this.item.repr();
} else {
return " ";
}
}
}
המשבצת אחראית לזהות האם היא כבר נחשפה, אבל אם כן כל פריט אחראי לצייר את התוכן שלו עצמו. בצורה כזאת הקוד שלנו יתמודד יפה גם עם שינויים עתידיים, למשל אם נוסיף למשחק גם דולפינים או יצורים אחרים.
## כתיבת בדיקות יחידה
בפרויקט שיצרנו עם create-react-app אנחנו מקבלים במתנה את התשתית לכתיבה והרצה של בדיקות יחידה. הוסיפו בתוך התיקיה lib וליד הקובץ submarines.tsx את הקובץ submarines.test.tsx ובו התוכן הבא:
import { Board, VerticalSubmarine, HorizontalSubmarine } from "./submarines";
test('can hit the sea', () => {
const b = new Board(10, 10);
b.bomb([0, 0]);
expect(b.cellAt([0, 0])?.revealed).toBe(true);
expect(b.repr()[0]).toBe('0');
});
test('can hit a submarine', () => {
const b = new Board(10, 10);
const s = new HorizontalSubmarine(4);
b.addSubmarine(s, 0, 0);
b.bomb([0, 0]);
expect(b.cellAt([0, 0])?.revealed).toBe(true);
expect(b.repr()[0]).toBe('/');
});
test('can sunk a submarine', () => {
const b = new Board(10, 10);
const s = new HorizontalSubmarine(4);
b.addSubmarine(s, 0, 0);
b.bomb([0, 0]);
b.bomb([0, 1]);
b.bomb([0, 2]);
b.bomb([0, 3]);
expect(b.cellAt([0, 0])?.revealed).toBe(true);
expect((b.cellAt([0, 0])?.item as HorizontalSubmarine).sank).toBe(true);
expect(b.repr()[0]).toBe('X');
expect(b.repr()[1]).toBe('X');
});
הפקודה test אחראית על הרצת תסריט בדיקה. פקודה זו משתמשת בפקודה נוספת בשם expect כדי לזהות שדברים מסוימים עובדים כמו שרצינו (או לא). לדוגמא בבדיקה הראשונה אנחנו יוצרים לוח, מפציצים את המשבצת השמאלית עליונה ומקווים שהיא אכן מזהה שהיא הופצצה.
המבנה של expect ואז toBe נראה מבלבל בהתחלה אבל אחרי שתתרגלו תראו שדווקא מאוד קל לקרוא אותו.
אחרי שתסיימו לכתוב את הבדיקות תוכלו להריץ אותן עם:
$ yarn test
מתוך שורת הפקודה.
וכשתסיימו הפרויקט כנראה יראה דומה לגיטהאב שלי בקישור: https://github.com/ynonp/mobx-submarines-demo/tree/bb7ba1e67cf8daaab35c5e6ecfd0337a1c5ab970.
## תרגילים להרחבה
סיימתם לכתוב את הבדיקות והכל עובד? נשאר לכם עוד קצת זמן? הנה כמה רעיונות להרחבה:
1. מה קורה אם ניסיתי לשים צוללת מחוץ ללוח? מה קורה אם הצוללת שלי קיבלה גודל שלילי? ומה אם אני מפציץ את אותה משבצת שוב ושוב? כתבו בדיקות לכל מקרי הקצה שאתם יכולים לדמיין ותקנו את הקוד כך שיתאים לציפיות שלכם.
2. תשתית הבדיקות ש create-react-app יצר בשבילנו נקראת jest. לכו לקרוא קצת על הפקודה expect בתיעוד של jest כדי לקבל רעיונות לדברים נוספים שתוכלו לבדוק. קישור לתיעוד: https://jestjs.io/docs/en/expect.1 420
# בעוד שלוש שנים
בעוד שלוש שנים את תהיי בעבודה אחרת, עם בוס אחרת ופרויקט אחרת. עם דאגות חדשות, חברים חדשים וטכנולוגיות שעדיין לא שמעת עליהן. וכשתלכי להתראיין לעבודה החדשה הזאת וישאלו אותך אם יש לך פרויקט להראות, זה לא ממש יעזור לספר שעבדת ממש קשה במקום הקודם (שעשה דברים מדליקים שאי אפשר להראות), או שעשית המון שעות נוספות.
כשמדובר בקוד שעה ביום זה לא הרבה, אבל אם מתמידים יום אחרי יום אחרי יום, השעה ביום הופכת ל-7 שעות בשבוע, ל 30 שעות בחודש ול 365 ימים בשנה. בעוד שלוש שנים השעה ביום שלך תתן לך פרויקט בהיקף של מעל אלף שעות פיתוח. זה כבר פרויקט שאפשר להראות אותו בשמחה למעסיק הבא, ושאולי אפילו יכול להכניס קצת כסף לתקופה שבין העבודות.
1 420
# אז הלכתי לעשות את המבחנים של לינקדאין כדי שאתם לא תצטרכו
לינקדאין הוסיפו לפני נצח את האופציה של Skills כך שאתם יכולים לציין איזה מיומנויות יש לכם, ואנשים אחרים יכולים לסמן שאתם באמת יודעים את הדברים האלה שאתם טוענים שאתם יודעים. זה היה אמור לתת מנגנון פשוט יותר מההמלצות הקלאסיות, כי לאף אחד אין כח לכתוב המלצה מסודרת.
וזה עבד. בערך. כי היום לכולם יש מלא Skills ורוב הפעמים אין שום קשר בין ה Skills שלך לבין הדברים שאתה עושה ביום יום. מספיק שמישהו פעם אחת אמר ללינקדאין שאני יודע תכנות מונחה עצמים וזה מופיע אצלי ב Skills לנצח נצחים.
בשביל להתמודד עם זה לינקדאין הוסיפו (גם די מזמן אגב) אופציה של מבחנים על Skills. הרעיון לשים במקום בולט את ה Skills שבאמת יש לך, באמצעות מבחן של 15 שאלות על אותו Skill. עברת את המבחן? תקבל סמל קטן מלינקדאין וכולם יוכלו לראות שאתה באמת יודע תכנות מונחה עצמים ולא סתם מקשקש.
וכמו שסיפרתי בכותרת נכנסתי היום לעשות את המבחן על גיט בשביל לראות מה זה, והאמת שדי נהניתי והמשכתי גם למבחן על ריאקט ועל JavaScript. אם אתם אנשים שאוהבים מבחנים אמריקאים מבלבלים ולפעמים לא מדויקים אז אולי גם אתם תהנו מהם. כמה טיפים אם בכל זאת תחליטו לשחק עם זה:
1. כדאי לעשות מבחנים על Skills שמופיעים אצלכם גבוה בפרופיל. הצלחה במבחן של לינקדאין נחשבת הרבה פחות מהמלצות חברים ומתוך ה-3 מבחנים שאני עשיתי רק זה של ה JavaScript מוצג במקום שאפשר לראות אותו.
2. נראה שחלק מהשאלות נכתבו בכוונה בשביל לבלבל, אבל יש גם שאלות ממש נחמדות. אין המון זמן לשאלה אבל כדאי לעשות צילום מסך של שאלות שלא ידעתם כדי שתוכלו אחרי זה לעבור על הדברים ולראות למה התכוונו.
3. לינקדאין טוענים שמעבר מבחנים כאלה מקפיץ אותך בתוצאות החיפוש של מגייסים. אני לא מחפש עבודה אבל יהיה מעניין לראות אם בראיה קדימה ה-3 מבחנים שעשיתי יעלו את מספר הצפיות בפרופיל שלי. אעדכן על זה.
4. והכי חשוב בין אם עברתם ובין אם לא - אין מה לקחת ללב. השאלות האלה לא אומרות כלום לגבי היכולת הטכנית שלכם להרים פרויקט או לעשות עבודה טובה בטכנולוגיה מסוימת. זה פשוט אוסף של שאלות טריוויה שבודקות בעיקר כמה טוב אתם מכירים את התיעוד (או כמה מהר אתם יודעים לחפש בגוגל).
