uk
Feedback
ToCode

ToCode

Відкрити в Telegram

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

Показати більше
1 420
Підписники
Немає даних24 години
+27 днів
-230 день
Архів дописів
ToCode
1 420
טיפ סקאלה: הדפסת דיבג באמצע Pipeline בשפות פונקציונאליות דינמיות כמו קלוז'ר או אליקסיר, יש אופרטור Pipeline ששולח את התוצאה של פונקציה אחת בתור קלט לפונקציה הבאה בתור. לדוגמה הקוד הבא בקלוז'ר:
(->> 10
  (range)
  (map #(* %1 %1))
  (reduce +)
  (println))
לוקח את המספר 10, שולח אותו בתור הפרמטר לפונקציה range, אחרי זה לוקח את התוצאה של range בתור קלט לפונקציית ה map, את התוצאה של map הוא שולח ל reduce ואת זה ישלח ל println כדי להדפיס. סך הכל נקבל על המסך את סכום ריבועי המספרים מאפס עד תשע. אם יש בעיה בחישוב אפשר להגדיר בקלות פונקציה שמדפיסה את הפרמטרים שקיבלה ומחזירה אותם, ואז להוסיף אותה באמצע ה Pipeline כדי לראות סטטוס ביניים:
(defn debug [n]
  (println n)
  n)

(->> 10
  (debug)
  (range)
  (debug)
  (map #(* %1 %1))
  (debug)
  (reduce +)
  (println))
הדפסות הביניים עוזרות להבין מה קורה שם ולתקן בעיות כשצריך. במעבר לסקאלה מאוד התגעגעתי למנגנון הזה, כיוון שבסקאלה קריאה בשרשרת לפונקציות משתמשת בתחביר המתודות של תכנות מונחה עצמים. ככה נראה קוד סקאלה מקביל לקלוז'ר מתחילת הפוסט:
  println(
    (0 to 9)
      .map(_.pow(2))
      .sum
  )
אז זה היה פשוט בסקאלה אני לא יכול להשתמש פעמיים בפרמטר של פונקציה אנונימית אבל במקום זה יש לי פונקציה להעלות בריבוע, טווח כולל את המספר האחרון לכן מסיימים בתשע ויש פונקציית sum אז לא צריכים את reduce. ובכל זאת שני דברים פוגעים פה בחוויה - הראשון הוא ש println צריך להיכתב בהתחלה בתור פונקציה, והשני שגם אם אכתוב פונקציית debug כמו שהיתה לי בקלוז'ר היא לא חלק מהפייפליין. לשמחתנו מנגנון ה Extensions של סקאלה מאפשר לפתור את שתי הבעיות יחסית בקלות. אני מגדיר Extension גנרי שיוסיף את הפונקציה debug לכל ערך בשפה. זה נראה ככה:
extension [A](value: A)
  def debug(): A =
    println(value)
    value
}

@main
def main(): Unit =
  println(
    (0 to 9)
      .debug()
      .map(_.pow(2))
      .debug()
      .sum
  )
והפלט:
NumericRange 0 to 9
Vector(0, 1, 4, 9, 16, 25, 36, 49, 64, 81)
285
יותר מזה, בגלל שחלק מהאוביקטים בשפה מחושבים בצורה עצלה (למשל Range), אפשר להוסיף עוד פונקציה שתהפוך איטרטורים לרשימות ואז תדפיס אותם, רק שימו לב לא להפעיל אותה על דברים אינסופיים:

extension [A](value: A)
  def debug(): A =
    println(value)
    value

  def eagerDebug(): A = value match {
    case it: Iterable[_] =>
      println(it.toList)
      value
    case it: Iterator[_] =>
      println(it.toList)
      value
    case _ =>
      println(value.getClass)
      value
  }

@main
def main(): Unit =
  println(
    (0 to 9)
      .eagerDebug()
      .map(_.pow(2))
      .debug()
      .sum
  )
ואם כבר הוספנו את debug נוכל להשתמש בה גם בסוף הפייפליין כדי להדפיס בסגנון קלוז'ר:
@main
def main(): Unit =
  (0 to 9)
    .eagerDebug()
    .map(_.pow(2))
    .debug()
    .sum
    .debug()

ToCode
1 420
סקריפטים ב JavaScript? תנו צ'אנס לדינוזאור אחת הבעיות בשימוש ב node.js לכתיבת סקריפטים היא הקובץ package.json, או יותר נכון הצורך לצרף אותו לסקריפט כדי להתקין את התלויות. התוכנית הבאה ב node.js מתוך קוד הדוגמה של המודול wikipedia על npm לא יכולה לרוץ לבד:
const wiki = require('wikipedia');

(async () => {
 try {
  const page = await wiki.page('Batman');
  console.log(page);
  //Response of type @Page object
  const summary = await page.summary();
  console.log(summary);
  //Response of type @wikiSummary - contains the intro and the main image
 } catch (error) {
  console.log(error);
  //=> Typeof wikiError
 }
})();
בשביל שהיא תעבוד אני צריך ליצור איתה בתיקיה קובץ package.json ולהפעיל npm install או להפעיל
npm install wikipedia
משורת הפקודה לפני הרצה. עכשיו בואו נראה איך אותו טריק יעבוד עם דינו. דבר ראשון צריך לשנות את שורת ה require ל import, ולציין שאני טוען את המודול מ npm כך שקוד התוכנית יהיה:
import wiki from 'npm:wikipedia';


(async () => {
 try {
  const page = await wiki.page('Batman');
  console.log(page);
  //Response of type @Page object
  const summary = await page.summary();
  console.log(summary);
  //Response of type @wikiSummary - contains the intro and the main image
 } catch (error) {
  console.log(error);
  //=> Typeof wikiError
 }
})();
ומכאן זה רק משתפר. אני מריץ את הקוד ודינו מתחיל להזהיר אותי:
$ deno run demo.js

⚠️  ┌ Deno requests env access to "npm_config_no_proxy".
   ├ Run again with --allow-env to bypass this prompt.
   └ Allow? [y/n] (y = yes, allow; n = no, deny) >
שים לב, הוא אומר, הסקריפט מעוניין לקרוא מידע ממשתנה סביבה ואפילו כותב את השם של משתנה הסביבה. אני יכול לאשר עם y או להריץ מחדש עם --allow-end כדי שלא ישאל יותר על גישה למשתני סביבה. אני מאשר וממשיכים לשאלות הבאות. כך זה נראה בסוף:
$ deno run demo.js

✅ Granted env access to "npm_config_no_proxy".
✅ Granted env access to "NPM_CONFIG_NO_PROXY".
✅ Granted env access to "no_proxy".
✅ Granted env access to "NO_PROXY".
✅ Granted env access to "npm_config_https_proxy".
✅ Granted env access to "NPM_CONFIG_HTTPS_PROXY".
✅ Granted env access to "https_proxy".
✅ Granted env access to "HTTPS_PROXY".
✅ Granted env access to "npm_config_proxy".
✅ Granted env access to "NPM_CONFIG_PROXY".
✅ Granted env access to "all_proxy".
✅ Granted env access to "ALL_PROXY".
✅ Granted read access to "/Users/ynonp/Library/Caches/deno/npm/node_modules".
✅ Granted read access to "/Users/ynonp/Library/Caches/deno/node_modules".
✅ Granted read access to "/Users/ynonp/Library/Caches/node_modules".
✅ Granted read access to "/Users/ynonp/Library/node_modules".
✅ Granted read access to "/Users/ynonp/node_modules".
✅ Granted read access to "/Users/node_modules".
✅ Granted read access to "/node_modules".
✅ Granted net access to "en.wikipedia.org".
ואחרי זה מגיע הפלט הרגיל של הסקריפט. אם אני סומך על הסקריפט אני יכול פעם הבאה להריץ אותו עם המתגים:
$ deno run --allow-net --allow-read --allow-env demo.js
כדי לדלג על השאלות. סך הכל כתיבה והרצת סקריפט עם דינו נתנה לי שני יתרונות משמעותיים על פני node: 1. אין צורך בקובץ package.json, כל התלויות רשומות בתוך קובץ הסקריפט וההתקנה קורית אוטומטית בהרצה הראשונה. 2. אני חושש הרבה פחות מקוד זדוני, כי בברירת המחדל הסקריפט רץ עם מעט מאוד הרשאות.

ToCode
1 420
היום למדתי - לא כזה פשוט לחפש מהסוף בביטוי רגולארי התחיל היום Advent Of Code ואומנם אני כנראה לא אצליח לפתור את כל החידות שלו השנה על היום הראשון אי אפשר לוותר. בחידה היומית היה צריך למצוא דברים בתוך טקסטים. לא כזה מסובך עד שנתקלים בטריק הקטן שמקלקל הכל. התרגיל והטריק הסיפור בגדול היה למצוא ספרות בתוך שורת טקסט, כשהספרות יכולות להופיע בתור ספרות ממש כמו 4, 9 או 2 או בתור שם הספרה כמו four, nine או two. אנחנו צריכים למצוא בהינתן שורת טקסט את הסיפרה הראשונה והסיפרה האחרונה בה. למשל בשורה:
24
הסיפרה הראשונה היא 2 והאחרונה היא 4. בשורה:
abc7d
הסיפרה 7 היא גם הסיפרה הראשונה וגם האחרונה. ובשורה:
eightwo
הסיפרה 8 היא הראשונה ו 2 היא האחרונה. ניסוי 1 - חיפוש כל המופעים רעיון ראשון שאפשר לנסות כדי למצוא את הסיפרה הראשונה והאחרונה הוא חיפוש גלובאלי, בפייתון זה יהיה:
>>> digits = [str(i) for i in range(10)] + ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]

>>> digits_r = '|'.join(digits)

>>> re.findall(digits_r, "1abc3")
['1', '3']
וזה עובד עד שזה מפסיק לעבוד:
>>> re.findall(digitsr, "eightwo")
['eight']
כי הבעיה שה t משותף גם ל eight וגם ל two ומנוע הביטויים הרגולאריים כבר איבד את ה t כשהוא מצא את eight. פיתרון - חיפוש הפוך בהיעדר דרך טובה לחפש מהסוף בביטוי רגולארי נדרשת יצירתיות - למשל להפוך את כל הטקסטים לפני החיפוש ואז להפוך חזרה אחרי שמוצאים כדי לדעת איזו סיפרה מצאנו. בפייתון זה קל:
>>> digits_re = '|'.join([d[::-1] for d in digits])
>>> [r[::-1] for r in re.findall(digits_re, "eightwo"[::-1])]
['two']

ToCode
1 420
בדיקות בתור First Class Citizen הקושי הכי גדול בכתיבת בדיקות לתוכנית קיימת היא רשימת התלויות של תוכניות קיימות. באופן טיפוסי כשאנחנו מגיעים לקודבייס נטול בדיקות הקוד משתמש ברכיבים חיצוניים שיהיה קשה להחליף, ויש תלות משמעותית בין אזורים שונים בקוד שלא מאפשרת "לנתק" מנגנונים מסוימים כדי לבדוק אותם בנפרד. התוצאה של כתיבת בדיקות למערכת כזאת היא או בדיקות אינטגרציה ענקיות שבודקות "מה המשתמש היה עושה", וכשהן נכשלות נותנות מעט מאוד אינפורמציה לגבי איפה הבעיה, או בדיקות יחידה קטנות מדי, שלא בודקות שום דבר מעניין. על פניו TDD היה אמור לפתור את הבעיה הזאת, אבל ב TDD הדגש הוא על כתיבת קוד הבדיקות ולא על התשתית או קוד המערכת. במילים אחרות אנשי TDD ישמחו לכתוב Mock Objects כדי שיוכלו לכתוב בדיקה לרכיב מסוים לפני שכותבים את קוד הרכיב. שלב הריפקטורינג ב TDD מגיע בסוף ומתמקד בריפקטורינג של הקוד אחרי שהבדיקה כתובה. בראיה של בדיקות בתור First Class Citizen אנחנו מסתכלים על כלל הקוד ואוסף התלויות שלו בתור משהו שצריך להיבדק בצורה יעילה. זה לא משנה אם הבדיקה נכתבת לפני או אחרי הקוד, הדבר החשוב הוא מה היא בודקת, וכמה קל להריץ אותה. הדבר משפיע על כל שלבי הפיתוח ובחירת הכלים ולפעמים מחייב החלטות קשות, לדוגמה: 1. נעדיף להשתמש בבסיס נתונים שיכול לרוץ מקומית מתוך קוד הבדיקה, במקום בבסיס נתונים שמחייב חיבור לרשת. 2. נארגן את הקוד כדי שחלק כמה שיותר גדול ממנו יוכל לתפקד לפני שמגיעים לממשקים החיצוניים, וכך אפשר יהיה לבדוק הרבה מהקוד גם בלי מוקים. 3. נעטוף קוד שמגיע מספריות חיצוניות כדי שיהיה יותר קל להחליף אותו בקוד בדיקה צפוי. אנחנו רוצים להגיע למצב שתוך פחות מדקה אנחנו יכולים לקבל הבנה לגבי רמת הבשלות של פיצ'ר חדש שכתבנו, וכמה הקוד החדש שובר מנגנונים קיימים. התיחסות לבדיקות בתור חלק בלתי נפרד מהתהליך והימנעות מתבניות ורכיבים שאי אפשר לבדוק אותם (כי אחרי זה כבר נכתוב לזה mock או קודם נבדוק שזה עובד) הם המפתח לפיתוח מוצרים שמחזיקים מעמד לאורך זמן.

ToCode
1 420
קוד אידמפוטנטי רדיטור אקראי שואל - אני מנסה להשתמש בריאקט כדי לאמת כתובת אימייל. גולש נכנס לכתובת שכוללת קוד אימות בתור Query Parameter, ואז קומפוננטת ריאקט מושכת את הפרמטר ופונה לשרת כדי לדווח על כניסה. כל זה קורה ב useEffect של הקומפוננטה ולכן נקרא פעמיים במצב פיתוח. מה עושים? אם נשים בצד את האתגר הריאקטי, מבחינת מערכת הפיתרון הכי קל כבר כתוב בשאלה והוא דווקא מחוץ לסקופ של ריאקט - אולי אפשר להפוך את ה API לאידמפוטונטי. קוד אידמפוטנטי זה קוד שאפשר להריץ אותו כמה פעמים בלי לשבור שום דבר, והמוסכמה באינטרנט היא שכך יתנהגו בקשות HTTP Get. במקרה של אימות כתובת מייל קל לדמיין שרת שבתגובה לבקשה לאמת כתובת אם הכתובת כבר מאומתת בבסיס הנתונים פשוט יחזיר HTTP 200. בנוסף בהרבה מצבים אפשר להוסיף מזהה למשאב וכך לקבל קוד אידמפוטנטי גם בפעולות "חד פעמיות", לדוגמה אם מישהו רוצה להוסיף קופון לעגלת קניות, אפשר לבקש שישלח גם את קוד הקופון וגם מזהה של עגלת הקניות, וכך אין בעיה של שליחה מרובה. לא תמיד נוכל לארגן את קוד המערכת בצורה אידמפוטנטית, אבל כשאפשר זה שווה את המאמץ.

ToCode
1 420
פיתרון פרויקט אוילר שאלה 12 בסקאלה פרויקט אוילר מציע אוסף אינסופי של תרגילים קטנים ואפשר להיעזר בהם כדי ללמוד שפות תכנות חדשות. מאחר ואני לומד סקאלה חשבתי לנסות לפתור איתה את בעיה 12, כדי ללמוד איך להשתמש ברשימות עצלות. התרגיל ניקח את סידרת הסכומים החלקיים של המספרים הטבעיים כלומר כל איבר הוא סכום כל המספרים הטבעיים עד אליו:
1, 3, 6, 10, 15, 21, 28
מצאו את המספר הראשון בסידרה זו שמתחלק ב 500 מספרים או יותר. פיתרון בסקאלה הדבר הראשון שרציתי לעשות כדי לגשת לזה בסקאלה היה לכתוב פונקציה שמחזירה כמה מחלקים יש למספר מסוים. הפיתרון הנאיבי נראה כך:
def divisorsCount(n: Int): Int =
  (1 to sqrt(n).toInt)
    .filter(n % _ == 0)
    .flatMap(i => List(i, n / i))
    .toSet[Int]
    .size
אחרי שזה מוכן אפשר להשתמש בו כדי לפתור את התרגיל:
def euler12(): Int =
  LazyList
    .from(0)
    .scanLeft(0)(_ + _)
    .dropWhile(divisorsCount(_) < 500)
    .head
מה למדתי על סקאלה השימוש ב LazyList היה מאוד נוח והזכיר את ה Stream של אליקסיר, ואפילו שם הפונקציה scan היה זהה. אני מתחיל גם להתרגל לשימוש בקו תחתי כדי להגדיר פונקציות אנונימיות, למרות שחייב להודות שפונקציית הסכום עדיין מבלבלת בעיניי (הקו התחתי מופיע שם פעמיים וכל פעם מייצג את הארגומנט הבא שעובר). הייתי גם שמח למצוא דרך לוותר על הקו התחתי בשורה:
.dropWhile(divisorsCount(_) < 500)
כי זה ברור שאני עובד על הפרמטר מהפקודה הקודמת. סך הכל הפיתרון בסקאלה היה מאוד אינטואיטיבי, אבל אולי זאת פשוט שאלה שקל לפתור אותה בגישה פונקציונאלית.

ToCode
1 420
זה הממשק, טמבל באחת השאלות הראשונות בפרויקט אוילר עלינו למצוא את המספר הפלינדרומי הגדול ביותר שהוא מכפלה של שני מספרים תלת ספרתיים. פיתרון שאני רואה הרבה מתלמידים שרק מתחילים לכתוב פייתון יהיה משהו כזה:
max_found = 0
for i in range(100, 1_000):
    for j in range(100, 1_000):
        product = i * j
        if str(product) == str(product)[::-1] and product > max_found:
            max_found = product

print(max_found)
אבל למרות שהקוד פשוט ועובד, אם נחזור אליו בעוד כמה שבועות עלול לקחת לנו זמן להבין מה בדיוק קורה בו. הסיבה לבעיית הקריאות היא שיש בקוד מספר מנגנונים המשולבים אחד בתוך השני: 1. איתור כל המספרים שהם מכפלה של שני מספרים תלת ספרתיים. 2. איתור כל המספרים מתוכם שהם פלינדרומים. 3. חישוב המספר המקסימלי. הדברים משולבים יחד כך שלדוגמה חישוב המספר המקסימלי דורש קוד גם לפני הלולאה וגם בתוך הלולאה הפנימית. אי אפשר להפריד כל מנגנון ואי אפשר להרכיב ולפרק אותם. ארגון מחדש של הקוד בחשיבה על המנגנונים והממשק ביניהם נראה כך:
import itertools

three_digit_numbers = range(10, 1_000)
pairs = itertools.product(three_digit_numbers, repeat=2)
products = (i * j for (i, j) in pairs)
palindroms = (p for p in products if str(p) == str(p)[::-1])
print(max(palindroms))
הפעם לכל שורה יש תפקיד והקשר בין תפקיד כל שורה למשימה הגדולה ברור גם מהקוד וגם משמות המשתנים. בניית קוד כמו לגו, כמו בלוקים שאפשר לחבר ולנתק, היא המפתח לקוד קריא שיוכל לשרוד לאורך זמן.

ToCode
1 420
איך למנוע באגים (שאלה של גישה) דרך אחת לייצר פחות באגים היא לבנות מנגנונים נוגדי באגים - לדוגמה בדיקות אוטומטיות, שימוש ב Strong Types, שילוב בודקי תוכנה בתהליך הפיתוח ותוספת הכשרות לצוות. דרך אחרת היא לזהות ולהעניש אנשים שמייצרים באגים. ו"עונש" כאן יכול להיות Shaming פומבי, אבל גם יכול להיות לאלץ אותם לעבוד שעות נוספות כדי לתקן את הבאגים (מה שבטעות נקרא Code Ownership). הבעיה שמה שגורם לאנשים לתמוך בדרך מסוימת לא מבוסס על מדד אוביקטיבי. מי שחושבת שהיא "טובה מדי בשביל להגדיר טיפוסים" או "כותבת בלי באגים" לא תשתכנע מאיזה סיפור על חברה שהצליחה להוריד את כמות הבאגים בעזרת מעבר ל TypeScript, כי היא בטוחה שהבעיה היא באנשים ועדיף היה לגייס מתכנתים "טובים יותר". וגם להיפך, מי שבטוחה שתרבות עבודה ומנגנונים הם הדרך לכתוב קוד טוב יותר לא תשתכנע מאיזה סיפור על חברה שהצליחה לכתוב קוד יותר טוב כשהפסיקו לכתוב בדיקות, כי היא תסביר לעצמה שאולי לאנשים שעובדים שם זה התאים אבל אצלה בצוות זה לא יעבוד. ואם אי אפשר לשכנע נשאר לנו רק לבחור. להבין איזה דרך מתאימה יותר עבורי, איך אני רוצה לעבוד, ולחפש פרויקט שזו תרבות העבודה בו. "תרבות העבודה כאן לא מתאימה לי" זו אחת הסיבות המוצדקות לחפש עבודה חדשה.

ToCode
1 420
5 טיפים למבחני בית טובים יותר מבחני בית הם רע הכרחי בעולם שלנו. כן יש חלופות אבל גם הן לא תמיד אפשריות או טובות - לדוגמה שאלות תכנות על הלוח בזמן הראיון יכולות להלחיץ, ולא תמיד למועמד או למועמדת יש קוד ציבורי שיכולים לשתף. הבעיה עם מבחני בית היא שמועמדים לא יודעים מה אתם רוצים לראות, ויכול להיות שהם יכתבו קוד שנראה לכם "נוראי" אפילו שהם לגמרי מסוגלים לכתוב קוד "מושלם". מאחר והמטרה שלנו בגיוס היא לזהות מועמדים טובים, הנה כמה טיפים שיוכלו לעזור למועמדים שלכם ולכם לתקשר טוב יותר. פיצ'ר עדיף על פרויקט מלא זה שאתם נותנים למועמד שבוע לסיים מבחן בית לא אומר שיש לו שבוע לשבת על הקוד שלכם. יותר מזה, ברוב המוחלט של התפקידים אתם רוצים אנשים שיודעים להשתלב בפרויקט קיים, להוסיף אליו קוד בלי לשבור אותו ולהתאים את עצמם למנטליות של הפרויקט. אל תשלחו אותם לכתוב דברים שממילא הם לא יכתבו בעבודה אצלכם. הכינו מראש פרויקט עם רשימת פיצ'רים מעניינים וכל פעם שצריכים לתת למישהו מבחן בית תנו לו לממש את אחד הפיצ'רים מהרשימה. סטארטר עדיף על להתחיל מאפס ואם כבר מדברים על הפרויקט שהכנתם שימו לב לבנות אותו בהתאמה לקוד שהייתם רוצים לקבל חזרה. חשוב לכם מבנה קבצים ותיקיות מסוים? השתמשו במבנה זה בפרויקט. חשוב לכם שהקוד יכלול בדיקות? כתבו בדיקות לחלקים המוכנים בפרויקט. חשוב לכם שמועמד ישתמש ב TypeScript עם כללי בדיקה מסוימים (למשל בלי any)? שימו מראש את הקובץ tsconfig.json שלכם בפרויקט. סטארטר טוב מכיל בתוכו את התבניות שמועמד יכול לקחת מהן השראה כדי לבנות את הפיצ'ר הבא. מועמדים טובים יתאימו את הקוד שלהם למבנה של הפרויקט, וכך כולם מרוויחים. כמה שיותר קונטקסט יותר טוב הפרויקט צריך להציג רשימה של קטגוריות, ואתם יודעים שלא יהיו לעולם יותר מ-5 קטגוריות? ספרו את זה למועמד. או, משתמשים יכולים ליצור קטגוריות בלי הגבלה וצפויות מאות אלפי קטגוריות? גם זה חשוב לדעת. מה גודל המידע שאמור לעבור ברשת? מה צפויה להיות מהירות האינטרנט אצל המשתמשים שלכם? מי יוצר את התוכן וכמה תוכן יהיה? האם יש דרישות מסוימות שכדאי להיערך אליהן? ואיזה שינויים ממש לא הגיוני שיגיעו אי פעם? ככל שתספרו יותר על המערכת כך אוכל להתאים את הקוד לצרכים שלכם. בסוף יש לנו פה צורך לכתוב קוד מדויק בזמן קצר, והמטרה של שני הצדדים היא למקד את המאמצים במקומות הנכונים. התשתית עלינו עוד דבר שאנשים מסתבכים איתו בפרויקטים הוא ה Deployment, אז בואו נוריד גם את זה מהשולחן. שימו את הפרויקט בגיטהאב, הגדירו Actions שיעלו כל PR לשרת חדש ותנו למועמדים שלכם לשלוח PR ולראות את העבודה שלהם לייב ברשת עם בסיס נתונים אמיתי שהכנתם מראש. גם את כל קבצי העיצוב או כל דבר אחר שצריכים כדי להשלים את המשימה עדיף לחלק מראש. נסו את זה בבית והכי חשוב נסו לפתור את מבחן הבית בעצמכם לפני שאתם נותנים למועמדים להתמודד איתו. תראו שזה אפשרי, תראו כמה זמן זה לוקח, תראו לאיזה רמת פיתרון אתם מצליחים להגיע ועל איזה דברים טפשיים נתקעתם ששווה להכין אליהם מראש את המועמדים. המטרה שלנו במבחני בית היא לזהות מועמדים מתאימים. ככל שנלך יותר לקראתם יש יותר סיכוי לראות ולזהות את אותם מועמדים שמתאימים לנו.

ToCode
1 420
היום למדתי: שלוש נקודות ברובי אופרטור שלוש נקודות ברובי קיים מסתבר כבר די הרבה זמן (מגירסה 2.7), אבל איכשהו עבר לי מתחת לרדאר. תפקידו להעביר את כל הפרמטרים שפונקציה מקבלת לפונקציה אחרת, כלומר לגרום לקוד כזה לעבוד:
def bar(x, y, z, **extra)
  puts "x = #{x}, y = #{y}, z = #{z}, #{extra}"
end

def foo(...)
  bar(...)
end

foo(10, 20, 30, hello: "world")
האופרטור מחליף תבנית ישנה יותר וקצת יותר מסורבלת שגם קיימת בפייתון:
def bar(x, y, z, **extra)
  puts "x = #{x}, y = #{y}, z = #{z}, #{extra}"
end

def foo(*args, **kwargs)
  bar(*args, **kwargs)
end

foo(10, 20, 30, hello: "world")
ודבר נוסף - בעבודה על פרויקט קיים, במיוחד כשלא משדרגים את השפה כשיוצאת גירסה חדשה, קל לפספס תחביר חדש ואפילו להעביר שנים בלי לשים לב אליו. זה לא קורה לי בשפות תכנות שאני מלמד כי שם הצרכים שונים. מאחר וגירסה חדשה של שפת תכנות יוצאת מקסימום פעם בשנה, שווה לעשות הרגל ולבדוק את רשימת החידושים בכל גירסה כשהיא יוצאת. גם אם נבחר לא להשתמש בכל טריק חדש שמתווסף, זה לא נעים להיות מופתעים באיחור של 4 שנים.