הבלוג של ינון פרק

טיפים קצרים וחדשות למתכנתים

שידרוגים ״לא כמו בספר״

11/07/2020

במדריך של ריאקט על המעבר מקלאסים לקומפוננטות מופיע המשפט הבא:

constructor: Function components don’t need a constructor. You can initialize the state in the useState call. If computing the initial state is expensive, you can pass a function to useState.

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

וזה מסתדר מעולה למי שעבד לפי הכללים ובאמת השתמש ב constructor רק בשביל לאתחל משתני State. אגב בדף התיעוד על Class Components מופיע המשפט הבא (בכתיב מודגש) רק בשביל לוודא שאנחנו מיושרים על הכלל:

If you don’t initialize state and you don’t bind methods, you don’t need to implement a constructor for your React component.

עד לפה תיאוריה :)

בחיים האמיתיים לא כל המשתנים נשמרים כמשתני State ומאותחלים בבנאי מכל מיני סיבות. הנה דוגמא קצרה שראיתי השבוע מתוך ספריית azure-devops-ui:

import * as React from "react";
import { Dropdown } from "azure-devops-ui/Dropdown";
import { Observer } from "azure-devops-ui/Observer";
import { DropdownMultiSelection } from "azure-devops-ui/Utilities/DropdownSelection";
import { dropdownItems } from "./Data";

export default class DropdownMultiSelectExample extends React.Component {

    private selection = new DropdownMultiSelection();

    public render() {
        return (
            <div style={{ margin: "8px" }}>
                <Observer selection={this.selection}>
                    {() => {
                        return (
                            <Dropdown
                                ariaLabel="Multiselect"
                                actions={[
                                    {
                                        className: "bolt-dropdown-action-right-button",
                                        disabled: this.selection.selectedCount === 0,
                                        iconProps: { iconName: "Clear" },
                                        text: "Clear",
                                        onClick: () => {
                                            this.selection.clear();
                                        }
                                    }
                                ]}
                                className="example-dropdown"
                                items={dropdownItems}
                                selection={this.selection}
                                placeholder="Select an Option"
                                showFilterBox={true}
                            />
                        );
                    }}
                </Observer>
            </div>
        );
    }
}

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

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

בקיצור לטיפ היומי - כשאנחנו כותבים קוד לפי הכללים אנחנו דואגים לעתיד: אנחנו בונים לעצמנו מסלול שידרוג קל יותר ליום בו התחביר ישתנה ונרצה להתקדם. וכן אני יודע שלא תמיד קל לכתוב לפי הכללים, במיוחד כשאתם רק מתחילים לעבוד עם טכנולוגיה ולא יודעים בעל פה את כל התיעוד. לפחות בריאקט אני יכול לעזור. עוד שבוע וקצת אני מתחיל עבודת מנטורינג עם קבוצה קטנה של מתכנתים שרוצים ללמוד לכתוב ריאקט מסודר ולפי הכללים. בקבוצה אני קורא קוד אמיתי שאתם כותבים כדי לזהות תבניות שלא מסתדרות עם שיטת החשיבה של ריאקט ועוזר לכם להיגמל מהן ולמצוא פיתרונות טובים יותר. אנחנו גם נכתוב קוד יחד ונתמודד עם בעיות מהעולם האמיתי כדי להתאמן על שיטת חשיבה ריאקטית. מתחילים ב 19/7 ויש כבר קבוצת סלאק פעילה למקדימים. פרטים ורישום בקישור https://www.tocode.co.il/bootcamps/react.

קורס אימייל חדש: שש תוכניות ללימוד פייתון

10/07/2020

הי חברים,

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

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

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

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

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

גם ידע הוא תשתית

09/07/2020

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

ארגונים טובים משקיעים ביצירת תשתיות דומות למתכנתים שלהם: תשתיות שמריצות אוטומטית את הבדיקות, שמאפשרות בצורה אוטומטית להעלות גירסא חדשה (או לעשות Rollback לגירסא אחורה), להוסיף עוד שרתים כשיש עומס.

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

מה שלפעמים קשה לראות זה את הקשר בין מיומנויות לתהליכי עבודה. אם אני יודע לעבוד טוב עם git - לא רק שאני אעשה פחות טעויות אלא שאני גם אעבוד איתו יותר. אני אשתמש ב rebase כשצריך כי אני לא פוחד מזה, אני ארגיש בנוח להפעיל reset או למחוק בראנצ'ים, וכך אני וכל הצוות נוכל לרוץ מהר יותר.

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

פחחח אני כותב את זה ביומיים (או: החלק הקשה במערכות תוכנה)

08/07/2020

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

אבל זה רחוק מלהיות מערכת דפי נחיתה ודיוורים כמו המערכות שיש היום בשוק: כל סידרת מסרים היא אוסף של קבצי Markdown שאני עורך באימקס, בשביל לראות סטטיסטיקות אני נכנס ל Database ומריץ ידנית שאילתות ואפילו לא התחלתי לדבר על ניהול משתמשים מסודר או תמיכה בעיצובים שונים לדפי הנחיתה.

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

החיים בפרודקשן

07/07/2020

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

קחו את קוד ריילס הבא לדוגמא:

add_column :bundles_users, :joining_date, :date

execute <<-SQL
    UPDATE bundles_users SET joining_date = created_at
    WHERE joining_date is NULL
SQL

change_column :bundles_users, :joining_date, :date, null: false, default: -> { 'CURRENT_DATE' }

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

  1. קודם כל מוסיפים עמודה לטבלא (הטבלא נקראת bundles_users, לעמודה החדשה קוראים joining_date והיא מסוג תאריך).

  2. אחרי זה מעתיקים את כל הערכים מעמודת created_at לעמודה החדשה שיצרנו

  3. ובסוף מוסיפים NOT NULL Constraint על העמודה החדשה כדי ששורות חדשות לא ייכנסו עם ערך NULL.

יכולים לראות איפה זה נשבר?

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

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

הטעות הכי גדולה של מתכנתים שרוצים להשתפר

06/07/2020

מה הופך אותך למתכנת או מתכנתת טובים יותר?

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

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

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

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

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

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

(נ.ב. מסלולי הבוטקמפ בריאקט ובפייתון מתקרבים. אם אתם כבר יודעים את התיאוריה ורוצים להתאמן על ליישם ולפתור בעיות Hands On בטכנולוגיות אלה זה המקום בשבילכם).

קירות

05/07/2020

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

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

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

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

בואו נתרגם משפטים עם Python ו Google Translate

04/07/2020

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

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

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

from googletrans import Translator

translator = Translator()
texts = ['אני אוהב שוקולד', 'ועוגות גבינה', 'וארטיק וסוכריות', 'ותות גינה']

translations = translator.translate(texts)
for item in translations:
  print(item.text)

אפשר למצוא את התוכנית ולשחק איתה בשידור חי ברפליט שבקישור https://repl.it/@ynonp/python2#main.py.

ובשביל להריץ אותה אצלכם על המכונה תצטרכו להתקין גם את החבילה googletrans עם הפקודה:

python -m pip install --user googletrans

הרצה של התוכנית תדפיס לנו על המסך את התרגום הלא מדויק הבא:

I love chocolate
And cheesecakes
And vinegar and candies
And garden strawberries

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

המשך קריאה

היום למדתי: אפשר לשרשר השוואות ב Python

02/07/2020

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

>>> 2 == 2 == 2

והוא ענה לי True.

אז הלכתי לכתוב לו שיר אהבה קצר מרוב אושר, ופייתון אפילו חייך אליי בחזרה:

x = 30
if 20 < x < 50:
    print("I \U00002764 Python")