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

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

על ההבדל בין -c ו -s ב su ו runuser

26/04/2021

הפקודות su ו runuser נועדו כדי שנוכל להחליף משתמש או להריץ פקודות בתור משתמש אחר. ב su אנחנו משתמשים כדי לעבור ממשתמש רגיל למשתמש רגיל אחר, וב runuser נשתמש כדי לעבור ממנהל מערכת למשתמש רגיל. בשתי הפקודות האפשרויות -c ו -s משמשות לבחירת התוכנית שצריך להפעיל. בואו נראה את ההבדלים ביניהן.

המשך קריאה

איך לקרוא קובץ ב Bash בלי cat

25/04/2021

בקבוצה [https://t.me/bash_tips] בטלגרם פורסמו לפני כמה ימים מספר אתגרי bash באתר שנקרא cmdchallenge.com. מאחר ויש לי חולשה לאתגרים מסוג זה הלכתי להעיף מבט. התחושה שלי היתה שרוב האתגרים שם לא היו מאוד מעניינים או לא היו מנוסחים מספיק טוב, אבל היה טריק אחד שתפס את העין.

בתרחיש המדובר הגענו למערכת קבצים שנמחקו ממנה כל התוכניות והיה צריך באמצעות Bash Builtins בלבד להציג תוכן של קובץ. האינטואיציה הראשונה שלי היתה להשתמש בפקודת read בלולאה, כמו בשורה הבאה שמדפיסה את כל תוכן הקובץ /etc/shells:

while IFS= read -r; do echo "$REPLY"; done < /etc/shells

אבל מסתבר שיש טכניקה יותר פשוטה ואחרי חיפוש קצר ב man bash מצאתי את הפיסקה הבאה:

The command substitution $(cat file) can be replaced by the equivalent but faster $(< file).

מה שאומר שאפשר לקצר את השורה לגירסה הבאה:

echo "$(< /etc/shells)"

שווה לשים לב למרכאות סביב המשתנה (בשני המקרים). ברוב הקבצים לא תשימו לב להבדל, אבל אם בקובץ יהיו סימנים מיוחדים כמו *, [] או ? הגירסה בלי המרכאות תתיחס לסימן המיוחד בתור תבנית של שם קובץ ותחליף אותו ברשימת כל הקבצים המתאימים לתבנית.

תשתית לשינויים

24/04/2021

בכל פעם שתנסו לשלוח Pull Request לפרויקט קוד פתוח, ובהרבה חברות תוכנה בכל פעם שתסיימו עבודה על פיצ'ר, יהיה מי שיבוא עם בקשות לתיקונים:

"תוסיף בבקשה הערות"

"הבדיקה לא מספיק טובה"

"מה קורה במצב ש... ?"

"תמעך את הקומיטים בבקשה שיהיה רק קומיט אחד ב PR"

"תהפוך את הטאבים לרווחים"

"יש לנו API חדש שבדיוק מתאים למה שכתבת, עדיף שתעבור להשתמש בו"

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

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

תשתית של שינויים מורכבת מידע, מכלים ומעיצוב הקוד:

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

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

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

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

איך ולמה להקים Fanout Exchange ב RabbitMQ

23/04/2021

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

המשך קריאה

ואם היום לא בא לי

22/04/2021

אנחנו אוהבים לחשוב על מוטיבציה בתור משהו שלא תלוי בנו: יש דברים ש"בא לי" עליהם, ואחרים ש"לא בא לי לעשות":

בא לי לראות יוטיוב; לא בא לי לקרוא ספר.

בא לי לעשות ספורט; לא בא לי לאכול פיצה.

בא לי לבנות פיצ'ר חדש; לא בא לי לחקור זליגת זיכרון ישנה.

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

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

חוסך עבודה או חוסך הבנה

21/04/2021

זה לא אותו דבר ולשניהם יש מקום:

אני יודע מעט מאוד על איך מערכת הפעלה קוראת קובץ Executable, אבל עדיין מצליח לבנות בקלות קבצי הפעלה ותוכניות באמצעות שפות תכנות מדרגה גבוהה יותר. אני כותב קוד Java => הקומפיילר של Java הופך את הקוד ל Bytecode => המכונה הוירטואלית של Java מתרגמת בזמן אמת את הקוד לשפת מכונה => מערכת ההפעלה מבצעת את הפקודות בשפת המכונה. העבודה ב Java, או בכל שפת תכנות אחרת, חוסכת לי הבנה.

ולמרות שאני יודע די הרבה על Webpack ומבנה פרויקט React, אני עדיין אעדיף להתחיל פרויקט חדש עם create-react-app וכשיגיע הזמן להפעיל eject ולהתחיל לתפעל את העניינים בעצמי. החיסכון בעבודה בהתחלה מאפשר לי לקפוץ מהר יותר לכתיבת הקוד, שזה מה שרציתי לעשות מלכתחילה.

כן חשוב להיות מיושרים וברורים מה אנחנו מנסים לחסוך ולוודא שמשתמשים בכלי הנכון. ספריית next.js היא דרך מעולה לחסוך עבודה בהקמת תשתית ל Server Side Rendering, אבל אם אתם לא מבינים איך SSR עובד יהיה לכם מאוד קשה לפתור בעיות שבוודאות יצוצו. מצד שני להבין איך המעבד עובד לא יהפוך אתכם למתכנתי Clojure טובים יותר, כי שפה פונקציונאלית כמו Clojure מגיעה עם עולם תוכן ועולם מושגים שלה.

כשמסתכלים על ספריה חדשה שווה לשאול קודם כל: "מה הכלי הזה אמור לחסוך לי?" ו"האם זה החיסכון שחיפשתי?"

המקסימום האפשרי

20/04/2021

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

וכך בתור תלמידים למדנו שאם אפשר ללמוד 10 שעות ולקבל 100 אז אין טעם ללמוד 20 שעות (כי ממילא לא תקבל יותר מ 100).

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

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

  1. ככל שתלמדי יותר שפות תכנות, כך יהיה לך קל יותר ללמוד את השפה הבאה.

  2. ככל שתבני יותר משחקים, כך יהיה לך קל יותר לבנות את המשחק הבא.

  3. ככל שתעבירי יותר הרצאות כך תגיעי יותר מוכנה להרצאה הבאה.

לא בשביל הציון. לא בשביל המשכורת. לא בשביל הקידום. פשוט כי אפשר.

פירוק כפול ב JavaScript

19/04/2021

מתכנתי JavaScript רבים כבר יודעים לעבוד עם Destructuring כדי לשבור מערך למספר משתנים, לדוגמה הקוד הבא שומר ב x את הערך 10 וב y את הערך 20:

const [x, y] = [10, 20];

ב React אנחנו משתמשים במנגנון זה הרבה כשמפעילים את הפונקציה useState. הפונקציה מחזירה מערך ואנחנו רגילים לכתוב:

const [value, setValue] = useState("");

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

function Input(props) {
  const [value, setValue] = props.model;
  return (
    <input
      type="text"
      value={value}
      onChange={(e) => setValue(e.target.value)}
    />
  );
}

function App() {
    const model = useState("");
    const [value, setValue] = model;

    return (
        <div>
            <p>Hello {value}</p>
            <Input model={model} />
        </div>
    );
}

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

const model = [value, setValue] = useState("");

והתשובה מורכבת.

הקוד יעבוד (לפחות בחלק מסביבות ההרצה) אבל לא יעשה את מה שרציתם שהוא יעשה. בכתיב כזה המילה const משפיעה רק על המשתנה הראשון model, והמשתנים value ו setValue יהיו משתנים גלובאליים. לכן הקוד יעבוד בסביבות שמאפשרות הגדרת משתנים גלובאליים בלי var, const או let. בכל מקרה אנחנו יודעים שמשתנים גלובאליים ב JavaScript רק מביאים צרות ולכן גם אם הכתיב עובד לא מומלץ להשתמש בו.

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

export default function App() {
  const model = useState(""),
    [value, setValue] = model;

  return (
    <div className="App">
      <p>Hello {value}</p>
      <Input model={model} />
    </div>
  );
}

בגרות באנגלית: חלק שני

18/04/2021

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

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

אם לקחתם את הקוד אתמול ואולי ניסיתם להדפיס חלק מהמילים יכולתם לגלות שהמילים house ו houses נספרות כשתי מילים שונות, וכך גם go, goes ו going. בנוסף אולי שמתם לב ששמות כמו George, Bill ו Jane נספרו בתור מילים.

בואו נתקן את שתי הבעיות בעזרת ספריית nltk.

ספריית nltk או Natural Language Toolkit כוללת אינסוף פונקציות שעוזרות לנו לעבוד עם טקסטים בצורה נקיה ומאפשרת גישה לאינספור משאבים טקסטואלים שאפשר להתאמן עליהם כשכותבים תוכניות לניתוח שפה. אנחנו נשתמש בשתי יכולות של הספריה:

  1. היכולת לבצע Stemming למילה, כלומר לקחת את המילים house ו houses, להבין שזו אותה מילה ולהחזיר את הצורה המקורית של המילה - house.

  2. מאגר השמות הפרטיים שמגיע בתוך הספריה שיאפשר לנו לזהות האם מילה מסוימת היא שם פרטי.

את הספריה מתקינים עם:

pip install nltk

ובתוך התוכנית נשתמש בה עם ה import-ים הבאים:

from nltk.stem import PorterStemmer
from nltk.tokenize import word_tokenize
import nltk.corpus

נתחיל עם מאגר השמות. הקוד הבא שומר במשתנה all_names קבוצה של כל השמות שמופיעים במאגר של nltk:

names = nltk.corpus.names

all_names = set(names.words('male.txt') + names.words('female.txt'))

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

import nltk
nltk.download('names')

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

# import these modules
from nltk.stem import PorterStemmer
from nltk.tokenize import word_tokenize

ps = PorterStemmer()

# choose some words to be stemmed
words = ["program", "programs", "programer", "programing", "programers"]

for w in words:
    print(w, " : ", ps.stem(w))

התוצאה של כל ההדפסות היא המילה program.

התוכנית שלי אחרי עדכון נראית כך:

import requests, textract, re, os.path
from functools import reduce
from nltk.stem import PorterStemmer
from nltk.tokenize import word_tokenize
import nltk.corpus

names = nltk.corpus.names

all_names = set(names.words('male.txt') + names.words('female.txt'))

index_url = 'https://meyda.education.gov.il/bagmgr/Ajax.ashx?search=1&sheelon=&miktzoa=16&safa=1&pagesize=10&page=1'

r = requests.get(index_url)
urls = [q["question"] for q in r.json()]
total_words = {}
ps = PorterStemmer()

s = requests.Session()
for url in urls:
    m = re.search(r'([^/]+\.pdf)', url)
    if m is None: continue

    filename = m[0]
    if not os.path.isfile(filename):
        r = s.get(url)

        with open(filename, 'wb') as f:
            f.write(r.content)

    text = textract.process(filename).decode('utf8')
    words = [
            ps.stem(w.lower()) for w in re.findall(r'\b[a-zA-Z_]+\b', text)
            if w not in all_names
            ]
    print(f"Test {filename} has {len(words)} different words")
    total_words[filename] = set(words)

all_words = reduce(lambda acc, val: acc | val, total_words.values())
print(f"All tests had a total of {len(all_words)} different words")

אלף מילים

17/04/2021

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

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

תוצאות? מיד אחרי הסקריפט שמחשב את הנתונים...

המשך קריאה