מימוש שערים לוגיים ב Clojure
ים מסיקה פירסם לפני כמה ימים אוסף מדליק של חומרי לימוד ותרגולים ללימוד פייתון (להורדה מהקישור הזה). אחד התרגילים שאהבתי משם היה לבנות קוד שידמה מעגל חשמלי.
טיפים קצרים וחדשות למתכנתים
ים מסיקה פירסם לפני כמה ימים אוסף מדליק של חומרי לימוד ותרגולים ללימוד פייתון (להורדה מהקישור הזה). אחד התרגילים שאהבתי משם היה לבנות קוד שידמה מעגל חשמלי.
אחד ההבדלים שמתכנתים מאוד רגישים אליו בין שפות תכנות הוא היכולת לבצע בקלות פעולות מסוימות בשפה אחת, כאשר בשפה אחרת צריך לעבוד מאוד קשה בשביל לקבל את אותה התנהגות. כמה דוגמאות שקופצות לראש:
לכל פונקציה ב JavaScript יש מאפיין משם length שמחזיר כמה פרמטרים הפונקציה מצפה לקבל. ב Python קצת יותר קשה לגלות את זה אבל עדיין אפשרי עם חבילת inspect, ב Ruby יש לכל פונקציה מאפיין בשם arity שמחזיר את הערך וב Clojure אנחנו צריכים לקפוץ שמיניות באוויר בשביל למצוא אותו.
הפונקציה merge של Hash ממזגת בין שני מילונים ב Ruby ומאפשרת לנו בקלות להחליט מה לעשות עם ערכים מתנגשים. כך קוד רובי הבא יכול לשלב בקלות ערכים משני מילונים למילון שלישי:
a = { a: 10, c: 30 }
b = { a: 5, b: 20 }
res = a.merge(b) {|k, v1, v2| v1 + v2 }
# now res is: { a: 15, b: 20, c: 30 }
בפייתון קל מאוד לשלב שני מילונים שאין ביניהם ערכים מתנגשים עם כתיב שתי הכוכביות:
a = { 'a': 10, 'c': 30 }
b = { 'b': 20 }
res = dict(**a, **b)
# now res is: { 'a': 10, 'b': 20, 'c': 30 }
אבל זה לא מה שרצינו ובשביל לשלב את המילונים עם פונקציית חיבור שלנו נצטרך להתאמץ יותר ולכתוב לולאה מסודרת.
ויש עוד מאות כעסים קטנים כאלה בכל מעבר בין שפות, וזה בסדר. שווה לזכור שבכל מעבר כזה בין שפות מאוד קל למצוא חבילות שסוגרות את הפער. גם אם ל JavaScript אין את random.randint של פייתון, אנחנו עדיין יכולים לקבל פונקציונאליות זהה מ lodash; חבילת mergedict של פייתון מאפשרת לשלב בצורה אלגנטית בין מילונים ולקבוע מה לעשות עם ערכים מתנגשים בקלות ממש כמו ב Ruby.
ההבדלים האמיתיים בין שפות הם לא בפונקציה מסוימת שנמצאת או לא, אלא בגישה ובהשקפת עולם שונה: האם יש Type System? האם הוא מחייב? האם יש Class-ים? האם יש הגבלה על עומק הרקורסיה? איך בונים קוד מקבילי או מבוזר? האם זה מתקמפל? האם זה רץ על המכונה אליה אני מכוון?
(וכמובן חוץ מבחירת שפה ברוב הפרויקטים נצטרך לעשות בחירה הרבה יותר קשה ולבחור Framework. אבל זה כבר סיפור ליום אחר).
אחת הטכניקות הטפשיות (אך מפתות) של אבטחת מידע היא לבנות מנגנונים שיהיה קל מאוד לעקוף אותם ויעצרו רק את האנשים שאין להם כח להתאמץ יותר מדי. השבוע למדתי במקרה על דרך קלה לזהות גולשים שמשתמשים בסלניום כדי להפעיל בצורה אוטומטית אתרים: מסתבר שסלניום או יותר נכון ה chromedriver שהוא מפעיל מוסיף Cache לכל דף - אני לא לגמרי בטוח מה הוא שומר ב Cache הזה - אבל את ה Cache הוא שומר במפתח עם שם מוזר שמתחיל ב $cdc
. לסקרנים שביניכם הנה הקוד שיוצר את ה cache בכרומדרייבר:
function getPageCache(opt_doc, opt_w3c) {
var doc = opt_doc || document;
var w3c = opt_w3c || false;
// |key| is a long random string, unlikely to conflict with anything else.
var key = '$cdc_asdjflasutopfhvcZLmcfl_';
if (w3c) {
if (!(key in doc))
doc[key] = new CacheWithUUID();
return doc[key];
} else {
if (!(key in doc))
doc[key] = new Cache();
return doc[key];
}
}
ומה שמעניין הוא שאנשים משתמשים במפתח הזה כדי לזהות האם הגעתם דרך סלניום והאם אתם מנסים להריץ דפדפן בצורה אוטומטית על האתר שלהם. זה לקח עוד שלוש דקות אחרי זה כדי למצוא את הפוסט מסטאק אוברפלו שמסביר איך לערוך את הקובץ הבינארי של chromedriver כדי לגרום לו להפסיק לשלוח את המשתנה ולעקוף את החסימה.
מנגנוני הגנה מסוג זה נקראים הרבה פעמים Security By Obscurity והרעיון שלהם שהם מצליחים לבלבל אותנו כדי שהבוס יחשוב שהמערכת מאובטחת, אבל לא מצליחים לעצור אף תוקף אמיתי. מנגנון אמיתי לזיהוי רובוטים יצטרך להיות הרבה יותר יצירתי מחסימה של תוכנות לפי Fingerprints כי כל מי שמספיק חשוב לו לקבל את המידע ימצא את הדרך לבטל את ה fingerprints בתוכנה שלו. זיהוי רובוטים אמיתי יחייב אותנו לזהות התנהגות של רובוטים וזה כבר הרבה יותר קשה.
יום אחד נצטרך להבין איך הקורונה דחפה אותנו להחליף שיטת לימוד לא מאוד יעילה בשיטה אחרת הרבה פחות יעילה. עד שזה יקרה ולכבוד הסגר השני בואו ניקח רגע להבין מה אנחנו מרוויחים ובעיקר מפסידים מכל הזומים האלה.
לפני כמה ימים במסגרת כתיבת פרק פנדס חדש לקורס פייתון שבאתר (יעלה עוד כמה ימים אל דאגה, עכשיו בעריכות), רציתי לצייר גרף שמתאר כמה שילמו כל נוסעי הטיטאניק על הכרטיסים שלהם. כן, מסתבר שגם את פרטי נוסעי הטיטאניק אפשר למצוא היום בקלות ברשת, אבל זה כבר נושא לסיפור אחר.
בגלל שכל אחד שילם מחיר קצת שונה היה נוח לחלק את המחירים לקבוצות עם pd.cut וכך הגעתי לקוד הבא:
import pandas as pd
url = 'https://raw.githubusercontent.com/guipsamora/pandas_exercises/master/07_Visualization/Titanic_Desaster/train.csv'
titanic = pd.read_csv(url)
s=pd.cut(titanic['Fare'], bins=[0, 10, 20, 50, 100, 1000], right=True)
data = s.value_counts()
print(data)
אבל להפתעתי התוצאה לא כללה את כל המחירים. הנה מה שקיבלתי מההדפסה:
(0, 10] 321
(20, 50] 216
(10, 20] 179
(50, 100] 107
(100, 1000] 53
Name: Fare, dtype: int64
והנה מאפייני הטיטאניק:
In: titanic['Fare'].describe()
Out:
count 891.000000
mean 32.204208
std 49.693429
min 0.000000
25% 7.910400
50% 14.454200
75% 31.000000
max 512.329200
Name: Fare, dtype: float64
קל לראות שבחלוקה לסלים בשביל לצייר את הגרף איבדנו 15 נתוני כרטיסים.
והשאלות: לאן נעלמו 15 נתוני כרטיסים? באיזו שורה הבעיה? ומה השינוי הקטן שאפשר לבצע כדי לתקן אותה?
לפעמים דווקא תרגילים פשוטים עוזרים לנו להתמקד ולקבל רעיונות לשיפור, שאחרי זה נוכל ליישם אותם גם במקרים יותר מורכבים. כך קרה לי עם דוגמת הריפקטורינג הבאה שמתחילה פשוט אבל מהר מאוד מסתבכת.
בתחומים רבים ובמיוחד אצלנו בהייטק, בסיס תיאורטי חזק הוא תנאי הכרחי להתקדמות. אם אתה לא יודע מה זה סיבוכיות זמן ריצה יהיה לך קשה מאוד לראות את ההבדל בין אלגוריתמים שונים בהיבט הזה. וגם מצד שני - אם את מבינה טוב את התיאוריה של תכנות מונחה עצמים ו Design Patterns יהיה לך קל מאוד להיכנס לשפת תכנות חדשה שעובדת בפרדיגמה זו.
מה שאנשים לא תמיד מספרים זה שהם עבדו מאוד קשה בשביל לקבל את הבסיס התיאורטי החזק שלהם, וכן חלק גדול מהזמן זה היה משעמם. הרבה יותר כיף לרוץ לפתור בעיות בתכנות או לכתוב איזה בוט חמוד לטלגרם מאשר ללמוד קורס באלגברה לינארית או הסתברות.
בקישור הזה: https://github.com/ossu/computer-science
יש רשימה של קורסים חינמיים לגמרי שילמדו אתכם את כל התיאוריה המשעממת של מדעי המחשב. זה ייקח שנתיים וממה שהצלחתי להתרשם לא ילמד אתכם לכתוב בוט לטלגרם. ובכל זאת זה מסלול הרבה יותר חכם מכניסה לבוטקמפ שילמד אתכם תוך שלושה חודשים את כל הטכנולוגיות שאתם צריכים (מאפס לעבודה או משהו כזה).
לפני הטכנולוגיות המדליקות; לפני מיומנויות למידה; לפני עבודת צוות; לפני גיט וריאקט ופייתון ו Node ו Full Stack ו Machine Learning יש בסיס תיאורטי חזק שאתם צריכים לקבל כדי שתוכלו להסתדר בעולם הזה ולתקשר בצורה מקצועית עם האנשים שסביבכם. המחשבה שמספיק פרויקט אחד טוב כדי למצוא עבודה ולהסתדר היא נאיבית. גם אם לפעמים זה עובד, בטווח הרחוק כשהטכנולוגיה משתנה זה לא מספיק להיות מסוגל "ללמוד לבד". צריך גם בסיס חזק שאפשר ללמוד ממנו.
אחד היתרונות בעבודה עם שפה דינמית הוא שמאוד קל לטעון קבצים שאולי לא ידעתם על קיומם בעת כתיבת הקוד וכך לקבל מערכת יותר גמישה - מערכת שבשביל להרחיב אותה כל מה שצריך זה לשים עוד קובץ בתיקיה מסוימת ובאופן אוטומטי המערכת מקבלת יכולות חדשות.
בשביל לבנות מערכת מבוססת פלאגינים כל מה שאנחנו צריכים זה להחליט (עם עצמנו) על דרך בה המערכת הולכת לתקשר עם הפלאגינים, להחליט על מבנה עבור הפלאגינים ועל תיקיה עבורם ולצאת לדרך.
בפוסט זה אראה דוגמה פשוטה לכתיבת מערכת מבוססת פלאגינים שטוענת את כל התוספים מתיקיה בתוך תיקיית הפרויקט בזמן העליה ומפעילה את הקוד מהתוספים לפי ההגדרות של כל תוסף.
החל מ 1.10 גיטהאב משנים את השם של ענף ברירת המחדל מ master ל main כדי להתאים לרוח התקופה. זה הולך לשנות הרבה Tutorials ברשת ואולי אחרי שהשינוי ישקע אני אוכל לנצל את ההזדמנות להקליט גירסה חדשה של קורס גיט כאן באתר.
בינתיים בכל מקרה וכהכנה לאירוע שני טיפים קשורים-
הראשון הוא שאתם יכולים (ותמיד יכולתם) לבחור מה יהיה שם הענף הראשון במקום master, פשוט באמצעות יצירת ענף ראשון חדש לפני הקומיט הראשון:
$ git init
$ git checkout -b main
והשני הוא שאתם יכולים (מיולי האחרון) לבחור מה יהיה שם ענף ברירת המחדל במאגרים מקומיים חדשים שאתם יוצרים באמצעות שינוי קונפיגורציה פשוט. הרצת הפקודה הבאה מ cmd (כרגיל בלי הדולר שבהתחלה) תשנה את שם ענף ברירת המחדל ל main בכל מאגר מקומי חדש שלכם:
$ git config --global init.defaultBranch main
בהנחה שיש לכם גיט 2.28 או עדכני יותר מותקן על המכונה.
לפני כמה ימים חשבתי לשנות את תמונת הרקע בלינוקס. עכשיו אני ב i3 אז קפצתי ל arch wiki כדי למצוא איך משנים ב i3 תמונת רקע ולמדתי שם על תוכנה בשם feh שמגדירה wallpaper. ההוראות עבדו והצלחתי ליהנות מתמונת הרקע החדשה ... לשתי דקות בערך.
כי כשהמחשב חזר ממצב שינה תמונת הרקע נעלמה. וכאן התחיל המסע כדי למצוא למה היא נעלמת ואולי יש תוכנות אחרות איתן אפשר לצייר רקע (יש והרבה). וככל שהמסלול הזה נמשך מצאתי את עצמי מוצא רעיונות יותר ויותר הזויים בגוגל: לא בגלל שהם היו גרועים, אלא פשוט כי הם לא נכתבו עבור הבעיה שלי.
הפיתרון בסוף? כמו שאולי ניחשתם היתה קונפיגורציה אצלי על המכונה שאיפסה את תמונת הרקע בכל מיני מצבים בגלל תוכנה אחרת שהיתה מותקנת. ברגע שמצאתי את הקונפליקט הבנתי גם איך לסדר את הכל, ומשם גם הצלחתי לחפש את התשובות הנכונות בגוגל בקלות.
כי אחת הבעיות בריצה בתוך מחילת הארנב היא שככל שאנחנו יורדים יותר עמוק ככה קשה יותר להסתכל לצדדים ולבחון את הסיבות האמיתיות לבעיה. והאמת שהרבה פעמים בתכנות כשמשהו מתחיל להסתבך זה בגלל שאנחנו מנסים לעקוף מגבלה או מנגנון של תוכנה או ספריה אחרת. אם נצליח להבין מה המנגנון שפועל נגדנו יהיה לנו הרבה יותר קל להשתמש בו לטובתנו.
וכן CSS - אני מסתכל עליך...