Archive for the ‘תכנות’ Category

HipHop לPHP, המחשבות שלי בנושא

צריך היה להיות ממתכנת מנותק מאוד בשביל לא לקרוא על הHipHop, כלי ששיחררה Facebook שלוקח קוד PHP בגירסה 5.2 פחות כמה פיצ'רים, וממיר אותו לקוד C++ שאפשר לקמפל באמצעות g++ לקוד מכונה שרץ באופן טבעי על השרת. Facebook טוענים שHipHop מסוגל להביא לביצועים טובים בכ50%, שהוא כשלעצמו מספר מרשים מאוד מחד, ומפתה מאוד בחשיבה על צריכת הCPU שיורדת משמעותית מאידך.

מה זה למעשה?

  • HipHop ממיר קוד PHP לקוד C++ שיכול להתקמפל לקוד מכונה טבעי. HipHop תומך ברוב מוחץ של האפשרויות בPHP 5.2 מלבד פונקציות כמו eval() למשל.
  • הכלי מתיימר ליצור את קוד הC++ היעיל ביותר האפשרי, הוא יבדוק מגמות כלליות ודברים שעשיתם בקוד הPHP שלכם ולפיו יכין את קוד הC++ המותאם ביותר.
  • לאחר שקומפל, HipHop מהווה בעצמו את שרת הרשת. הוא איננו צריך תוכנות שרת כמו Apache ואחרות.
  • כרגע, HipHop לא תומך בכלל בווינדוס. מפתחי PHP, אם עוד לא עברתם, זה הזמן לנסות את לינוקס.
  • כרגע אתר Facebook כולו משתמש בכלי הזה לייעול הקוד ולהתמודדות עם עומס המשתמשים.

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

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

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

עוד מילה על CppCMS

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

מבני נתונים בתכנות – חלק א', מערך ורשימה מקושרת

הקדמה

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

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

מערך -Array

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

אז מהוא למעשה מערך? ברשותכם אשתמש בתמונה להמחשה הלקוחה מהmanual הרשמי לJAVA:

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

מיון מערך

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

מחיקת ערכים וחיפוש

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

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

מערכים רב ממדיים

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

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

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

רשימה מקושרת -Linked List

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

פה אני אסקור את מבנה הנתונים שפותר כמה מהבעיות האלו, הרשימה המקושרת, Linked List. הרשימה המקושרת היא ככל הנראה מבנה הנתונים השני בשכיחותו אחרי המערך. הרשימה המקושרת היא מבנה נתונים מבוסס מצביעים, או כפי שבשפות ללא מצביעים (C# או JAVA למשל) אוהבים לקרוא לזה, הפניות. כל עצם ברשימה כולל שני נתונים, את הinfo, כלומר המידע שיש לאותו איבר, שיכול להיות מכל סוג, מספר שלם, מחרוזת או עצם שיצרתם בעצמכם, והנתון השני הוא המצביע או ההפניה לבאיבר הבא בתור. כל איבר כזה ברשימה מכונה בדר"כ Node, כאשר למעשה הרשימה עצמה מהווה בסה"כ מצביע לNode הראשון ברשימה, ומשם זה כבר ממשיך לבד. הרשימה מסתיימת בכך שההפניה לאיבר הבא בעצם האחרון בעצם מפנה לnull. התרשים הבא מסביר את הכוונה היטב:

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

סוגי רשימות נוספים

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

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

הוספה והסרה של איברים ברשימה

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

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

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

מיון וחיפוש

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

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

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

לסיכום יתרונות וחסרונות רשימה מקושרת

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

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

סוף חלק א'

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

אני לא רוצה לעבוד עם אנשים שלא מתכנתים לכיף

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

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

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

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

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

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

איך לטפל במצב של memory underrun בC++

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

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

אני חושב שהקוד ידבר בעד עצמו:

    void main( )
    {
    void outofMemory( );
    set_new_handler(outofMemory);

    char *pointer = new char[..Huge value here..];
    }
    void outofMemory( )
    {
    cout<<"System ran out of memory";
    exit(1);
    }d

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

איזה פריימוורק לPHP הייתם בוחרים לפרויקט הבא שלכם?

מה שהחל בStackoverflow.com כשאלה רגילה על פריימוורקים שונים לPHP התפתח לדיון פורה על ההבדלים, היתרונות והפיצ'רים השונים שבפריימוורקים Zend Framework, Code Igniter, CakePHP וכו'.

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

תרומות קוד? לא בדיוק. 75% מלינוקס נכתב ע"י מפתחים בתשלום

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

במהלך ההרצאה שלו בLinux.conf.au הציג ג'ונתן קורבט, הבעלים של LWN.net את הנתונים המפתיעים משהוא האלו ואת הניתוח שלו לקוד הלינוקס.לפי קורבט 18% מהקוד נכתבו על ידי מפתחים שלא השתייכו לשום תאגיד ולא דרשו תשלום, כלומר מתנדבים טהורים, עוד 7% מהקוד נתרמו ע"י כותבים שלא הוגדרו, כלומר אין לדעת אם מדובר במתנדבים או מפתחים בתשלום, אך 75% מהקוד נתרם ע"י אנשים ששולם להם בכדי לכתוב את הקוד הזה.

בתוך תחום הקוד שנכתב בתשלום נמצאות רד-האט שבראש הטבלה עם 12% מהקוד, כשאחריה אינטל עם 8%, מיד אחר כך IBM ונובל כשכל אחת עם 6% ואוראקל עם 3%. אף על פי שהחברות הן מתחרות ויריבות מטבען, הפיתוח המרכזי של הקרנל מתנהל מצוין לפי קורבט.

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

למה אתם צריכים לפתח עם OpenGL ולא עם DirectX

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

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

מהאודות של OpenGL באתר הרשמי כתוב כך: "..מאז נוסדה ב1992 הפכה OpenGL לפלטפורמת פיתוח הגרפיקה ב2D וב3D הנפוצה בעולם, כשהיא תומכת במגוון רחב של פלטפרמות (מערכות הפעלה)…". על פי ויקיפדיה לOpenGL שתי מטרות עיקריות, האחת היא לחסוך מהמשתמש את הכתיבה הכל כך קשה של קוד למנועי 3D שונים על ידי הצגת API יחיד שתואם לכולם, המטרה השניה היא לחסוך מהמפתח את כאב הראש שבהתחשבות ביכולות שונות של חומרות שונות על ידי תמיכה אחידה של החומרות בממשק הOpenGL. כיום, OpenGL מנוהל על ידי Khorons Group, מלכ"ר שעושה את עבודתו נאמנה. חשוב לציין, OpenGL תומכת בכל פלטפורמת משחקים קיימים, החל בווינדוס, מק, לינוקס, BSD, וגם בWII ובPLAYSTATION, באייפון ובמכשירי האנדרואיד והMaemo וכו' וכו'.. ובכן, היא תומכת כמעט בכל הפלטפורמות הקיימות, מלבד XBox שהסיבה לכך לדעתי ברורה, וזה מוביל לנושא הDirectX:

כבר מאז ימי הMS-DOS הותיקים הבינה מיקרוסופט שמשחקים על מחשב הוא אחד הדברים היותר חשובים למשתמשי המיינסטרים, לפיכך ב1995, עם יציאת מערכת ההפעלה הראשונה שלהם ב32BIT, הווינדוס 95, הם יצרו מערך ספריות שסייע ודירבן מפתחים לכתוב משחקים במיוחד למערכת הווינדוס 95 שלהם. הספריות הללו כללו את Direct3D, DirectInput וDirectSound, כאשר כל החבילה כאחד נקראה DirectX. כאשר מיקרוסופט נכנסה בכוחות עצמה לשוק הקונסולות היא קראה לקונסולה שלה DirectX BOX או בקיצור XBox.

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

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

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

אז… למה OpenGL עדיף?

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

OpenGL חזקה יותר

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

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

OpenGL חוצה פלטפורמותחוצה פלטפורמות

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

OpenGL היא טכנולוגיה שעדיף להשען עליה, היא טובה לעתיד

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

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

לסיכום…

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

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

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

הערות:

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

Rails 3 בטא ראשונה בפברואר

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

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

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

הרצאה בGoogle Tech Talk על Cmake

ביל הופמן הרצה בGoogle Tech Talk בניו יורק על כלי הקוד הפתוח CMake/CPack/CTest/CDash ועל שימושים בבדיקה ובפיתוח תוכנות C++.

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