סיכום אוגוסט פנגווין 2015

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

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

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

הרצאה על systemd

הרצאה על systemd

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

ואז התפזרנו לצילום קבוצתי (שכמו כמעט בכל כנס – לא השתתפתי בו) ומסלולים שונים.

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

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

לאחר מכן, הלכתי לשמוע על מערכות הפעלה, והמרצה ניסה לסמן מטרה גדולה מידי, ופספס אותה לגמרי תוך כדי הציור שלה.
הוא לקח את לינוקס והגזים עם המון דברים, כמו למשל הרעיון שיש לך הרבה tty פתוחים גם בשרת ווירטואלי. אבל אפשר לכבות את זה. במידה ואתה עם מערכת init של sysv יש לך את הקובץ Inittab ואם אתה משתמש ב systemd אז אפשר גם שם לסגור דברים.
העניין הוא, שהוא פספס לגמרי את השימוש ב tty ומה הם אומרים – שזו תקשורת סיריאלית אשר מסוגלת לעשות המון דברים, בהתאם לסוג המסוים, כמו למשל text terminal, או teleprinter וכיוב'… כן זה עולם ישן, אבל הפשטות שלו גורמת לו להיות מאוד יציב ואיכותי יחסית, שניתן לזרום איתו להרבה כיוונים שונים.

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

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

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

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

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

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

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

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

אנדרואיד, mms ובעיית אבטחה עם פתרון ישים

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

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

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

בעולם הסלולרי, יש לנו יכולת לשלוח הודעות קצרות (אם כי לאחרונה זה הפך להיות יותר כמו מגילה מאשר הודעה קצרה) בשם SMS. הפירוש של SMS הוא Short Message Service.
הוא נשלח באמצעות אותות בשם ss7 ממכשיר לאנטנה, ומאנטנה לספק טלפון כלשהו. עכשיו הספק מעביר את זה הלאה לספק אחר שהוא שולח את ההודעה למכשיר אחר.

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

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

כיצד עובד ה MMS? אני שולח הודעת SMS במבנה מסוים שאומר כי יש לי משהו כדוגמת תמונה בשרת שניתן להוריד באמצעות WAP.

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

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

פיתון מול רובי, לא מה שחשבתם

הקדמה

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

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

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

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

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

שאלה ראשונה

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

a = 10.times.select{ |x| x % 2 == 0 }
a
=> [0, 2, 4, 6, 8]

זהו, זה כל מה שצריך, שורה אחת 🙂
אסביר אותה בקצרה. ברובי כל דבר הוא אובייקט, אין כזה דבר משהו שהוא "פרימיטיבי" (בהשוואה לג'אווה למשל).
מספר שלם "רגיל", הוא אובייקט מסוג Fixnum. יש לו מתודה אשר מקבלת ירושה ממחלקת האב – Integer בשם times, אשר מבצעת כמות הפעמים של המספר המבוקש איטרציה.
במידה ולא יוצרים block או proc בשביל לרוץ כמניית האיטרציה, חוזרת לנו מחלקה מסוג Enumerator אשר היא מחלקת בסיס לדברים בעלי יכולת מנייה (כדוגמת מערכים). במחלקת ה Enumerator ישנה מתודה בשם select, המאפשרת להגדיר אילו ערכים באיטרציה כלשהי יחזרו אלי כמערך, כאשר אני יצרתי כאן למעשה proc עם הוראות.
היות וברובי השורה האחרונה בהכרח תמיד חוזרת (אם אין explicit return), אז הוא יודע שכאשר יש מספר זוגי, אז אני רוצה שזה הערך אשר יחזור אלי.
עכשיו הנה משהו מעניין על רובי תוך כדי ההסבר – אין ברובי אופרטורים. כל מה שנראה כאופרטור (כדוגמת חילוק השארית ופעולת השוויון), הם למעשה מתודות, ולכן מתודה כדוגמת even?‎ זהה למה שהייתי צריך, ויתר מזה, אין צורך בסוגריים, ולכן זה יכול גם להראות כך:

a = 10.times.select{ |x| x.even? }
a
=> [0, 2, 4, 6, 8]

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

שאלה ראשונה – תת שאלה

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

a = []
10.times do |i|
  a.push(i) if i.even?
  puts a.inspect
end

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

ובנוסף, לרובי גם יש תמיכה בשני תחבירים של משפט טרינארי אשר שם נפל השואל:

i = 1
a = if i.even? then 't' else 'f' end
b = i.even? ? 't' : 'f'

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

c = unless i.even? then 'f' else 't' end

שאלה שניה

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

a = [1, 2, ['a', 'b', [0xa, 0xb] ]]
=> [1, 2, ["a", "b", [10, 11]]]
a.flatten
=> [1, 2, "a", "b", 10, 11]

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

כפי שכתבתי בתשובה לשאלה הראשונה, מערך ברובי, יורש מ Enumerable, אבל יש לו גם הרבה מתודות משל עצמו.
מתודה אחת כזו היא flatten, אשר עושה בדיוק את מה שאותו בחור ביקש.
המתודה יכולה להגיע גם בעוד צורה בשם flatten!‎ אשר התפקיד שלה הוא זהה, עם שינוי קטן אחד – היא לא מחזירה מערך חדש בלי לגעת בקיים (כפי ש flatten עושה), אלא היא משנה את המערך הקיים וחוזרת עם אובייקט המערך עצמו.

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

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

שאלה שלישית

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

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

str1 = 'yoyo'
print 'sdfsdfsfsdfsfsdf' if str1.eql?('aaaaa') || str1 == 'yopo' || str1 === 'yoyo'

ישנם כאמור עוד דרכים לביצוע השוואת מחרוזות, אבל אלו מספיקות, לא?
על רגל אחת (בלי באמת למצות את ההסבר עד הסוף שלדעתי דורש פוסט שלם רק על זה):
המתודה (בדיקה) הראשונה של eql?‎ בודקת האם האורך והתוכן זהים.
המתודה (הבדיקה) השנייה של ==, בודקת האם זה תוכן זה הוא מסוג מחרוזת, ובמידה וכן, בודקת אורך ורק אז את התוכן.
המתודה (הבדיקה) השלישית של ===, בודקת גם היא את סוג המחלקה, ובמידה ושניהם מחרוזות אז מבצעים פעולה הזהה ל==, במידה ולא, תהה בדיקה האם יש מכנה משוטף בניהם הניתן להשוואה באמצעות פעולת case.

שאלה רביעית

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

require 'open-uri'

image = open('https://www.google.com/images/srpr/logo11w.png')
open('/tmp/image.png', 'wb+') { |a| a.write(image.read) }
image.close

קצת פירקתי את הדברים לקריאות.
אני טוען את הספרייה open-uri, אשר תפקידה הוא לדעת לפתוח קישורים של ftp, http ו https כאילו היו file descriptor של רובי.

אני במקרה הזה ניגש לקובץ תמונה של גוגל, ושומר אותו כקובץ בינארי בספריית /tmp/ .
שימו לב כי אינני סוגר את הקובץ תמונה שאני שומר בדיסק, והוא נסגר לבד, בזכות פעולת ה proc, אשר בעצם מתבצעת "מאחורי הקלעים" באמצעות yield. וכאשר פקודה זו מסתיימת, הפונקציה של open סוגרת את עצמה לבד.

סיכום

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

ניסויים בתורי הודעות

יש מערכת שאחרי load test הבנתי כי אני חייב לבזר את המערכות שבה. אז התחלתי לבצע מחקר על סוגים שונים של message queue בשביל לבזר את המערכת. עשיתי ניסויים עם המון מערכות שונות, כולל התייעצות עם אנשים שממשים כבר מערכות המשתמשות בהם, והגעתי להבנה כי כנראה ש RabbitMQ מתאים לצרכים שלי.

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

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

למשל אני עשיתי 2 הגדרות בלבד לRabbit להתאים למכונת הפיתוח החלשה שלי, והגעתי ללמעלה מ7 מליון בקשות בשניה אחת, עד שרוחב הפס נחנק, אבל ה load היה על 0.02 לאורך זמן רב. כלומר לא הגעתי ל load שהם דיברו עליו. אבל יכולתי לבדוק לאורך זמן, רק כאשר ירדתי בערך ל5 מליון בקשות בשניה, ואז הרוחב פס כבר לא נחנק לי.

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

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

כך שלי חסר מאוד מידע איך ומה בוצע בפוסט, אבל אני לא מצליח לשחזר את מה שהם כן מזכירים.
העניין הוא, שאני לא בוטח ברדיס לפעולות ה mq שאני צריך, כי אני צריך מחסנית יציבה של worker..
אם חלילה וחס הוא נפל, אסור שהמידע יאבד, ויותר מזה, במידה ואני צריך להוסיף workers, אני צריך מצב של ביזור המידע, בלי שworker אחד ידרוך על השני, ואני מקבל את זה בצורה טבעית ב Rabbit, (ועוד מספר סוגים של MQ שבדקתי), אבל רדיס מעולם לא תוכנן לזה. הוא נמצא בזיכרון, אני כמובן שיכול להכריח אותו לכתוב לדיסק (איטי מאוד, אבל זה מה שקורה עם persistence queue בRabbit), אבל בשביל לעשות תורים בגישה של Round Robin, ובכן, בלי לכתוב משהו ב lua, אני לא מכיר תמיכה לזה ברדיס, למרות שאשמח לגלות שיש.

ככול שאני עובד כרגע (אמנם עדיין בפיתוח) עם MQ, ככה אני אוהב יותר את הרעיון של השימוש ב Rabbit.
במערכת שאני בונה, יש לי מערכת חיצונית שהיא של ספק אחר שמדברת עם HorentQ, דרך הפרוטוקול שנקרא STOMP (בניגוד לRabbit שברירת המחדל שלו היא AMQP אך תומך גם ב STOMP), והיתרונות של מערכת כזו שהיא robust מאוד, מאפשרת להתמודד עם בעיות שונות, כדוגמת קריסת מערכת, ניתוק התקשורת, התנהלות של load balance של מספר שרתים וכיוב'…

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

 

 

שבוע עם Atom

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

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

העורך משתמש בחלקים של כרומיום, ב node.js, ומשתמש גם ב coffeescript עבור התצוגה של דברים (הנעשים בcss).

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

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

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

  • היכולת להגדיר מה הוא API תקין מבחינת תוספות ולא לאפשר תוספות שאינן כאלו
  • היכולת להגדיר תוספים על בסיס מה שאני עובד כרגע
  • קבלת תוספים איכותיים מבית github לשפות שונות, כדוגמת PHP, רובי וכיוב', מעבר למה שמגיע כברירת מחדל.

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

recursive tail

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

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

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

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

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

הגישה המוכרת ביותר לכך נקראת tail recursion. או רקורסיית זנב בעברית טכנית.

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

מה הכוונה? אשתמש בקוד רובי (שהוא לדעתי קריא מאוד) לשם כך.

רקורסיה בגישה ה"רגילה" תהיה כתובה כך:

def recursive(n)
  if n <= 1
    1
   else
     n * recursive(n - 1)
   end
end

recursive(4)
=> 24

רקורסיית זנב, תראה כך:

def tail_recursive(current, n, result)
  return result if current <= n

  new_result = result * current
  tail_recursive(current + 1, n, new_result)
end

tail_recursive(1, 4, 1)
=> 24

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

אבל לא הכל ורוד בזה. קשה יותר לדבג בעיות ברקורסיית זנב, היות ולמעשה אין לנו stack frames רבים, שיהיה ניתן להבין באיזה שלב יש בעיה. ובכך אין לנו stack trace שיסייע לנו בנושא.

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

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

חשיבה מופשטת

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

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

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

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

תיאור זה מה שhtml עושה מצויין. למשל יש את כל הנושא של aria, המתארת איך להסביר מה בעצם לבצע עם הטאגים, המידע והאלמנטים בכלל עבור קוראי מסך (למשל), וכך למשל הטאג של role מסביר מתוך aria שה ul שיש לנו, הוא בעצם תפריט ולא bullet point, כי לעיצוב אין משמעות, וה div ההוא זה בעצם חלון דיאלוג, וביחד עם שאר ה aria, אני יכול להגיד כי ברירת המחדל שלו, הוא מוסתר.

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

אבל זה לא הכל. גם לעיצוב בhtml יש תיאור, למשל בשביל להגיד שcss הוא עבור המסך. זה נקרא media types.

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

אני מסביר לדפדפן כי הדף שנטען הוא למשל בקידוד של UTF-8, ואני מסביר לדפדפן כי אסור לו לבצע זום.

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

וזה הכיוון שאני חשבתי עליו כאשר דיברתי על מה אני הייתי רוצה ש HTML יבצע.

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

מה זה מאפשר לנו להשיג אם זה בhtml (ולא, זה לא דומה אפילו לתכנות)?
דבר ראשון, זה אומר שאנחנו טוענים פחות מידע. למשל יש עכשיו את פרוטוקול HTTP/2. הפרטוקול אומר כי בגלל שיש המון מידע שצריך להטען, במקום לחכות לכל המידע הזה, אני אכניס הכל בבקשה אחת ואצור multiplexing.
טעינה של המון לוגיקה ב Javascript, טעינה של המון CSS שלא לדבר על תוכן שאולי רק לא יוצג ב HTML, כולם יוצרים בעיות ביצועים. אך במידה ואנחנו נוכל לטעון רק את המידע הרלוונטי כאשר הוא רלוונטי בלבד, אז למעשה כמות המידע ירד, ולמרות ש HTTP/2 הוא נחמד, עדיין אשיג אופטימיזציה מצויינת רק מעצם זה שאני לא טוען מידע שאני לא זקוק לו.

אז איך ניתן להשיג את כל זה בלי תכנות? סתם רעיון, לא באמת הדרך הנכונה:

<div src="/foo.html" alt="no content" media="(max-wdith: 640px and max-height: 480px)">

הנה עוד בעיה, אתרים עובדים עם bootstrap בגרסה 3.3.4 (לצורך ההדגמה בלבד), ובאתר הראשון שנכנסתי אליו שמשתמש בו, אני מקבל עותק מקומי שעשה minified אבל למעט ה copyright נמחקו כל ההערות בפנים.
האתר השני בכלל משתמש ב cdn. האם הדפדפן שלי ידע כי מדובר באותה גרסה בדיוק? לא! אבל מה אם אוכל לתאר לו שזה המצב? האם זה לא יוסיף לי אופטימיזציה? האם זה לא יוסיף לי מהירות של חוסר טעינה מחודשת של המידע? האם זה לא יוריד את כמות התעבורה לטעינת bootstrap בגרסה זו?

הנה הדגמה גם לזה:

<link href="/styles/bootstrap.min.css" rel="stylesheet" provides="bootstrap" ver="3.3.4">

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

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

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

מעניין איך תפתרו את ה"תרגיל" למעלה …

הבעיות שיש לי עם תכנות ריספונסיבי

הקדמה

אנחנו חיים בעולם שיש בו המון מילות באזז, כדוגמת big data, responsive design, cloud computing, סייבר וכיוב' …
כל המילים האלו מגיעות מעולם השיווק, אבל לאדם טכני לא באמת אומרות הרבה.

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

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

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

מונחי יסוד

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

CSS – הם קבוצה של חוקים אשר יכולים לכסות אחד את השני (מכאן השם: Cascading Style Sheet) בצורה שתספק עיצוב למסמך.

הסבר

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

בטח תשאלו מה ההבדל בין הדברים.
ובכן, כאשר מדברים על עיצוב, אנחנו מדברים על איך המראה יהיה תחת רזולוציות שונות, אבל למשל תקשורת סלולרית (HSPA) כדוגמת 3G, 4G, LTE וכיוב', אינן נלקחות בחשבון, היות והן מדברות על תעבורה, לא על מראה.

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

כך שאולי יש מסמך איכותי עם המון מידע, שמעוצב מדהים ויודע להיות מוצג בהרבה רזולוציות, אבל האם הוא באמת יודע להגיב כמו שצריך למגבלות המכשיר אשר המסמך מוצג בו?

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

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

הרעיון של תכנון מערכות גמישות – חלק ראשון

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

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

בהרצאה שהעברתי לפני מספר שנים בשם database free application, דיברתי על עיקרון ה actor model, שבו יש לי מערכת פשוטה אשר יודעת לקבל צורך מסויים ולבקש ממערכת מסויימת לבצע את הפעולה ולהחזיר תשובה.

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

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

כך גם הגישה של actor model שבה אנחנו מקבלים משהו שיודע לשלח בקשות ולקבל תשובות, אך זה לא חייב להיות אותו החלק.

גישה נוספת אשר מפשטת מאוד פיתוח, אך קשה יותר לתכנון נקראת micro services.
הרעיון הוא די פשוט ואנחנו מכירים אותו למעשה מעולם היוניקס: יש משהו קטן שיודע לעשות פעולה אחת ורק אותה, ולהחזיר אותה הלאה.
למשל מכירים את הפקודה cat? היא יודעת להציג פלט מתוך "קובץ" – בברירת המחדל ל sdout.
אם נשלב אותה עם sort למשל, נוכל עכשיו לסדר שורות לפי סדר מסויים שנבחר. אם נשלב עוד תוכנה בשם uniq, עכשיו נעיף כל מה שחוזר על עצמו, ונקנח בפקודה tr, אשר תתרגם לנו סוף שורה לפסיק, ועכשיו נשים את הכל בקובץ חדש, והנה יצרנו מערכת יחסית מסובכת המשתמשת בפעולות מאוד מאוד פשוטות.

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

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

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

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

בחלק הבא, אכנס קצת יותר בצורה טכנית וקצת פחות תיאורטית.

הפרוטוקולים המהירים של גוגל

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

עם המהלך הזה של גוגל יצאו 2 פרוטוקולים מאוד מעניינים:

  1. SPDY – אשר כרגע עובר להית HTTP/2
  2. QUIC – היכולת לקחת את UDP ולתת לו רק חלק מהתכונות של TCP

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

העניין הוא, שבSPDY, יש שימוש בפרוטוקול TCP, והוא, כאשר יש משהו שנמשך הרבה זמן הופך להיות סוג של blocking עד שהבקשה הארוכה הזו מסתיימת.
אז איך מאיצים את זה?
אפשר לחשוב על UDP. הבעיה היא שהוא חסר state. כלומר או שעבר לי מידע או שלא, אבל אני לא יכול לדעת מעבר לזה, וזה אומר שבשביל לדעת אם משהו ביצע, אני יוצר עוד סוג של over-head וזה ליצור בתוך המידע שלי יכולת לדעת אם משהו הצליח או לא.

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

כרגע יש שמועות שבנוסף לHTTP שעבורו תוכנן QUIC, הפרוטוקול יהיה בשימוש בעוד מקומות, כמו למשל webrtc, אך זה רק שמועות כרגע, ונראה שהולך להיות מאוד מעניין 🙂

פונקציה מונדית

אחד הדברים שאני שומע מהרבה אנשים אשר מתעסקים בתכנות פונקציונאלי הוא שפונקציה מונדית (monad function) היא בערך התשובה לכל מה ש42 לא מצליח לכסות.

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

הנה קוד ג'אווה סקריפט (מבוסס jQuery) קצר שאסביר אותו עוד מעט:

$('#id').html('<p>success</p>').addClass('success')

הקוד כאן עושה משהו מאוד מעניין.
אני קורא לפונקציה בשם דולר, אשר מחפשת בעצם id מסויים לפי selector ומחזירה אובייקט.
כאשר נמצא ה id, אני קורא למתודה html, אשר מוסיפה לתוכן ה id עוד אלמנט חדש מסוג p.
כאשר המתודה של html מסיימת את הריצה, אני משרשר אליה עוד מתודה בשם addClass, אשר מסיפה בעצם סוג של class המוגדר מראש כתכונה.

סביר להניח כי מי שמתכנת עם jQuery נתקל בגישה הזו, אבל מה בעצם מתרחש כאן?

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

function init() {
  var self = this;
  return {
     callMe : function() {
       return self;
     }
  };
}

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

הרעיון לשימוש בקוד יהיה בגישה הבאה:

init().callMe().someOtherMethod() ...

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

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

אנשי DBA

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

הבעיה בשוק שלנו, היא שמרבית האנשים המדווחים כי הם מומחים למשהו, במקרה הזה – DBA, אינם באמת מומחים, וחלקם הגדול גם לא מבינים מעבר לאיזה קורס וקריאה של התעוד הרשמי.
רובם אפילו לא עשו ניסויים על התמודדויות של בעיות כדוגמת מה קורה כאשר באמצע כתיבה התקשורת נופלת, או יש בעיה בדיסק, או איך להתמודד עם כך ש slave לא מצליח לשמור את הנתונים, שלא לדבר על כך שיש journal שנכתב והוא מה שנקרא, והרשימה עוד ארוכה.

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

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

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

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

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

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

האלמות

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

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

סינטרה מודולרית

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

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

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

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

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

אנחנו משתמשים בRack בעצם, היות וכמעט וכל הframeworks עבור בניית מערכות web ברובי משתמשים בו, אנו זקוקים לקובץ קבוע בשם config.ru.

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

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

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

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

למערכת שיצרתי ישנם שני מצבים – מערכת לדיבוג REST, ומערכת "בדיקות" אשר עליה אפשר לבדוק שדברים עובדים, והיא בעיקר על תקן "echo" כלשהו.

את המערכת של יצירת המסכים, ושליחת ה REST, יצרתי בקובץ rest.rb, והכל מאוגד שם.
יש שם משהו שהולך לעבור למקום אחר בקרוב, וזה מספר מתודות לסיוע בפעולות.

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

Sinatra תומך במשהו אשר קיבל את השם Helpers, וזה מתודות אשר מסייעות לנו לבצע דברים, בצורה שלא נהיה צריכים לחזור עליה כל פעם, וזה זמין גם ל view שלנו, ובגרסה הבאה שאשחרר (נכון לכתיבת הפוסט), המידע יעבור לקובץ בשם helpers.rb ואיתו עובדים קצת שונה ברובי.

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

במקרה הזה, הגדרתי כי במצב של ‎:development משתמשים ב Sinatra::Reloader, אשר מגיע עם Sinatra-Contrib – תת פרוייקט המספק הרבה כלי עזר לדברים שונים.
הסיבה לשימוש ב Reloader הוא לא לאתחל את השרת בכל שינוי שעושים למחלקה של סינטרה, כאשר Reloader מגלה כי התוכן של הקובץ השתנה, הוא גורם ל rack לטעון אותו שוב, וככה אנחנו לא זקוקים לטעינה מחודשת של השרת עצמו.

המערכת שכתבתי, משתמשת ב template בשם haml, למעשה פעם ראשונה אשר אני משתמש בה מרצון. תוכלו למצוא את ה layout.haml שהוא המסגרת הרגילה וכן כרגע קובץ בשם index.haml תחת ספריית view.
ועבור העיצוב, אני משתמש ב Foundation 5, אשר אני אוהב אותה יותר מאשר bootstrap.
עבור Javascript יש גם את jQuery וגם את knockout.js, כאשר אני נעזר גם ב lodash.js למספר דברים פשוטים, והיא מספקת בעצם גרסה שעברה אופטימיזציה ל underscore.

את הקבצים של Foundation, וכל ה Javascript ניתן למצוא תחת public.

דבר אחרון שנשאר לספר עליו הוא שאני משתמש במשהו אשר נקרא puma.
מה זה ?
puma הוא משהו שלוקח את rack וגורם לו להיות שרת לכל דבר ועניין, אשר ניתן לבצע עליו חיבור לשרתי HTTP שונים, כדוגמץ apache או nginx.
החיבור נעשה על ידי הגדרת proxy בשרתים.

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

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

האקינג לראוטר, או איך להפוך ראוטר לקוד פתוח

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

מאז לא היו לי אתגרים באמת מעניינים בנושא ההאקינג של מכשירים, עד שרכשתי את WDR4300 של TP-Link והחלטתי שאני לא אוהב את הרעיון שאין לי שליטה על הראוטר שלי.

גיליתי שאני מוגבל, היות ובמדינת ישראל יש הגבלת תדרים על ידי משרד הביטחון (ולא משרד התקשורת) – WTF ?!
אז בגלל זה אני למשל לא הייתי יכול לעדכן את הראוטר לגרסה חדשה יותר של TP-Link, כי אין להם הורדה של גרסה "ישראלית" המגבילה תדרים (מצטער אבל זה הזוי).

אז התקנתי openwrt, ופתאום נזכרתי לטובה במוקו, אשר דרש ממני קצת האקינג בשביל לגרום לו לעבוד.
מצאתי את עצמי ב7 בערב עד 1 לפנות בוקר מתאים אותו לצרכים שלי.

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

אני קיבלתי את הראוטר עם חומרה v1.7, שזה השיפצור האחרון של tplink (נכון לכתיבת הפוסט הזה) בנושא החומרה, ונראה שהכל עובד מהקופסא, אחרי שאפשרתי מספר דברים 🙂

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

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

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

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

אני יכול לבצע אפילו התקנת freeswitch עליו, מגרסת הפיתוח (משום מה), שלא לדבר על אסטריסק, או yate.
התקנה של מרכזיה כדוגמת freeswitch למשל, מאפשרת אם מתבצעת נכון, להעביר את הכוח לסוג של DMZ, שמוגן מתקיפות למינהן, אבל כן מסוגל לבצע שיחות.
אך אין לי כוונה להתקין מרכזיה כלשהי על הראוטר.
אם זה לא מספיק, אני יכול גם להתקין את Kamailio מסדרת שלוש וסדרת ארבע, מה שאומר שאני גם יכול לקבל SIP Proxy שאני יכול לתכנת כפי שאני רוצה, אך גם כאן, זה לא יהיה מה שאעשה.

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

בכל מקרה, אני מאוד נהנה 🙂

מזלגות נעוצים

בתקופה האחרונה, נעשו מספר פעולות fork לפרויקטים מוכרים, בהם node.js ודביאן.
בנוסף, פרויקט docker מקבל מתחרה, לאחר שחברת CoreOS הודיעה כי לא מקובל עליה הכיון של docker.

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

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

החשיבה כאילו systemd גוזל משהו, בכך שהוא בא לסדר בלאגן ובעיות שיש במערכת הקיימת כיום, מקבלת תירוצים של "נוצרת תלות במערכת", והתשובה שלי היא: "כי עד עכשיו התלות ב sysv לא היתה קיימת ?"

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

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

הרעיון הוא לא להיות תלוי בהחלטות של חברה מסחרית בפרויקט, ובכך להשאיר אותו פתוח בתפיסה, אם כי זה לא אומר שהתפיסה של המפתחים תהיה מוסכמת על שאר השוק …

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

Rocket
במידה ולא שמעתם על docker, אתם כנראה ישנים איפשהו, או שרחוקים מעולם ה IT. זה השם החם ביותר מאז שסייבר ומחשוב ענן נכנס לעולם, או אולי זה היה 42 ?

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

דוקר התחיל ללכת למחוזות שלא נראים לCoreOS – חברה המתמחה במתן פתרונות של פריסה אוטומטית של שרתים, ואחד הלקוחות הגדולים ביותר המשתמשים בדוקר (כנראה).

החברה של CoreOS, רוצים container ומשהו שזו כל ההתמחות שלו, אבל docker מתחיל להיות stack שלם של דברים, והם ממש לא אוהבים את זה, כי בסופו של דבר,זו סוג של תחרות, לא ?

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

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

Firebird 3.0

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

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

לFirebird יש מספר תחבירי SQL, וחשוב להבין אותם לפני הבנה של התכונות החדשות. סוג התחבירים הם:

  • DSQL
  • ESQL
  • PSQL

DSQL – הם בעצם השאילתות שכותבים ומריצים בצורה דינאמית באמצעות API. המקדם D מייצג את המילה Dynamic.
ESQL – הם בעצם שאילתות עם preprocessor, כאלו שכותבים למשל דרך תוכנה שלנו. ההבדל בינה לבין DSQL היא שבשפה זו משתמשים בפקודה EXEC. הפירוש של המקדם E מייצג את המילה Embedded.
PSQL – השפה שבה כותבים stored procedure וטריגרים. המקדם של P מייצג את המילה Procedural.

בנוסף ישנה שפה בשם DDL – ‏Data Definition Language. זו השפה בה עושים פעולות כדוגמת create table או create database.

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

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

SQL – כלל השפות:

  • Merge Syntax
  • פונקציות window
  • תמיכה ב regex בביצוע SUBSTRING
  • נכנס סוג נתונים בשם Boolean
  • יכולת לשמור גרסאות עם RDB$RECORD_VERSION
  • cursor יציב

PSQL:

  • פונקציות SQL
  • פרוצדורות
  • טריגרים, פונקציות ופרוצדורות משפות חיצוניות
  • חבילות
  • חריגות עם פרמטרים
  • SQLSTAT במצב של WHEN
  • שימוש ב continue בתוך לולאות.
  • cursor יכול להחזיר התייחסות כמשתנה מסוג רשומה
  • cursor דו כיווני

DDL‏:

  • תמיכה במצב null של עמודה ו domain
  • היכולת לשנות קידוד ברירת המחדל של מסד הנתונים
  • הוספה של Identity Column – המקביל ל serial בPG ו Auto Increment של SQLITE ו MySQL
  • תחביר עבור RECREATE SEQUENCE/GENERATOR
  • טריגרים עבור DDL
  • תמיכה ב DATABASE LINGER

אבטחה:

  • תמיכה database encryption
  • תמיכה מורחבת יותר בהרשאות Object
  • הרשאות לעבודה עם DDL
  • הרשאות ברמת מסד הנתונים
  • תוספות לעבודה עם Roles

פיקוח:

  • הוספת יכולות נוספות לסטטיסטיקה אודות שאילתות ומסד הנתונים בכלל

אז מה זה כל הסעיפים האלו ? להמשיך לקרוא

יחידות בדיקה, כן, לא, אולי

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

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

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

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

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

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

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

יחידות בדיקה (מיד יצעקו הבודקים), לא נועדו לכך, ואני אומר להם כי הם טועים !

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

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

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

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

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

האם בדקת באמצעות ‎ /dev/full האם המערכת שלך יודעת להתמודד עם מצב בו אין מקום יותר לשמור מידע ?
רק השבוע סידרתי את MySQL שהרס טבלה כי מערכת הקבצים הגיעה ל 100% ולא היה מקום לרשום את הרשומה, אז הטבלה נהרסה.

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

יותר מזה, אתה בודק את הקוד שלך על 10,000 רשומות, הלקוח קצה שלך אבל משתמש ב10,500 רשומות, ואז יש איטיות (ב10,499 עדיין אין), איך לא ידעת להוסיף עוד רק 500 רשומות לבדיקה ? זה מה שמנהל מסוים יצעק עליך, לא ?

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

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

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

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

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

אז עכשיו חלק מהקוראים כאן (שעוד נשארו ולא עזבו בזעם או שיעמום) יגידו "כן, אבל תראה את סוג הבעיות ב X מול סוג הבעיות של Y".

אבל התשובה היא שזה לא משנה.
בדיקה מוכיחה כי היא מסוגלת לעבור (או לא), אבל היא לא מוכיחה העדר בעיות, אלא רק שהיא עוברת (או לא).

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

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

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

מוגש כחומר למחשבה.

אריקסון ו webrtc

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

אחד הדברים שמאוד נחמדים בעולם ה webrtc, זה היענות של מרבית החברות הגדולות בשוק בשביל לאמץ אותו.

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

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

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

החברה פתחה אתר בנושא, ושמה את הקוד שלה ב github, וגם הוא ברישיון פתוח – BSD.
הכלים שהיא משתמשת גם הם פתוחים, כדוגמת Gstreamer .
הם גם משתמשים במימוש של סיסקו – מימוש קוד פתוח עבור H.264, למעשה זה משהו שהם מספקים שגוגל בכלל לא.

הם גם משחררים דפדפן עבור iOS בשם bowser אשר מאפשר בעצם לקבל תמיכה ב webrtc, ובכך הם הופכים להיות הדפדפן הראשון במערכת הפעלה זו שתומך בזה.
הדפדפן נועד לקדם דווקא את H.264, אבל בנתיים גם מאפשר להשתמש ב webrtc.

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

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

כרגע יש קרב גדול על בחירת קודקים לוידאו, כאשר הקרב הוא בין H.264 לבין VP8 ובעתיד גם VP9.

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

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

knockout.js

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

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

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

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

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

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

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

הכלי נקרא knockout.js. הכלי הזה בנוי בגישה של "תשאיר לי את ה data binding, השאר שלך לעשות מה שתרצה".

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

הגישה של konockout.js קיבלה את השם Model-View-ViewModel אשר מאוד מוכרת לי מעולם הדלפי, רק בצורה שונה.

על רגל אחת, הגישה אומרת כי משהו גרפי יכול להשפיע על המידע, והמידע יכול להשפיע על משהו גרפי.  וזה נעשה לפי אירועים שונים.

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

זה נעשה בצורה די פשוטה בג'אווהסקריפט נקי:

function observable() {
   if (arguments.length > 0) {
      //write stuff
   } else {
      // read stuff
   }
}

למעשה arguments זה המקביל ל var_args של C או open array של פסקל, רק שהוא מכיל בתוכו אוביקטים כי זו שפת javascript.

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

הנה קוד מאוד פשוט ב knockout:

<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
function ViewModel() {
    this.firstName = ko.observable("Joe");
    this.lastName = ko.observable("Bloggs");
 
    this.fullName = ko.computed(function() {
        return this.firstName() + " " + this.lastName();
    }, this);
}
 
ko.applyBindings(new ViewModel());

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

זהו, זה כל מה שהיה צריך. אין צורך בשיריון של namespace, איזורים וכיוב' … בלי לבחור סוג של template וכיוב'.
במקום שבו משתמשים בשדות, אז נכנסים לתוך ה namespace של אותו אובייקט, ואז במידה ורוצים לצאת החוצה משתמשים ב ‎$parent ובמידה ורוצים להתחיל מההתחלה, משתמשים ב ‎$root כלומר בנקודה שבה קראנו ל applyBindings.
אם אתם רוצים את האובייקט עצמו שאנחנו משתמשים בשדה מסוים (למשל כאשר משתמשים במערך), משתמשים ב‎$data וישנם עוד סוגי משתנים. הנה הסבר פשוט בנושא.

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

systemd

זהירות פוסט ארוך מאוד

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

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

מהפכה נוספת, היא החלפת הגישה של sysv כמעט לגמרי, עם מנהלי init שונים, כאשר זה שלוקח את הכי הרבה אש, וגם בשימוש הרב ביותר הוא systemd. זה השם שלו, כפי שהוא כתוב. והd בסוף מצייג כמובן את המילה daemon, כי הוא יושב ב pid 1, ומנהל את העליה של כל השאר, אחרי שמנהל האתחול (כדוגמת grub) מריץ אותו.

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

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

בניגוד ל init הישן, ולדעתי הלא טוב, systemd מביא איתו גישה חדשה, אך בראש ובראשונה הוא פותר בעיות שפעם לא נחשבו לכאלו, וחלקם גם לא התקיימו, אבל כיום הן כן – תאימות בכתיבת services בראש ובראשונה. להמשיך לקרוא

go_libhdate

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

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

בGo יש משהו שנקרא cgo – אפשרות לגרום לקוד שלך לדבר עם C.
הוא בעצם מספק סוג של preprocessor אשר לוקח את קוד ה Go, ומתרגם אותו לשפת C בצורה כזו שיש תאימות בין הקוד לבין שפת C.

אם תריצו ידנית את הפקודה

go tool cgo

על חבילה המדברת (כלומר עושה binding) עם C, תראו שתקבלו בעצם ספרייה בשם ‎_obj ושם כל ה"קסם" גלוי לעיניים: להמשיך לקרוא

טלפון חכם, טלפון טיפש

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

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

התשובה המסובכת יותר: להמשיך לקרוא

שינוי פורמט לוג של Rack, והסתרת אזהרות ברובי

יש לי מערכת העובדת עם Sinatra, unicorn ו nginx ביחד.

הבעיה היא, ש nginx נמצא בראש, והוא מעביר את הבקשה ל unicorn, אני מקבל את כתובת ה ip בלוג של ה nginx ולא של הפונה המקורי, ורציתי לשנות את זה, שאראה את הכתובת של הפונה, ולא של nginx.

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

# ... 
# snips 
# ...

# Overriding the original constant
FORMAT = %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n}

# ... 
# snips 
# ...

def log(env, status, header, began_at)
  now = Time.now
  length = extract_content_length(header)

  logger = @logger || env['rack.errors']
  logger.write FORMAT % [
    # adding IP
    env['HTTP_X_REAL_IP'] || env['HTTP_X_FORWARDED_FOR'] || 
    env["REMOTE_ADDR"] || "-",
    env["REMOTE_USER"] || "-",
    now.strftime("%d/%m/%Y %H:%M:%S"),
    env["REQUEST_METHOD"],
    env["PATH_INFO"],
    env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"],
    env["HTTP_VERSION"],
    status.to_s[0..3],
    length,
    now - began_at 
  ]
end

# ...
# snips 
# ...

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

proxy_set_header        X-Real-IP       $remote_addr;

במידה והוא אינו קיים, אני מנסה לבדוק האם HTTP_X_FORWARDED_FOR קיים, במידה ולא, אז אנסה את מזלי עם REMOTE_IP, ואם זה גם לא, אז אין IP.

במידה ותריצו את זה, תגלו אבל בעיה חדשה – הודעת אזהרה ש FORMAT כבר הוגדר:

warning: already initialized constant Rack::CommonLogger::FORMAT
/home/ik/.gem/ruby/2.0.0/gems/rack-1.5.2/lib/rack/commonlogger.rb:24: warning: previous definition of FORMAT was here

אז מצאתי להודעה הזו פתרון נחמד ופשוט:

module Kernel
  def suppress_warnings
    original_verbosity = $VERBOSE
    $VERBOSE = nil
    result = yield
    $VERBOSE = original_verbosity
    return result
  end
end

והשימוש בו יהיה בצורה הבאה:

module Rack
  class CommonLogger
    Kernel::suppress_warnings do
      # Overriding the original constant
      FORMAT = %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n}
    end

    def initialize(app, logger=nil)
...

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

הקוד המלא נמצא כאן.

webrtc ORTC

הקדמה

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

הרעיון הוא לקחת SDP ו RTP (שכמובן מכיל RTCP) ולאפשר להזרים אודיו ווידאו בצורה טבעית בדפדפן ללא שימוש בתוספים.
הטכנולוגיה גם מגיעה עם תמיכה ב STUN, ICE ו TURN.

היא תומכת ב OPUS, ו G711, ומחייבת אותנו לעבוד בצורה מאובטחת תחת DTLS,

עכשיו כל מה שנשאר זה לממש מערכת סיגנלים כדוגמת SIP או כל פתרון אחר – פשוט יותר עם web sockets,שגם הוא כיום (לפי התקן של webrtc) חייב כבר להיות מאובטח תחת TLS, ויש לנו פיתרון סטרימינג מלא.

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

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

הדגמה קלה (מה RFC):

v=0
o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com
s=.
c=IN IP4 host.atlanta.example.com
t=0 0
m=audio 49170 RTP/AVP 0 8 97
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:97 iLBC/8000
m=video 51372 RTP/AVP 31 32
a=rtpmap:31 H261/90000
a=rtpmap:32 MPV/90000

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

הנה הסבר על מה שאתם רואים מול העיניים שלכם:
האות v, מייצגת version – גרסת הפרוטוקול, שלפחות כרגע היא תמיד 0.
האות o, מייצגת origin של הבקשה, ומכילה (לפי הסדר) – שם משתמש, session id, בנוסף session-version, סוג רשת (אינטרנט), סוג הכתובת, כתובת הרשת.
האות s מייצגת את session, כלומר השם שלו.
האות c מייצגת מידע על connection. זה אומר סוג הרשת, סוג כתובת הרשת, כתובת הרשת.
הכוונה היא לאן רוצים להתחבר בשביל המדיה.
האות t מייצגת זמנים.
האות m מייצגת מדיה, עם סוג מדיה, פורט דינאמי, פרוטוקול משלוח של המדיה, ומידע הקשור לפרוטוקול.
האות a מייצגת attribute, שזה תכונות שונות, למשל כאן, זה מייצג איזה קוקדים של אודיו ישלחו, כולל הקוד שלהם שמוגדר ב RFC עבור כל סוג קודק.

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

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

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

תוכן

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

לפני ORTC, תכננו פרוטוקול אחר לגמרי, אשר היה מאוד low level, ומאוד קשה להגנה, וסיפק יותר מידי כוח בצד המשתמש. הפרוטוקול קיבל את השם Open Peer. אז בגלל הסיבות האלו, החליטו לרדת ממנו.

ואז ישבו הרבה אנשים, אשר רובם יצרו את webrtc ואת Open Peer, והחליטו על גרסה 1.1 לwebrtc בכנס מסחרי מסוים, אם כי למרות ההכרזה על 1.1 ההכרזה מרגישה יותר כמו 2.0.
השם לפרוטוקול החדש באותו כנס, קיבל את השם ORTC או Object Real Time Communication, אשר ה draft הראשון (מבחינת יכולת מימוש) שלו שוחרר באוגוסט 2014.
היכולת לעקוב אחרי דברים, נעשת באתר ייעודי לכך בשם ortc.org.

הרעיון הוא לספק סוג של API, שמצד אחד קל לתכנות, ומצד שני קל לאבטח, אשר מאפשר לשלוט בצורה קלה ופשוטה יותר במידע על המדיה, כאשר יש API בצד ה javascript, אך גם עם תאימות לאחור, בשביל לא לשבור פתרונות קיימים.
אבל לא סתם API, אלא הדגש הוא על גישה של Object Oriented, כאשר בעבר דיברו על כך שהיא תכלול את היכולת להחזיק אובייקטים של סוקטים בשם RTCSocket אשר ניתנים לשימוש מחודש במידת הצורך, ובכך בעצם לעשות שימושיות ב RTC ללא צורך באתחול מחודש של הכל. אך אינני מוצא זאת בdraft האחרון (נכון לכתיבת פוסט זה).

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

הבעיה היא שORTC הוא סוג של API שבסוף משתמש ב SDP (אבל רק בהתחלה – תאימות לאחור) ואח"כ כנראה שיפרד מהגישה הזו. אבל הם עוד לא בטוחים בזה. כלומר הרעיון שלהם, הוא שבסופו של דבר לא יהיה SDP, אלא דיבור ישיר בין ה"ענן" (מערכת כלשהי שאתם תבנו בצד השרת) לבין הדפדפן, ואיכשהו יוחלט מה יורץ.

זה רעיון נחמד, אבל איך הוא מתבצע כאשר אין לך SDP ?
התשובה פשוטה – אתה תממש משהו כזה מחדש, ואתה תספק לו שם חדש, למשל השם Media Information Protocol או משהו בסגנון.

ואכן, זה מה שORTC מבצע. הם יצרו אובייקט בשם RTCRtpCapabilities, אשר התפקיד שלו לדבר על "מה אני צריך" עם הצד השני וניתן אפילו לעשות החלפה בזמן ריצה של המידע (ב SIP זה נקרא re-Invite).

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

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

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

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

גו – השלמתה של שפה

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

למשל יכול להיות שרת ג'ינטו מ 2007 (שלא התעדכנה) ומערכת פדורה 20, שהמערכת צריכה לרוץ על שניהם.

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

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

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

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

צד השרת (שלי) נשאר ברובי, עם grape עבור הקליינט בGo, ועבור המשתמש הרגיל, יש סינטרה (אין יותר מידי ווב שם עבור הלקוח).

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

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

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

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

קודקים למתחילים

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

ישנו מושג בעולם המולטימדיה אשר נקרא codecs. הפירוש הוא encoder ו decoder של מידע כדוגמת אודיו ווידאו.

ישנם הרבה מאוד סוגים מאלו, אבל מה זה בעצם אומר ?

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

ישנם 2 סוגי דחיסת נתונים בעולם הקודים:

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

Lossless מייצג צורת דחיסת נתונים עם יכולת שחזור מלא של המדיע ללא איבוד המידע. הדחיסה נמצאת בעיקר בדחיסת מידע מדוייק, כדוגמת טקסט, פורמטים כדוגמת ZIP וכיוב'.
ישנם גם תמונות (כדוגמת PNG) ואפילו קבצי קול (כדוגמת FLAC) המשתמשים בשיטה זו, אך אלו נדחסים פחות טוב בדרך כלל, ולכן גודל הקובץ גדול יותר, מאשר אם היו משתמש בים lossy.

G711

להמשיך לקרוא

הפילוסופיה של הקוד

ישנו פודקאסט מאוד מעניין שקיבל את השם "הפילוסופיה של הקוד".

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

הפודקאסט מדבר על טכנולוגיות בעולם התכנות. אבל בניגוד להרבה מאוד מאוד מקומות בהם מתמקדים רק בכותרת, כלומר, לא מתפזרים בדברים ומסבירים אותם לעומק, כאן יש כניסה ממש לעובי הקורה. למשל נגיד ומדברים על javascript (הפודקאסט השלישי בשם mocha), אז לא מדברים רק עליה, אלא גם על ההשפעות שממנה היא הגיעה, מה זה אומר, הרבה מונחים, התנהגויות מוזרות וכיוב' …

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

כל זה נעשה בשפה העברית.

ממליץ בחום לכל מי שהנושאים האלו מעניינים אותו ורוצה להקשיב.

ענב הזעם – API

ברובי, הדבר הכי מוכר ביקום הוא framework בשם Rails, אשר מאפשר ליצור אתרים דינאמיים בצד השרת.

ישנם עוד מספר סוגי framework עבור עולם ה web, בהם Sinatra, שאני משתמש המון, ולאחרונה התחלתי לשחק גם עם framework מאוד מעניין שנקרא grape.

Grape הוא framework אשר נועד לתת לנו כלי לפיתוח API. זה אומר שכל הפיטצ'רים שלו הם על טהרת REST ואין שום דבר הקשור להצגת templates למשל בצד המשתמש.

כלומר ניתן להציג xml, json או כל מבנה אחר של מידע, אבל זה לא נועד ליצור אתר, אלא להחזיר מידע, או לבצע פעולות API.

הנה הדגמה קלה כיצד תראה תוכנית שכזו: להמשיך לקרוא

למי הפרופיל רשת חברתית קיים אחרי המוות ?

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

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

facebookעכשיו השאלה היא לא רק למי שייך המידע, אלא מה קורה עם פרופיל שכזה כאשר אדם מת ?

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

מה אנחנו כבני אדם בכלל רוצים שיהיה בחברה שלנו במצב שכזה ?

פוסט למחשבה.

סידור תיבות דואר

יש לי חבר קיבל פרויקט בעבודה שלו – סידור מחדש של שרתי דואר של לקוחות החברה (חברת ISP), ולמרות שהם כולם בתוצרת maildir, הם מסודרים בצורה לא קבועה, וחלקם נמצאים בספרייה בשם mbox למשל, למרות שהם לא בפורמט הזה.

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

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

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

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

טיפים על עבודה ב ssh

כאשר פותחים חיבורים של ssh,אנחנו מקבלים משהו שנקרא channels, שהם בעצם הצורה ש ssh מזהה את החיבורים שלנו על אותה "מנהרה" שמוצפנת.
חשוב להדגיש כי חיבור לשרתים שונים, לרוב לא יכללו את אותה המנהרה, אלא רק חיבורים לאותו השרת, אך כל חיבור מכיל channels.
אני נוהג להשתמש בצורה שבה כל חיבור לשרת, משתמש בsocket בודד, וכך עושה את החיבור יעיל אפילו יותר – היות וגם ככה כל חיבור מנוהל על ידי channel.

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

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

Host *
  ControlPath ~/.ssh/sockets/master-%l-%r@%h:%p
  ControlMaster auto
  GSSAPIAuthentication=no
  ServerAliveInterval 25
  Compression yes
  IdentityFile ~/.ssh/id_rsa

ה"חלק" הזה שיצרנו בעצם יוצר קבוצה של הגדרות עבור 100% מהחיבורים שלנו (אלא אם נדרוס אותן). אנחנו יודעים זאת, בזכות הglob של כוכבית.
אנחנו אומרים לו ליצור קובץ socket על שם החיבור המדויק שלנו, ושopenssl ינהל אותו לבד. מדובר למעשה ב unix socket, וזה מה שמאפשר את השיתוף.
אנחנו אומרים למערכת שלנו כל 25 שניות לשלוח סוג של ping בשביל להשאיר את החיבור פתוח (אחרת יש חיבורים שיסגרו בשרתים שונים אם אין תגובה אחת לזמן מסוים), אנחנו דוחסים את המידע העובר עם החיבור, ובסוף אומרים מה המפתח ברירת המחדל שלנו.

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

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

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

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

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

הגעתי אל המשרדים של השותף, במטרה ליום שלם של מחקר בנושא. ובאיזשהו שלב, גם הצלחתי לשחזר את הבעיה – ובעיה זו היתה מאוד קשה לשחזר, ולמעשה רק אחרי הצהריים הצלחתי להגיע אליה, למרות שהתחלתי את המחקר ב9 בבוקר.

הפעלתי wireshark, וגיליתי כי three way handshake אינו מתבצע עד הסוף, ולמעשה ה ACK האחרון לא נשלח חזרה על ידי השרת (ה wireshark היה על השרת עצמו).
יש מספר נסיונות שליחה של לחיצת היד, ובסוף יש RST על הבקשה כי לא ניתן היה ליצור קשר, והבקשה התנתקה.

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

בנתיים דיברתי עם בוריס, והוא הצליח למצוא קישור מעניין שמדבר כי אפצ'י בברירת המחדל מגיע עם דגל של TCP_DEFER_ACCEPT. עד כמה שאני מבין, הדגל הזה אומר לשרת לא לחכות ל three way handshake, אלא במידה ונשלח מידע אחרי החיבור הראשוני, כשעוד אין ACK, אלא רק SYN-ACK, ניתן כבר לקבל את המידע, ולמעשה רק כשהוא יסתיים להישלח, ישלח גם ה ACK.

מסתבר שבאפצ'י 2 הדגל מאופשר בברירת המחדל (בניגוד לnginx ששם צריך להגיד לו את זה במפורש), ולכן צריך לכבות אותו.

בשביל לכבות את הדגל בחיבור, צריך לשים ב httpd.conf הראשי, את הקוד הבא:

 AcceptFilter http none

במידה ויש הגדרה אחרת בנושא, למשל עם data, יש לשכתב אותה לnone.
וזה מכבה למעשה את הדגל של TCP_DEFER_ACCEPT ועכשיו אפצ'י חייב לחכות ללחיצת היד כמו שצריך לפני שיוכל לנתח את מה שנשלח.

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

 

עוד מערכת לדיווח על אזעקות

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

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

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

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

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

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

לגבי כתיבה של גרסת Go כרגע ירדתי ממנה, אולי אבל אחזור ואצור משהו בנוסף, רק כהוכחת יכולת עבור עצמי.

 

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

NaCl, Sodium והצפנה

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

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

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

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

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

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

מערכת פשוטה לשיתוף קבצים פנים ארגונית

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

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

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

אז החלטתי כי במקום להמשיך ולחפש תוכנה, אכתוב משהו פשוט שיעשה את זה, ותוך שעה וחצי, כולל דיבוג כתבתי את simple file sharing – גרסת mercurial וגרסת git.
זהו מנוע פשוט, הכתוב ברובי עם סינטרה ללא javascript שאני כתבתי, אלא cgi מול html/css פשוטים מאוד מבוססי foundation.

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

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

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

כנס אלטרנטיבי לאוגוסט פנגווין

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

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

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

  • אנשים שיסיעו לארגן
  • מרצים
  • יצירת גרפיקה ואתר לכנס
  • סיוע בתמלול ההרצאות לאנשים עם מוגבלויות שונות כדוגמת חרשים
  • צילום ההרצאות
  • סיוע ביצירת נגישות להרצאות – בכל מה שניתן
  • סיוע בפרסום
  • להגיע לכנס 🙂

עריכה: אתר הכנס
ניתן ליצור קשר עם "חתול" – אחד המארגנים.

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

פוסטים נוספים בנושא:

node.js כן או לא ?

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

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

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

אבל יש לי עם זה בעיה, שגורמת לי לחשוב ולרעוד מפחד, כל פעם שאני מסתכל לכיון node.js.
גוגל החליטה לפני שנה לעשות fork לwebkit שהוא עצמו fork של khtml, וקראה לפרויקט שלה blink.
היא עשתה זאת, מבחירה מסחרית גרידא ("אנחנו בידלנו את עצמנו בצורת פרוססים וטרדים שלנו, ולכן עשינו fork").

אמנם node.js לא משתמש ב webkit או ב blink, אבל הוא יוצר לי בעיות קשות:

  1. האם v8 ישאר גם מחר ?
  2. האם יהיה fork ?
  3. האם הוא ימשיך להיתמך ?
  4. האם הכיון שלו כיום ישאר, או אולי ישוכתב/ישתנה לגמרי בגרסאות חדשות יותר ?

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

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

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

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

אני עדיין לא בטוח שיש לי תשובה לכך, אבל אלו כרגע החששות שלי בנושא. מה דעתכם ?

סליחה, יש לכם אולי זמן ללמוד טכנולוגיה חדשה ?

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

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

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

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

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

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

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

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

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

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

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

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

ממליץ בחום לצפות בה:


 

עייפות הIT

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

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

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

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

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

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

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

מוקדש כחומר למחשבה

תם עידן הפרטיות, תחי הפרטיות

Le roi est mort, vive le roi !

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

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

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

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

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

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

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

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

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

זה תלוי בנו בלבד, ובבחירות שלנו. אני מקווה שכולנו ננהג בחוכמה בנושא.

מוגש כחומר למחשבה.

שחרור משאבים ברובי ו Go

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

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

כיצד זה מגיע לידי ביטוי ?
הדגמה בGo:

func open_file {
f, err := os.Open("/tmp/a_file")
if err != nil {
log.Fatal("Unable to open a_file")
}
defer f.Close()
// do something here
}
view raw defer.go hosted with ❤ by GitHub

אחרי do something here אין קוד לסגור את הקובץ, בזכות defer שהיה אחרי בדיקת שגיאות.
הוא גם מסוגל לקבל פונקציה אנונימית וניתן לבצע שם עוד בדיקות במידת הצורך.

ברובי קוד שכזה יראה כך:


def read_file
  f = open('/tmp/a_file')
  # do something here
rescue => e # catch exceptions globally
   $stderr.puts("Unable to open a_file") if e.kind_of? Errno::ENOENT
ensure
  f.close if f
end

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

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

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

יצאה גרסת 1.4.4 של FreeSwitch

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

המרכזייה בנויה מיחידת בסיס (core) ואוסף מודולים שונים, אשר מספקים לה תכונות שונות, בהתאם לצורת השימוש.
למשל, במידה ומעוניינים ליצור call centre, אז יש מודול לכך, ובמידה ורוצים ליצור ivr בצורה פשוטה, גם לכך יש מודול. אפילו חדרי ועידה מקבלים תכונות רבות יותר מאשר אלו של אסטריסק.
כל ההגדרות כולל ה diallplan נעשות באמצעות קבצי xml, אבל אפילו תוכניות החיוג זה למעשה מודול חיצוני. כאשר מעוניינים בכך, ניתן לצאת לשפות תכנות חיצוניות (גם כמודול), כדוגמת lua (שנתמכת הכי טוב), פרל (לא מתועדת מספיק), פיתון ואפילו ג'אווה סקריפט (יש תמיכה ב v8 ו SpiderMonkey, כאשר האחרון נמצא בשלב deprecated).
בנוסף, יש מימוש של event sockets – אחת הדרכים לשלוט במרכזיה, ולקבל אירועים ממנה, על ידי שימוש בפרוטוקולי תקשורת, כדוגמת TCP. ואלו מאפשרים חיבור של שפות נוספות, כדוגמת Go.
בנוסף, יש גם ספרייה שממשת את rayo – תת פרוטוקול xmpp אשר מאפשר גם שליטה דומה ל event sockets.

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

עץ 1.4 הביא איתו המון חידושים ושיפורי ביצועים, בהם בראש ובראשונה תמיכה מלאה בתקני webrtc ו websockets, אשר מניסיון שלי, טובים יותר מהתמיכה שיש באסטריסק. נכון לכתיבת שורות אלו, כרום ביטל את התמיכה ב SDES, דבר שמקשה על התמיכה ב webrtc של אסטריסק ללא בנייה אישית שלו, בעוד שFreeSwitch תומך ב dtls-srtp ללא בעיה מהקופסא.

בעוד שהפצת הלינוקס העיקרית של אסטריסק מבוססת red-hat (בדגש על centos), החל מגרסה 1.4, דביאן היא ההפצה הרשמית של Freeswitch.
במידה ואתם עדיין על centos5, אז יש סיכוי כי אולי תתקלו בבעיות בעת השדרוג.

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

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

העניין החשוב באמת הוא, ש FreeSwitch מספקת את האפשרות לקבל מרכזייה יציבה, שמשתמת יחסית במעט משאבים (תלוי באופן השימוש), עם המון יכולות.
היא יכולה להיות למעשה מרכזייה ברמת class 4 ולא רק class 5 בניגוד לאסטריסק למשל. ועץ 1.4 מבטיח כניסה לעולמות חדשים.

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

סיפ, מדוע זה לא פשוט כמו HTTP ?

אחד התסכולים הרבים שיש בעולם ה VoIP הוא התמודדות עם בעיות הקשורות לעולם הרשתות.

רוב העולם בטוח כי HTTP זו התקשורת המסובכת ביותר שיש בעולם הרשתות, ולכן אני שומע את השאלה: "אני לא מבין למה SIP לא פשוט כמו HTTP ?"

ובכן, התקן של SIP בראש ובראשונה מדבר כי חייבים לתמוך ב UDP, אך ניתן גם לתמוך ב TCP.
אבל זו לא הבעיה בכלל. UDP זו לא צורת תקשורת שהיא אויב כלשהי, היא פשוט עובדת ללא ידיעה מה מצב המידע שנשלח, מה שאומר שאת המצב מעלים לרמת פרוטוקול במקום לרמת תשתית (layer 4)

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

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

על זה נוסיף עוד בעיה "נחמדה" אשר נקראת NAT, כאשר ישנם 2 סוגי NAT: להמשיך לקרוא