פיתוח PHP עם PDT

היסטורית, מפתחי PHP תמיד היו מקופחים.
בזמן שמפתחים לשפות אחרות נהנו מסביבות פיתוח מתקדמות, עם יכולות דיבאג (נקודות עצירה, בדיקת ערכי משתנים בזמן ריצה ועוד), השלמת קוד תלויית הקשר ועוד, הרוב המכריע של מפתחי הPHP השתמשו בעורכי טקסט פשוטים יחסית (ואני לא מזלזל בVIM ובEmacs).
את FireStats התחלתי לפתח כאשר לא ידעתי כמעט כלום על PHP, ובוודאי שלא ידעתי על סביבות הפיתוח המומלצות לפיתוח בPHP, כך שהתחלתי את הפיתוח בשימוש בVIM ישירות על שרת הפיתוח שלי (המחשב בסלון), והייתי מרוצה מהתוצאות.
לפני מספר חודשים נתקלתי בMylar, שאיפשר לי התממשקות נוחה למערכת ניהול הבאגים של FireStats, שעובדת על trac.
החלטתי שזה שווה את המאמץ של המעבר, והתחלתי לחפש פתרון PHP לEclipse.
בהתחלה מצאתי את PHPEclipse, פלאגין שעובד די טוב, אבל כמה באגים עיצבנו אותי, ושמתי לב שהפרוייקט די רדום, אז נטשתי אותו לטובת PDT שמפותח כתוסף רשמי של פלטפורמת Eclipse, בעיקר על ידי מפתחים של Zend.

PDT נמצא כרגע במצב די טוב, יש כמה באגים קטנים אבל הפרוייקט חי ומשחרר גרסאות חדשות כל כמה חדשים.
ההשלמה האוטומטית עובדת יפה מאוד, גם בהקשר של PHP, גם בהקשר של HTML ואפילו בהקשר של CSS וJavaScript.
בנוסף, במאמץ קטן יחסית ניתן לאפשר דיבוג באמצעות xdebug מתוך Eclipse (!), ממש סוף הדרך.

עבודה עם PDT:
pdt.png

דיבאג עם PDT:
pdt1.png

בונוס למגיב הראשון שיספר מה עושה הפונקציה fs_sum_search_tree.

גוגל קונים את פידברנר

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

פענוח שפות פורמליות

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

key1=value1
key2=value2
key3=another value

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


private static void parse(BufferedReader reader) throws IOException
{
String line = null;
while ((line = reader.readLine()) != null)
{
StringTokenizer tok = new StringTokenizer(line, "=");
String key = tok.nextToken();
String value = tok.nextToken();
System.err.println("Read: key = " + key + ", value = " + value);
}
}

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

key1=ABC\
DEFG

פה יש רק ערך אחד לפי החוקים של השפה.

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

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

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

בגדול, יש חלוקה כזו:
חלק ראשון הוא המנתח הלקסיקלי, שמקבל זרם תווים, ומוציא זרם של לקסמות, הידועים גם כאסימונים (Tokens). האסימונים מוגדרים באמצעות ביטויים רגולריים (שפה דומה לשפה שמשמשת את grep).
חלק שני הוא המנתח התחבירי, שמקבל זרם של אסימונים מהמנתח הלקסיקלי, ומוציא עץ תחביר אבסטרקטי (Abstract syntax tree).
יש כלים שיודעים לקבל הגדות לקסיקליות ותחבירות, ולייצר מזה בצורה אוטומטית קוד שיודע לפענח קלט בשםה הנתונה. למעשה, הטכניקה המקובלת לכתיבת קומפיילרים כבר עשרות שנים מתבססת על כלים אוטומטיים כאלו.
את הPreprocessor של אנטנה כתבתי תוך שימוש בantlr, שהוא כלי כזה שכתוב בג'אווה, אבל יודע לייצר קוד במגוון שפות, ובקורס קומפילציה שאני לוקח כרגע בפתוחה לומדים להשתמש בכלים הקלאסיים – flex וbison.
לדעתי antlr הרבה יותר סימפטי לעבודה.

אם תהיה דרישה אני ארחיב עוד בנושא.

בעיות רשת מוזרות

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

בעיית רשת מוזרה מספר 1:

BattleField 2142, משחק רשת מרובה משתתפים עובד היטב, עד שיום בהיר אחד הוא מפסיק לראות שרתים ברשת.
פניתי לתמיכה של EA, שהציעו להסיר ולהתקין מחדש, תוך מחיקה של כל רמז לספריות נוספות שהמשחק שומר (במילים אחרון, אין להם מושג והם יורים באפלה).
עקבתי אחרי ההוראות, וכמובן שהבעיה לא נפתרה.
בצר לי, הורדתי את WireShark (לשעבר Ethereal), שהוא Network sniffer רב עוצמה, והפעלתי אותו לפני ההפעלה של המשחק.
wireshark
די בקלות זיהיתי את הבעיה: המשחק שולח בקשת DNS למציאת כתובת הIP של השרת שמחזיק את רשימת השרתים, מקבל שגיאה מהDNS ומתעלם ממנה ומפסיק לנסות בלי למסור הודעת שגיאה למשתמש.
ברגע שהחלפתי את שרת הDNS שלי הבעיה נפתרה.

בעית רשת מוזרה מספר 2:

Call of duty 2, עוד משחק רשת משובח, עובד היטב ברשת המשרדית, עד שיום בהיר אחד הוא מפסיק לראות שרתים אחרים.
במילים אחרות, עמרי לא יכול להצטרף לשרתי המשחק ברשת, ונאלץ לעבוד בעבודה.
לאחר הטחת האשמות סרק ברשת, בסוויץ' במערכת הפעלה ובאלוהים, הפעלתי את WireShark על שני מחשבים, אחד בו אין בעיה, וזה שלי.
לאחר שהפעלתי את המשחק בשניהם, בחנתי את תעבורת הרשת, וגיליתי את הדבר הבא:
המשחק שולח בBroadcast פקטת UDP לכל הרשת כשהוא מחפש שרתים, והשרתים אמורים לענות לו ולמסור לו מידע על עצמם. (כדי לשלוח Broadcast צריך לשלוח את הפקטה לכתובת 255.255.255.255).
עד פה הכל טוב, רק שראיתי משהו מוזר במחשב שלי. במקום לצאת מכתובת הIP הרגילה שלי הוא יצא מכתובת IP אחרת, שבכלל לא נראית כאילו היא ברשת הפנימית שלנו.
מסתבר שהכתובת הנ"ל (192.168.40.1) שייכת למתאם רשת וירטואלי של VMWare, ומסיבה עלומה המשחק שלח את חבילת הUDP כאשר הכתובת של המתאם היא כתובת המקור של החבילה. השרת ניסה לענות, אבל מכיוון שהכתובת לא ברשת לא קיבלתי את התשובה.
אחרי ביטול של מתאמי הרשת של VMWare הבעיה נפתרה.

בעיית רשת מוזרה מספר 3:

תוכנה שאנחנו מפתחים בעבודה מקבלת זרם של חבילות UDP משרת.
התוכנה עובדת טוב מול שרת אחד, ומאוד לאט מול שרת שני, שני השרתים מריצים את אותה תוכנה בדיוק.
הפעלה של WireShark על השרת והמכונה שמריצה את הלקוח מראה שהשרת שולח את החבילות בקצב הנכון, והחבילות מגיעות למכונת היעד באותו קצב, ובכל זאת לאפליקציית הלקוח החבילות מגיעות מאוד לאט.
הלקוח רץ על WTK, שהוא אמולטור של סביבות ג'אווה של פלאפונים. לWTK יש כלי Profiling פנימי, שמאפשר להגיד איפה האפליקציה משחיתה את זמנה.
הפעלתי את הפרופיילר, והסתבר שהיא משחיתה את מיטב זמנה בפונקציית מערכת בשם getHostByName.
תפקידה של הפונקציה הזו הוא בעצם לקבל כתובת שמית ולהמיר אותה לכתובת IP מספרית, במילים אחרות – לקרוא לDNS.
מסיבה לא ברורה הפונקציה לקחה הרבה זמן, ומסיבה לא ברורה היא נקראה עבוד כל חבילת UDP שהגיעה לאמולטור (באג באמולטור לדעתי, אבל שיהיה).
לחלונות יש קובץ בשם hosts בספריית החלונות, שדומה מאוד לאותו קובץ במערכות יוניקס (זה מראה על הקשר בין חלונות ליוניקסים), הקובץ משמש להוספה ידנית של רשומות לDNS המקומי.
ברגע שהוספתי את כתובת הIP של השרת לקובץ ההוסטים הבעיה נפתרה.

עד כאן פינתנו, בעיות רשת מוזרות.

Antenna 0.9.5-beta

Antenna הוא פרוייקט ותיק לבניה של ישומי J2ME (ג'אווה לטלפונים סלולאריים), הפרוייקט היה בתרדמת די ארוכה.
לפני כמה שנים התחלתי לתרום קוד לפרוייקט, אבל התרדמת היתה כל כך עמוקה שהשיפורים לא שוחררו.
עד עכשיו.
קיבלתי הרשאות Commit לפרוייקט לפני כחצי שנה, הכנסתי את השיפורים שלי, כשגולת הכותרת היא Preprocessor חדש ורב עוצמה, שמגיע גם כפלאג-אין לEclipse (אבל כמובן מאפשר גם הרצה מסקריפט ANT) וכן Task שמאפשר חתימה על מידלטים.
את הTask שחותם פיתחתי מזמן, ואת הPreprocessor ממש לפני כמה חודשים, במסגרת העבודה שלי בחברת Vollee.
ביום שישי שחררתי גרסא חדשה (0.9.5-beta) שכוללת את הכל.

antenna preprocessor

הגשת פרוייקט על דיסק Knoppix

במסגרת קורס הפרולוג, נתבקשתי לכתוב פרוייקט.
בחרתי במנוע שחמט, וחיברתי לו ממשק משתמש שכתוב בג'אווה (Jin).
החיבור בין פרולוג לג'אווה מתבצע באמצעות API בשם JPL.
אחרי שסיימתי לפתח, גיליתי שלמרות שכל הרכיבים של הפרוייקט (SWI-Prolog, Java) כוללים גרסאת חלונות – העסק לא עובד בחלונות, עקב בעיה בJPL שגורמת למערכת להתקע בחלונות.
במקום לנסות לפתור את הבעיה החלטתי לעקוף אותה בכך שאני אגיש את הפרוייקט על לינוקס.
מכיוון שההתקנה של הפרוייקט לא טריויאלית – צריך להתקין ג'אווה, את הגרסא המתאימה של SWI-Prolog, ואולי גם לשנות מסלולי קבצים בקובץ ההרצה בהתאם, החלטתי להשתמש בגרסא מותאמת של Live CD, שמכילה התקנה מוכנה של כל העסק.
בדקתי את DSL, אבל הוא היה בסיסי מדי ולא היו בו מספיק כלים כדי שאני ארגיש איתו בנוח.
ניסתי את KNOPPIX, שבהחלט היה עשיר מספיק, ונראה מתאים מאוד.
לKNOPPIX יש הוראות מפורטות להכנה של דיסק מותאם על בסיס הקיים (Remastering).
בגדול, התהליך הוא כזה:
מתאחלים את הCD, מעתיקים את התוכן שלו לכונן הקשיח, עושים את השינויים הדרושים, יוצרים ISO חדש, וצורבים אותו.
כמובן שזה יותר מורכב מזה, אבל ההוראות די טובות.
אפשר לקצר תהליכים על ידי שימוש במכונה וירטואלית (VMware, QEmu, Xen) שחוסכת איתחולים.
נתקלתי בבעיות מוזרות בבמהלך איתחול מהISO בהתחלה, לא ברור לי מה פתר אותן, אבל אלו השינויים שעשיתי:
1. התחלתי את התהליך כולו מחדש, הפעם על מערכת קבצים מסוג EXT3 (בהתחלה השתמשתי בReiserFS).
2. נתתי למכונה הווירטואלית ששימשה ליצירת הISO יותר זכרון.

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

תכנות ממוקד משימות – Mylar

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

כששוטטתי בבאגים של Eclipse בזמן שחיפשתי מידע על משהו, נתקלתי בAttachment של קובץ מוזר שסיקרן אותי:
mylar/context/zip.
לא נתקלתי בזה בעבר, ולא ראיתי שום קשר בינו לבין הבאג.
חיפוש קצר בגוגל הביא אותי לדף הזה, שמכיל מאמר על "תכנות מונחה משימות עם מיילר".
חפרתי עוד קצת, ומצאתי גם את המצגת ווידאו הזו, שמתארת איך משתמשים במיילר ומה הוא עושה (40 דקות).
מסתבר שמיילר הוא פרוייקט Eclipse חדש, אחד מני רבים (Eclipse הפכה לחממה של עשרות טכנולוגיות חדשניות), שמתיימר לפתור את הבעיה של עומס מידע בזמן שעובדים עם Eclipse.
mylar screenshot
באופן הבסיסי ביותר, Mylar הוא רשימת משימות, למשימות מקומיות וכן למשימות/באגים ממערכות באגים כמו bugzilla, trac וJira
מה שיפה זה שמיילר מנהל הקשר (Context) לכל משימה בצורה אוטומטית, שמכיל את כל מה שקשור אל המשימה – איזה קבצים פתחת, איזה אלמנטים בתוך הקבצים מעניינים (במקרה של קוד ג'אווה – איזה פונקציות למשל) וכו'.
ברגע שעוברים לעבוד על משימה, מתחילים מיד מההקשר הקודם של המשימה (ריק בהתחלה), ואחרי שעוברים למשימה אחרת, ההקשר נשמר – מוכן להשלף אוטומטית ברגע שחוזרים לעבוד על אותה משימה.
דמיינו את הסיטואציה הבאה:
אתם עובדים על איזה באג/פיצ'ר לתומכם, ופתאום יש מקרה חירום וצריך לתקן באג חדש ולייצר גרסא חדשה של הdemo מאתמול.
לפני מיילר, מה שזה אומר זה שצריך להתחיל להזכר מה צריך כדי ליצר גרסא חדשה, לפתוח קבצים חדשים, כנראה גם לסגור את כל מה שקשור לבאג שעבדתם עליו.
עכשיו, נניח שהבאג הזה בכלל שייך למישהו אחר בצוות, אז צריך להעביר את העסק עליו ואז להזכר מחדש איפה הייתם ומה עשיתם, לסגור את הקבצים שקשורים לבאג בdemo, לפתוח את הקבצים של הבאג שעבדתם עליו ולהמשיך לעבוד.
כל הסחות הדעת האלו יגרמו לכך שגם תבלו איזה עשר דקות בynet בין המשימות, סתם כדי לנקות את הראש.
עם מיילר, אפשר לעבור בקלות בין ההקשרים, בלי לבזבז זמן ותאי זכרון יקרים.
מיילר מייעל גם עבודה בצוותים: את ההקשרים האלו, שכוללים בעצם ריכוז של ידע על אותו באג, אפשר לצרף לבאג עצמו, ככה שהמפתח הבא יוכל פשוט למשוך את ההקשר מהבאג ולהמשיך מאותו מקום שאתם עצרתם. (כל הקבצים פתוחים, כל הפונציות שרלוונטיות לדעתכם כבר יהיו בהקשר, וכו').
Eclipse הוא כבר מזמן לא כלי לפיתוח Java בלבד, כבר היום הוא תומך בC/C++, PHP, Prolog ועוד, מיילר אמור לתת ערך מוסף לתכנות בלי קשר לשפה, כל עוד אתם עובדים בתוך Eclipse – אם כי אני לא בטוח שהוא באמת מוכן לשפות אחרות עדיין.
יתרון נוסף הוא התמיכה האוטומטית בקבוצות שינויים (Changeset) כשעובדים מול מערכת ניהול גרסאות הקוד (CVS/SVN וכו').
מה שזה אומר זה שמיילר ינהל בצורה אוטומטית את הChangeset שקשור לבאג שאתם עובדים עליו, ואפילו יכלול הודעת Commit אוטומטית כשתעשו Commit!

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

יש לינקים עם עוד מידע פה.

קופסות על קופסאות

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

ג'אווה 6

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

Initial Expert Group Membership:
* Google
* HP
* IBM
* Intel
* Doug Lea

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

סודוקו

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