ארכיון יומי: 16 מאי, 2015

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

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

למשל הרבה שנים דיברתי כאן על שפת פסקל ועד כמה היא שפה מדהימה. בייחוד אם לוקחים את ++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. הספרייה היא של ג'אווה, הסביבה היא של ג'אווה, אבל הקוד ברובי ממוקד יותר מטרה, בעוד שג'אווה דורשת ממני הרבה עודפים שבלעדיהם אני לא מסוגל להגיע למטרה.

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