EBuild

הפוסט הזה מיועד למתכנתי ג'אווה שעובדים עם Eclipse.

אז אתם מתחילים פרוייקט, מפתחים, משתמשים בכל מני JARים מפרוייקטים אחרים בתוך הסביבת עבודה, מוסיפים פרוייקטים אחרים לרשימת התלויות של הפרוייקט שלכם, והכל עובד בתוך Eclipse.
ואז אתם צריכים לשחרר JAR שירוץ מחוץ לסביבת הפיתוח שלכם.
פה יש כמה אפשרויות:
1. להשתמש באופצית הExport JAR של Eclipse.
2. ליצור build.xml לפרוייקט

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

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

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

המפתח העצלן כבר מזמן שאל את עצמו: "מה, אין דרך אחרת?"
הרי לרוב הפרוייקטים, Eclipse מכיל את כל המידע שצריך בשביל לבנות אותם.
מעבר לזה, המידע הזה תמיד נכון בהגדרה כי אחרת לא תוכלו לפתח כלום וזה יהיה הדבר הראשון שתתקנו ברגע שתעשו איזה שינוי.
Eclipse שומר את רוב המידע בתוך קבצי ה.claspath בתוך כל פרוייקט (וגם קצת בתוך קבצי ה.project). הקבצים האלו הם קבצי XML פשוטים למדי, שלא השתנו משמעותית מאז ימי Eclipse הראשונים.
אז הנה רעיון:
מה אם במקום לשכפל את המידע גם בEclipse וגם בbuild.xml, ניצור build.xml אחד שקורא את המידע על הפרוייקטים מEclipse, מבין מה סדר הבניה הנכון של הפרוייקטים, איזה JARים צריך לכל פרוייקט ובונה את העסק לפי זה?
אותו build.xml קסום ומופלא יעבוד כמעט לכל פרוייקט Java שפותח בתוך Eclipse בצורה שקופה, בלי שום התעסקות ותחזוקה של קובץ build.xml ספציפי לפרוייקט.
נשמע טוב מכדי להיות אמיתי?
ובכן, שחררתי מערכת כזו בדיוק, ולמערכת קוראים ebuild.
התחלתי לפתח אותה לפני שנים, והיא ליוותה אותי דרך ארבע מקומות עבודה עד עכשיו (למעשה דרך כל מקומות העבודה שהיו לי בתחום ההיטק).
המערכת משוחררת תחת רשיון FreeBSD (רשיון תעשו מה שבזין שלכם, לא מזיז לי) ודף הבית שלה הוא http://ebuild.firefang.net.
בגדול, כדי להשתמש בה, מה שצריך לעשות זה:

  • לקחת את הקוד שלה ולהכניס לפרוייקט נפרד בסביבת העבודה.
  • להעתיק את example-common.properties לcommon.properties (הוא מכיל הגדרות ספציפיות למחשב שלכם, למרות שכרגע אין מה להתעסק איתו ברוב המקרים).
  • ליצור קובץ build.properties בתוך הפרוייקט שאתם בונים (מאוד פשוט ומינימלי)
  • להריץ עם ant -Dproject=YOUR_PROJECT, כאשר YOUR_PROJECT הוא השם שם הפרוייקט שלכם בסביבת העבודה.
  • לקחת את התוצרים האיכותיים מספרית הbuild שנוצרה תחת הפרויקט.

התוצר יהיה JAR שניתן להריץ בעזרת java -jar file.jar, וכן זיפ שכולל את הJAR ואת הספריות הדרושות כדי להפיץ את התוכנית.

נכון לכרגע, המערכת די בסיסית ומסוגלת לבנות פרוייקטי Eclipse בתוך סביבת העבודה (Workspace) שלכם.
בהמשך אני מתכנן להוסיף אפשרות לתייג פרוייקטם ולבנות ישר מCVS/SVN בלי לגעת בקוד בסביבת העבודה (זה דרוש כדי לשחרר גרסאות בצורה מסודרת).
בנוסף, אני מתכנן להוסיף אפשרות לebuild-hook.xml אופציונלי שיהיה ספציפי לפרוייקט שיכיל כל מני דברים שבאמת ספציפיים לפרוייקט מסויים.

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

  • ebuild תומך בזה בצורה טובה, אבל לא ברור לי אם הוא יתמודד עם JARים חיצוניים.
  • ebuild לא תומך בכל מני הרחבות מוזרות של eclipse, שמסתמכות על מידע שלא מופיע בקבצי ה.classpath. למשל 'user libraries'. אם אתם רוצים שהוא יעבוד בשבילכם, תעבדו פשוט.

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

Facebook Comments

Doctor horrible

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

horrible.jpg

Facebook Comments

חור אבטחה בסקריפט דוגמא שPaypal מספקים

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

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

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

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

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

[code lang="php"]
$struery = "insert into paypal_cart_info(txnid,itemnumber,itemname,os0,on0,os1,on1,quantity,invoice,custom)
values ('".$txn_id."','".$_POST[$itemnumber]."','".$_POST[$itemname]."','".$_POST[$on0]. "','".$_POST[$os0]."','".$_POST[$on1]."','".$_POST[$os1]."','".$_POST[$quantity]."','".$invoice."','".$custom."')";
$result = mysql_query($struery) or paypal_die("Cart – paypal_cart_info, Query failed:
" . mysql_error() . "
" . mysql_errno());
[/code]

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

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

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

Facebook Comments

FireStats 1.5

בשעה טובה, פיירסטטס 1.5 הגיע לגרסא יציבה עם השחרור של 1.5.11-stable.
שדרגו בהמוניכם 🙂

Facebook Comments

אחרי המצור

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

אפשר להוריד גם מפה.

Facebook Comments

MySQL optimization

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

כדי לבטל את אותו Cache, אפשר להשתמש בפקודת הMySQL:
[code lang="sql"]
SET GLOBAL query_cache_size = 0;
[/code]

FireStats תומך בגרסאות MySQL ממשפחת 4.0, 4.1 ו5.0, כאשר ההבדל בין 4.0 ל4.1 כל כך משמעותי שיש שאילתות בFireStats שכתובות אחרת לכל אחת מהגרסאות.
נסיון לשיפור ביצועים, במיוחד כזה שמבוסס על שינויים בסכמת הנתונים יצריך שינויים בקוד שמטפל ב4.0 ובקוד של 4.1, לכן כדאי לבדוק שהכל עובד על השרת הרלוונטי. בנוסף, מכיוון שרוב (60%) משתמשי FireStats עובדים עם MySQL 5.X, כדי גם לבדוק את השיפור על השרת הזה.
כדי לבצע את זה, הרמתי שלושה שרתי MySQL, נציג אחד מכל משפחת גרסאות, והכנסתי לכל שרת חבילת נתונים די כבדה (וזהה בין השרתים) שמבוססים על סטטיסטיקות מהשרת שלי.
ובכל אחד מהשרתים ביטלתי את מטמון השאילתות (query_cache_size).
יצרתי טבלא בגנומטיק (כמו אקסל), שנראית ככה (תת טבלא כזו לכל בדיקה שאני רוצה)
fs-opt.jpg

נניח שהפונקציה שאני רוצה לשפר היא:
[code lang="php"]
function foo()
{
$sql = "SELECT * from …";
return query($sql);
}
[/code]

קודם כל הכפלתי את הקוד והוספתי הדפסה של שאילת הSQL שנשלחת לשרת:
[code lang="php"]
function foo()
{
if (true) // old code
{
$sql = "SELECT * from …";
echo $sql; return;
return query($sql);
}else{
$sql = "SELECT * from …";
echo $sql; return;
return query($sql);
}
}
[/code]
מכאן זו היתה שיטת העבודה:
1. הרצה של הקוד במצב הישן.
2. העתקה של השאילתה שהודפסה, והרצה שלה ישירות על כל אחד משלושת בסיסי הנהנתונים. ושמירה של הזמן שנדרש בטבלא מסודרת.
3. מעבר למצב חדש (פשוט לשנות את הfalse לtrue בראש הפונקציה), אופטימיזציה של השאילתה וחזרה על הבדיקה מול כל אחד מהשרתים, ושוב שמירה של התוצאות בטבלא, הפעם בעמודה של תוצאות אחרי אופטימיזציה.

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

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

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

ככה נראית הטבלא שלי אחרי שמילאתי אותה:

Query name MySQL Version 4.0.17 4.1 5.0.51
Num page views for all hits in site=1 Original query time sec 1.20 0.93 0.84
Optimized query time sec 0.10 0.06 0.06
Improvement % 91.67% 93.55% 92.86%
Num page views for all hits in all sites Original query time sec 1.17 0.91 0.84
Optimized query time sec 0.11 0.08 0.08
Improvement % 90.60% 91.21% 90.48%
Num page views for for last last 14 days for all sites Original query time sec 0.19 0.16 0.16
Optimized query time sec 0.12 0.09 0.11
Improvement % 36.84% 43.75% 31.25%
Num all unique visitors for site_id = 1 Original query time sec 2.93 1.24 1.13
Optimized query time sec 1.75 0.68 0.72
Improvement % 40.27% 45.16% 36.28%
Num all unique visitors for all sites Original query time sec 2.09 1.24 1.15
Optimized query time sec 1.26 0.47 0.47
Improvement % 39.71% 62.10% 59.13%
Num unique visitors for last 14 days for all sites Original query time sec 0.32 0.18 0.18
Optimized query time sec 0.28 0.16 0.15
Improvement % 12.50% 11.11% 16.67%
Recent referrers for all sites Original query time sec 2.54 3.01 3.01
Optimized query time sec 2.30 1.54 1.78
Improvement % 9.45% 48.84% 40.86%
Recent referrers for site_id = 1 Original query time sec 2.48 2.71 2.76
Optimized query time sec 2.65 1.65 1.90
Improvement % −6.85% 39.11% 31.16%
Search terms for site_id = 1 Original query time sec 1.67 2.14 2.75
Optimized query time sec 1.67 0.84 0.91
Improvement % Not optimized 60.75% 66.91%
Popular pages (all) Original query time sec 1.88 4.67 4.80
Optimized query time sec 1.73 1.96
Improvement % Not optimized 62.96% 59.17%
Popular pages (site_id = 1) Original query time sec 1.93 4.07 4.09
Optimized query time sec 1.88 2.11
Improvement % Not optimized 53.81% 48.41%
get questagents (180 days, site_id = 1) Original query time sec 6.89 2.90 2.35
Optimized query time sec 5.07 1.00 1.10
Improvement % 26.42% 65.52% 53.19%
Countries (20 countries, 180 days, site_id = 1) Original query time sec 1.95 1.08 1.08
Optimized query time sec 0.30 0.20 0.23
Improvement % 84.62% 81.48% 78.70%
Hits table (100) Original query time sec 0.30 0.61 0.42
Optimized query time sec
Improvement % Not optimized Not optimized Not optimized
Facebook Comments

תאריך? מי צריך את זה בארץ?

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

שלום.
נראה לי שמישהו אצלכם שותה יותר מדי.
אין תאריך פרסום בכתבות, למשל:
http://www.haaretz.co.il/hasite/pages/ShArtPE.jhtml?itemNo=975758&contrassID=2&subContrassID=17&sbSubContrassID=0

וקיבלתי את התשובה המשעשעת אם כי לא מועילה הזו:

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

תגובתי היתה:

תודה לירון.
ובנימה יותר רצינית:
אתה לא חושב שזה גורע מהמידע בידיעות?

ולזה כבר לא קיבלתי תשובה.

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

Facebook Comments