טכנולוגיה לארגונים

הבלוג של מומחי הטכנולוגיה של HP ישראל

חיפוש
רונן נרקיס

בן 30 מפתח תוכנה (ב Java) מזה 4 שנים, בשנה האחרונה ב- HP software כמפתח Java ב Release Control, בין יתר הנושאים שאני עוסק בהם נכללים: Service Desk integrations, Testing frameworks, Server side services, בבלוג זה אנסה לכסות ת המגמות החדשות והמעניינות בתחום: * שפות תוכנה ופרדיגמות אלטרנטיביות. * תכנות בעידן מרובה הליבות. * אלגוריתמים ו AI (כיצד ניתן לפתור בעיות בדרכים לא שגרתיות). * תוכנה בסביבת ה enterprise.

עדכונים ב-RSS לפוסטים של רונן נרקיס


המהפכה השקטה

פורסם ביום חמישי / 5.11.09


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

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

אוקיי נשמע פשוט למדי לא? אז זהו שלא כל כך, הפרדיגמה הנפוצה כיום בשפות כמו Java ו C# לכתיבת קוד מקבילי הינה shared state with locks, כלומר ישנו איזור משותף בזיכרון אליו ניגשים מספר Thread-ים, האמצעי לסנכרון גישה זו הינו באמצעות מנעולים שעל כל Thread לרכוש טרם הוא ניגש למקטע זה, גישה זו יוצרת מספר בעיות:

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

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

אז מה הן האלטרנטיבות בעצם?

אז בואו נחזור אחורה בזמן ל 1936, שנה בה Alonzo Church פיתח מערכת חישובית בשם Lambda calculus השקולה בכוחה ל Turing machine, מערכת זו היוותה את הבסיס למשפחה עשירה של שפות תוכנה בפרדיגמה פונציונאלית (functional programming languages).

איך זה מתקשר לנושא?

ובכן אם נחשוב לרגע על פונקציה f(x) = y פונקציה זו תחזיר את אותה תוצאה ולא משנה כמה פעמים נפעיל אותה, היא אינה תלויית זמן או מקום, תוצאתה מובטחת לנו תמיד, כך שלא משנה כמה Thread – ים יפעילו אותה תמיד נקבל תוצאה תקינה, אותן שפות פונקציונאליות (כמו Lisp למשל) מאפשרות יצירת תוכניות שלמות המורכבות כולן מפונקציות, תוכניות כאלו הינן "טהורות" במובן הזה שהן נטולות side effects (אין שום פרמטר חיצוני המשפיע על ביצוען), מובטחת לנו אותה תוצאה תמיד עבור אותם ערכים.

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

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

גישה זו אפשרית גם בניהול גישה למקטעי זיכרון משותפים בתוך process, היא זוכה לשם Software transactional memory או בקיצור STM הרעיון הבסיסי דומה לתהליך שהזכרתי קודם, במקרה בו מספר Thread – ים ניגשים למקטע זיכרון עליהם לבצע זו במסגרת transaction, במידה ומאותרת אי עקביות (למשל תהליך אחד כותב ושני קורא את אותו מקטע) אזי אחד מהם מגולגל ומתחיל מבראשית, קיימים מספר מימושים מעניינים לגישה זו מעל ה JVM כאשר אחד הבולטים הינו בשפה Clojure עליה אני מתעתד לכתוב בעתיד.

הגישה האחרונה שאעסוק בה הפעם  Data flow programming נוטלת את ההשראה שלה מפסי יצור, דמיינו לרגע פס כזה המורכב משרשרת ארוכה של נקודות בכל נקודה קיים פועל (או מכונה) המקבל תוצרים מנקודות קודמות ומפיק תוצרים עבור המשך התהליך, מערכת כזו הינה מקבילית לגמרי (אין state משותף בין 2 רכיבים), דמיינו עשרות או מאות Thread-ים כל אחד מהם צורך מידע ומפיק מידע באופן בלתי תלוי בעמיתיו וקיבלתם מערכת שלא סובלת מאותן בעיות ש shread state גורם.

לסיכום, מהפכת ה multi concurrency תשנה את האופן שבו אנו מפתחים וצורכים אפליקציות, הולך להיות מעניין!

מתחילים לתפוס את הגרוב

פורסם ביום שני / 3.08.09


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

רוב המפתחים על ה JVM מרגישים בבית כשהם כותבים ב Java, לא היה נחמד אם היתה שפה שמשמרת את ה syntax הקיים ועדיין משפרת את הנקודות הפחות נעימות שלמדנו לחיות איתן?

לנישה הזו נכנסת Groovy אשר הינה שפה דינאמית (בעלת static typing אופציונלי), התחביר עצמו מהווה super set ביחס לתחביר ה Java-י (כמעט כל קוד ב Java הוא קוד תקין ב Groovy), השפה שואבת השראה מ Ruby, SmallTalk, Lisp, Objective C ושפות נוספות.

הפיתוח שלה החל ב 2003 כאשר החברה המרכזית שפיתחה אותה G2ONE נרכשה לא ממזמן על ידי Spring source.

השפה עצמה כוללת בין היתר:

  • Closures, פונקציות כאזרחיות מדרגה ראשונה בשפה (ניתן להעביר אותם כפרמטרים והן משמרות lexical scope).
  • Map, List, Array Literals אין צורך לכתוב 10 שורות על מנת לאתחל מבנה נתונים.
  • GDK, העשרת ה JDK במתודות עזר נוספות (למשל File.eachLine מאפשרת בשורה אחת לסרוק קובץ).
  • MOP,  ניתן לשלוט על גישה לתכונות והפעלת מתודות על אובייקטים בצורה כללית זאת באמצעות API המובנה בשפה (MetaObjectProtocol).
  • AST Trasnformations, תשתית המאפשרת מניפולציות על ה AST בזמן קומפילציה, כמו למשל להגדיר Singleton באמצעות annotation.

בכלל מה ש Groovy מצטיינת בו ביחס ל Java היא בכמות הקוד הפחותה (לא במחיר קריאות!), למשל הטיפול בניהול משאבים הופך להיות קל בזכות ה Closure-ים שכן ניתן להעביר התנהגות למתודה ולתת לה לנהל את סגירת הקובץ \ חיבור, אין צורך גם לנהל ערימות של Try Catch שכן השפה לא אוכפת Checked exceptions.

אבל לא פה נגמר הסיפור, Groovy כיום היא eco-system מכובד בפני עצמו הכולל את:

  • Grails, תשתית פיתוח Web-ית היורשת הרבה מ Ruby On Rails תוך כדי שהיא מאמצת בסיס Java-י הכולל את Spring ו Hibernate.
  • Grifon, הנוקטת גישה דומה ל Grails אולם הפעם עבור אפליקציות Swing.
  • Gradle, תשתית build אלטרנטיבית ל Maven.

בנוסף היא מכילה "מיני" תשתיות, idiom-מות כגון:

Builder-ים, הודות לקיומם של Closure-ים ה Design pattern הוותיק מקבל משמעות חדשה לגמרי, למשל Swing Builder המאפשר להגדיר (הצהרתית כמעט) כיצד נבנית יחידת UI ב Swing, או Http builder המאפשר ליצור Http request, ה idiom-מה הזו חוזרת על עצמה מספר רב של פעמים ומאוד קל לבנות באמצעותה אובייקטים מסובכים, למעשה ניתן ליצור Custom builders בעצמנו באמצעות FactoryBuilderSupport.

פיתוח אינראקטיבי, groovyConsole המסופק עם השפה הינו בעצם REPL שבעזרתו אנחנו יכולים לבחון רעיונות במהירות תוך כדי שאנחנו כותבים את הקוד (המקור לרעיון הוא Lisp), אחד השימושים הנפוצים שאני עושה הוא לנהל שאילתות מול RDBMS-ים, לא פעם ניסוח שאילתות הוא תהליך מייגע שמאלץ אותנו לשלוף כל טריק SQL-י אפשרי מהזיכרון, לא היה נחמד אם היינו יכולים לבצע פעולות שהן טריוויאליות ב Java בקלות? , הסרטון הבא מדגים עד כמה קל להדפיס תת מחרוזת מ Clob בתוצאות שאילתה:

יצירת DSL-ים, יכולות ה MOP בשילוב ה Closure-ים ו operator overloading מקלים על יצירת שפות המכוונות ל Domain מסויים תוך שימוש ב Groovy בלבד, ניתן למשל ליצור מיני שפה לחישוב אורכים, משקלים וכדומה.

לסיכום ה sweet spots שאני מוצא שניתן לשלב בהן Groovy בהצלחה כוללות:

  • Glue code & Configuration, קוד המחבר בין מערכות\אפליקציות שונות ואוטומציה, data transfomation (ביחוד XML).
  • Swing UI, תשתיות כמו Griffon מדגימות כמה רחוק ניתן להגיע עם builder-ים ויכולות ה binding מובנות (עוד דוגמא ל AST trasnformation).
  • Build, האינטגרציה עם Ant ו Maven והפונקציונאליות שה GDK מוסיף לעבודה עם קבצים מקלים מאוד על משימות מסוג זה.
  • Fast prototying, השימוש ב REPL והירידה בכמות הקוד מקלים על יצירת קוד במהירות.

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

Java השפה שהפכה לפלטפורמה

פורסם ביום רביעי / 15.07.09


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

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

עם החדירה של מספר רב של שפות קם וצץ לו מושג חדש בשם Polyglot programming, לו אני מוצא 2 ביאורים אפשריים:

  • הראשון הוא שכל מפתח לומד מספר גדול של שפות (קצת בדומה לשפות טבעיות) וכך בעצם לומד פרדיגמות שונות והופך למפתח טוב יותר (Learn a new language every year).
  • השני והמעניין יותר הינו זווית ראייה שונה למהות השפה והתפקיד שלה, לרוב בכל פרוייקט נבחרה שפה יחידה בה כל הקוד נכתב, בגישה האלטרנטיבית שפת תוכנה היא עוד כלי בארגז הכלים שלנו (בדומה ל IDE ולכלי ה Build בהם אנו עושים שימוש) אנו יכולים לבחור את השפה המתאימה למשימה המתאימה, כך שלמעשה בפרוייקט אחד עשויים לדור מספר שפות בכפיפה אחת.

אבל בואו נתמקד בנושא שלשמו התכנסנו, ה- JVM עד לא מזמן נתפס (בעיקר) ככלי להרצת byte code שמקורו בקוד Java-י בלבד (נכון ששפות נוספות היו קיימות זה מזמן אך הן לא היו פופלאריות כמו Java), מסתבר שהוא אוצר מספר יכולות מרשימות שהופכות אותו בעצם לפלטפורמה יעילה מאוד לשפות נוספות:

  • מהירות, ה- JVM מנטר את הקוד בשעת ריצה ומבצע מספר גדול של אופטימזציות.
  • פורטביליות, כבר מראשיתו ה JVM רץ על מספר עצום של פלטפורמות ממערכות משובצות ועד למחשבי על.
  • בשלות, קיימים מספר עצום של ספריות שרתים וכלים שכל שפה הפועלת מעל ל JVM יכולה לנצל.
  • ישימות, Java היא שפת בסיס נוחה למימוש שפות (GC), "קל" ליצר byte code (למשל בעזרת ASM).

כיום קיימות לפחות כ 240 שפות שונות הפועלות מעל ל- JVM, המספר (המדהים) מוליך בעצם לשאלה כיצד לבחור שפה מתוך בליל האפשרויות?

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

  • קהילה, רצוי שלשפה תהיה קהילה נעימה ומזמינת פנים ל n00b-ים שכן לא פעם אנו לומדים שפה כזו בשעת הפנאי וחשוב שנהנה תוך כדי התהליך.
  • תיעוד, אתר מרכזי ותיעוד הם הכרח ולא מותרות, נכון שלחיות על הקצה דורש לא פעם נבירה ב- source code ובשיטוט אחר דוגמאות, עדיין הבסיס צריך להיות נגיש.
  • Java interop, אנחנו חיים על ה JVM ורוצים לנצל זאת, שפה שלא מאפשרת זו אינה אופציה.
  • כלים, לא פעם מדובר בשפות שמגוון הכלים התומכים מצומצם עדיין ישנם כלים בסיסיים שאי אפשר לוותר עליהם (בראש ובראשונה Testing framework).
  • נקודת מוצא, לכל שפה יש מטרה והנחות מוצא שונות, רצוי שנבחר שפה העונה למגוון רחב של בעיות בהן אנו נתקלים ומעוניינים לפתור.

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

רונן