לעיתים קרובות אנחנו כמנהלי מוצר נדרשים לאפיין API. בפוסט הזה יש לי שתי מטרות, הראשונה היא לתת איזה מבוא בסיסי על מנת להסביר מה זה API ואיך מאפיינים אחד למי שלא מכיר והשניה היא לאפשר לכולנו להימנע מכל הטעויות הנפוצות שאני רואה שוב ושוב באפיון ממשקים.
שימו לב שלעיתים קרובות לאפיון ממשקים יש הרבה חלקים מאוד טכניים שצוות הפיתוח מוסיף ועוסקים באספקטים הטכנולוגיים של צריכת ה-API, בפוסט הזה אני מצמצם את הפירוט הטכני כי קהל היעד שלי הוא מנהלי מוצר ובעיקר כאלו עם מעט ידע טכני.
מבוא: מה זה API?
בפשטות, API (או Application Programming Interface) זה ממשק בין תוכנות. המטרה של API זה לאפשר תקשורת בין מערכת או תוכנה אחת לתוכנה שנייה בצורה מוגדרת מראש ומבלי שנצטרך להבין כיצד התוכנה השניה עובדת. הדימוי טוב יהיה שליחת בקשות בדואר לרשות ממשלתית. כןכן, דמיינו לכם שאנחנו בשנות ה2000 לרגע. אם אני רוצה שמשרד הפנים ישנה את הכתובת שלי אז אני צריך להדפיס טופס שינוי כתובת, למלא אותו ולשלוח אותו למשרד הפנים. אחרי שהמכתב יגיע, משרד הפנים יבצע את השינוי וישלח לי בחזרה מכתב שאומר שהפעולה בוצעה. על מנת שהאינטראקציה הזו תצליח אני צריך שיהיה לי את הטופס (מבנה הבקשה), למלא את המידע הנכון, ולשלוח למקום הנכון. משרד הפנים יקבל את הטופס, יבצע או לא יבצע את הפעולה וישלח לי הודעה רלוונטית.
אם נעביר את הדימוי הזה לעולם התוכנה, אז יכולה להיות לי בטלפון אפליקציה של משרד הפנים שתאפשר לי למלא את הבקשה לשינוי הכתובת. ולאחר מכן האפליקציה תשלח את הבקשה לשרת של משרד הפנים לביצוע. על מנת ששתי התוכנות יוכלו לתקשר בצורה מוצלחת אותם כללים נשמרים: האפליקציה על הפלאפון שלי צריכה לדעת איזה בקשה יחד עם איזה מידע לשלוח ולאיזו שרת במשרד הפנים לשלוח את המידע.
כלומר API הוא סט היכולות שהתוכנה שלנו חושפת למשתמש חיצוני בצורה תכנותית. ולכן שכאשר אנחנו מאפיינים API, אנחנו בעצם רושמים את מגוון הפעולות שהתוכנה שלנו צריכה לתמוך בהם (סוגי הטפסים שהלקוח יכול למלא), מה מבנה הממשק (איזה מידע צריך לרשום בטופס), ומה מבנה התגובה (איזה טופס שולחים חזרה ללקוח).
חשוב לזכור ש-API זה כלי שימושי בכל קישוריות בין רכיבי תוכנה, לפעמים צוות הפיתוח משתמש ב-API בין חלקים שונים של המוצר שלנו כחלק מתהליך הפיתוח. ממשקים כאלו מכונים “API פנימי” והם חלק מתהליך הפיתוח ולא אמור לעניין אותנו כמנהלי מוצר. כפי שלא מעניין אותנו אם רכיב מסוים במוצר מפותח כפונקציה אחת או מחולק לפונקציות רבות. אולם, אם אנחנו בונים API מתוך כוונה שלקוחות חיצוניים לחברה ישתמשו בהם אז הם מכונים “API חיצוני” או “API פתוח” (External API או Open API) וככאלו הם מוצר שאנחנו מציעים ללקוחות. בפוסט הזה אנחנו כמובן מתעסקים ב-API חיצוניים בלבד.
כמובן שיש סוגים שונים של API: ישנם ממשקים שמטרתם לאפשר תקשורת בין תוכנות כפי שהצגנו פה ויש ממשקים שמטרתם לאפשר גישה למסדי נתונים או למנועים שונים. כל אחד מהממשקים הללו יכול להיות ממומש בטכנולוגיה אחרת אבל היות וזה לא משפיע ישירות על האפיון שלנו אז לא ניכנס לנושא הזה.
איך מאפיינים API?
הנה החדשות הטובות: API הוא מוצר כמו כל מוצר אחר. אז האפיון שלו צריך להתנהל כמו האפיון של כל מוצר אחר. כלומר קודם כל להבין את הצרכים של המשתמשים שהולכים להשתמש ב-API שלנו.
בואו נעשה דוגמה קטנה, נניח שאני הבעלים של קולנוע ויש לי מערכת לניהול בית הקולנוע שלי. ופונה אלי חברת שקרכלשהו לממכר כרטיסים, הם רוצים API לאתר למכירת הכרטיסים שלהם. אני חושב שהם יצטרכו שני שירותים שאחשוף להם: איזה סרטים מציגים כעת (get_list_of_presenting_movies) בכדי להציג את הסרטים ואפשרות לסמן כרטיס שתפוס (purchase_ticket) (ברור לכולנו שיש עוד שירותים רבים שהם עלולים לרצות כמו ביטול רכישה, קבלת פרטי אולם, אבל לצורך הדוגמה נניח שהשירותים הללו מספיקים להם) .
חשוב מאוד לזכור שאם במקום אתר למכירת כרטיסים המשתמש ב-API היה מערכת לניהול בית הקולנוע שלי יכול להיות שהמערכת תרצה מידע אחר לגמרי כמו כמה כרטיסים נמכרו היום (ticket_sales_by_day).
רק אחרי שהבנו את הצרכים של המשתמשים, איזה מידע מעניין אותם, ואיזה פעולות הם רוצים לבצע על המידע שלנו אנחנו יכולים להתחיל ליצור רשימה של ממשקים.
מבחינת תהליך העבודה שימו לב שיש חלקים באפיון הממשק שצריכים לעבור דיוק על ידי המפתח לכן אני תמיד ממליץ שלאחר שאנחנו כותבים את הממשק מבחינה עסקית (הבנו מי המשתמשים, מה הפעולות הנדרשות, ומה המידע שצריך לקבל ולתת) לשבת יחד עם המפתח ולעבור על האפיון. השינויים שהמפתח יוסיף לפעמים יהיו בשינוי מונחים מסוימים כדי להשתמש במונחים טכניים נכונים (למשל בממשקים מסוג REST נהוג להשתמש במונח GET לבקשת מידע ולא במונח RECEIVE) או לדייק את הגדרות הנתונים שלנו (למשל אנחנו עלולים לכתוב בסוג המידע Number בעוד שהתוכניתן יעדיף לעדכן ל-Integer שמשמעו מספר שלם).
איך נראה איפיון של API?
אפיון של API מורכב בדרך כלל ממספר חלקים ולא תמיד כולם יהיו נוכחים (למשל בממשק מסוג Webhook שולחים הודעות אבל לא מצפים לקבל תשובה ולכן אין צורך לאפין את התשובה):
- שם הממשק – לרוב תיאור של הפעולה המתבצעת
- תיאור הפנייה לממשק – שתכלול תיאור קצר של מטרת הפניה, תיאור של השדות שאנחנו מצפים לקבל (לרוב בצורת טבלה), ופירוט נוסף שאולי צריך (למשל בדיקות תקינות של הקלט המתקבל)
- תיאור התשובה שנחזיר – לרוב תכלול תיאור טקסט קצר של הפלט שנחזיר, תיאור של מבנה השדות שאנחנו נשיב (שוב, לרוב בצורת טבלה), ופירוט נוסף שאולי צריך, למשל הוראות כיצד לחשב את השדות השונים בתשובה.
- הודעות שגיאה עסקיות – לעיתים נרצה להחזיר תשובה מיוחדת במקרי קצה עסקיים, חשוב לפרט את המקרים הללו ומה התשובה שתוחזר. זהו חלק מאוד חשוב מאפיון הממשק וחלק שלעיתים קרובות לא מפורט דיו ומוביל לסיבוכים ברגע שישנה תקלה.
בואו נצלול לתוך האפיון עם הדוגמה שלנו לגבי בית קולנוע. קהל היעד שלנו הוא שותפים המוכרים כרטיסים עבור הסרטים שאנחנו מציגים. למען הנוחות אנחנו נניח שיש לי רק אולם אחד בקולנוע שלי.
בשלב הראשוני של האפיון אני משוחח עם השותפים ומבין כי השירותים שאני אחשוף עבורם הם :
- קבלת רשימת הסרטים שמוצגים בקולנוע בתאריך מסוים
- קבלת רשימת המקומות באולם (כולל סטטוס זמינות כדי שיוכלו לדעת מה למכור)
- וקנייה של כרטיסים
עבור הממשק הראשון “קבלת רשימת הסרטים”, אני מברר מה הצורך של הצרכן שלי, ומסתבר שהם רוצים לתת טווח תאריכים ולקבל את כל הסרטים שאני מקרין בטווח התאריכים הזה.
- שם הממשק
נתחיל עם שם הממשק שלי, אני אקרא לו get_movies_by_dates כי זו המטרה שלו, לקבל את פרטי הסרטים המוצגים בתוך טווח תאריכים. לא לפחד משמות ארוכים. שימו לב שעבור המפתחים השם אמור להיות מספיק בשביל להבין לחלוטין מה הממשק עושה.
- תיאור הממשק
פה נרצה לכתוב באופן מאוד קצר וברור מה מטרת הממשק. לדוגמה: “קבלת רשימה של הסרטים המוצגים בתוך טווח תאריכים לבקשת הלקוח”. שימו לב שבמוצר יכולים להיות עשרות API ולפעמים השמות שלהם לא לגמרי מבהירים מה ההבדל בין כמה ממשקים דומים. המטרה של התיאור הזה הוא להקל מי שמפתח או משתמש בממשק הזה.
- בקשה ותשובה
לאחר מכן אני מפרק את הממשק לבקשה (request, מה שהצרכן שולח אלי) ותשובה (response, מה שאני מחזיר לצרכן). כמה נקודות חשובות: איפיון ממשקים כמעט תמיד מתבצע באנגלית. חלק מכך נובע מהעובדה שלמרות שזהו חלק פנימי של פיתוח תוכנה, ממשק הוא מוצר שהשותפים שלך חשופים אליו ולכן חשוב מאוד שהמונחים והשמות יהיו מדויקים וברורים.
עבור כל שדה בבקשה או בתשובה אנחנו נציין את
- שם השדה – חשוב שהשם יהיה מאוד ברור ויתאר נכונה את מהות התוכן.
- סוג המידע והפורמט – לא תמיד ברור מה המידע ששדה מכיל. למשל בשדה “סוג מטבע” (currency) יכול להיות השם של המטבע בטקסט קצר “Dollar”, בטקסט ארוך “US dollar”, בטקסט עוד יותר ארוך “United states Dollars” או בסימן “$” ואנחנו רוצים לוודא שאין אי הבנות. זו גם הסיבה שאנחנו מוסיפים דוגמאות. החשיבות בציון הפורמט היא במניעת תקלות ואי הבנות. לדוגמה תאריך יכול להיות רשום במגוון פורמטים וציון של הפורמט ימנע בעיות בטעויות, למשל MM-DD-YYYY (פורמט תאריך אמריקאי) לעומת DD-MM-YYYY (פורמט ישראלי).
- הסבר – לפעמים נצטרך הסבר על מנת לוודא שהערך שנוצר הוא הנכון. זה יכול להיות הסבר מפורט או קצר, בהתאם לרמת הסיבוך.
- דוגמה – אני גיליתי שממש מועיל להוסיף דוגמה לערכים שאנחנו מצפים לראות בשדה. זה מונע המון בעיות ומאפשר למפתח להעתיק מהמסמך אפיון לממשק עצמו כדי לעשות בדיקות.
- חובה או רשות – האם חובה לציין ערך בשדה הזה או שהו אוציונלי.
אנחנו ממשיכים עם הדוגמה של בית הקולנוע שלנו והממשק לקבלת סרטים לפי תאריכים, בואו נסתכל על הבקשה:
Request:
Each request will contain a start date and end date.
Field | data_type | description | example | Required |
Requestor_id | number | The id of the partner site that wants to get the movie details | 23 | YES |
Start_date | Date (including timezone) | The first date of the information requested | 2023-03-23T00:00:00+2 | YES |
End_date | Date (including timezone) | The last date of the information requested | 2023-03-23T00:00:00+2 | YES |
מצוין, קל להבין מה צריך לשלוח. איזשהו מספר מזהה כדי שאני אדע מי מבקש את המידע, ותאריך התחלה וסיום. שימו לב לעמודה האחרונה שמטרתה לציין אילו מהשדות חובה למלא ואיזה ניתן להשאיר ריקים.
לאחר הטבלה נציין מגבלות והוראות לגבי הבקשה. למשל: שתאריך הסיום חייב להיות מאוחר יותר או זהה לתאריך ההתחלה.
Please make sure to check that the end_date is equal or later then the start_date
השלב הבא הוא לציין את מבנה התשובה שאנחנו שולחים לצרכן שלנו, נתחיל עם הסבר קצר ואז במבנה עצמו:
response:
A list of movies, each with a set of screening times
Field | data_type | description | example |
Movie_title | text | “Dungeons and dragons: Honor among thieves” | |
movie_id | number | 30 | |
movie_desc | Text (up to 300 characters) | “An epic adventures based on the roleplaying game” | |
movie_screenings | {id, screen_date, screen_time} | A list of screenings, each with ID, date and time | Single screening:{01, 23.03.2023, 19:00 GMT+2} Multiple screenings:{01, 23.03.2023, 19:00 GMT+2},{02, 23.03.2023, 22:00 GMT+2} |
ולאחר מכן, כמו בבקשה, הסברים והרחבות לגבי מה התשובה מכילה. למקרה הזה התגובה היא די ברורה: כותר הסרט, קוד הסרט, תיאור הסרט, ורשימה של הקרנות של הסרט במבנה מוגדר היטב.
- הודעות שגיאה עסקיות
רוב הממשקים בעולם כבר באים עם קודי השלמה טכניים ברורים ולכן אנחנו לא צריכים לטפל בהם. למשל ב-HTTP קוד ההחזר “200” מייצג ביצוע מוצלח בעוד הקוד ” 4xx” מייצג שגיאה בצד הלקוח (למשל קריאה לממשר עם ערך שגוי). אז אין צורך לאפיין מחדש את התגובות הללו.
מה כן חשוב לציין? הודעות שגיאה עסקיות. למשל מה להחזיר אם לקוח מבקש רשימת סרטים שמוצגים בתאריך מסוים אבל אין סרטים? האם להחזיר רשימה ריקה? או תגובה מיוחדת? במקרה הזה למשל הייתי מצפה לקבל תשובה כגון Response_code: 204 שמציין שהפעולה בוצעה בהצלחה אבל עם אזהרה כלשהי יחד עם הטקסט Response text: success, no movies found. הוספת טקסט הבהרה להודעת שגיאה יוכל לחסוך המון זמן ומאמץ בניסיונות להבין מה הבעיה.
ניהול גרסאות
כמו ברוב מוצרי התוכנה בעולם, בעתיד אנחנו עלולים לרצות ליצור גרסאות מתקדמות יותר של הממשק שלנו. במקרה כזה אנחנו עלולים למצוא את עצמנו עם מספר בעיות. הראשונה ביניהן היא שאין לנו שליטה על מה עושה מי שמשתמש ב-API שלנו. אנחנו לא יכולים להכריח אותם לעבור להשתמש בגרסה חדשה.
כיצד עושים ניהול גרסאות עם API? הדרך המקובלת היא לתכנן מראש את האפשרות לגדילה עתידית ולתמיכה לאחור (Backward compatibility). נסו לחשוב על התקדמות עתידיות וודאו שגם אם תוסיפו פונקציוניוליות לא תצטרכו למשל להוסיף שדות חובה חדשים.
זה אומר שלפעמים נצטרך שתהיה לנו תוכנית מעבר לגרסה חדשה של הממשק שלנו, תוכנית שכזו תכלול הוצאת התראה לפני מעבר לגרסה חדשה, התרעות למשתמשים בגרסה ישנה לפני המעבר, ולוודא שיש זמינות ויידוע של צוות התמיכה בזמן מעבר בכדי לספק ללקוחות שלא עברו לגרסה החדשה תמיכה נאותה.
חווית מפתח (Developer Experience)
אחד מהמונחים שאני מנסה לקדם הוא חווית מפתח, כולנו מכירים את המונח “חווית משתמש” ולוקחים אותו בחשבון בעיצוב המוצרים שלנו. אבל ב-API המשתמש שלנו הוא גם הלקוח שמשתמש בממשק וגם המפתח שצריך להתממשק ל-API שיצרנו. על מנת ליצור חווית פיתוח נוחה למפתח אנחנו נרצה לעשות מספר דברים:
תיעוד – כתיבת תיעוד מסודר של הממשק המיועד למשתמשי ה-API. חשוב שהתיעוד יכיל את התהליך העסקי כדי לתת למפתח את ההקשר העסקי להבנת התהליך שה-API הוא חלק ממנו.
דוגמאות לקוד – אחת מהדרכים הכי טובות להקלה על מפתחים היא לספק דוגמאות קוד שמבצעות שימוש נכון ב-API. ברור שזה לא תפקידו של מנהל המוצר לכתוב את הדוגמאות הללו כמו שזה לא תפקידנו לעצב את המסמך. אבל זה כן באחריותנו לוודא שמישהו מצוות הפיתוח מקבל את המשימה הזו ומוסיף את הדוגמאות הנכונות.
שימוש בכלים סטנדרטיים – יש מגוון כלים שמטרתם לסייע בפיתוח וצריכה של ממשקים. אחד מהכלים הנוחים לשימוש נקרא Swagger ואני ממליץ לעבור עליו קצת ולראות מה הוא נותן בכדי להכיר כמה best practices.
טיפים, לקחים, ובעיות נפוצות באפיון הממשק
היות וכבר איפיינתי ועבדתי מול הרבה מאוד ממשקים שמתי לב שיש מספר בעיות שנוטות לחזור על עצמן. שימו לב שאתם לא נופלים באחת מהטעויות הנפוצות הללו:
כללי כתיבה וטרמינולוגיה אחידים – אחד מהדברים שהכי מקלים על יצירה וצריכה ממשקים זה להגדיר מראש כללי כתיבה וטרמינולוגיה. זה כולל כלליי כתיבה כגון האם משתמשים בקוים תחתונים (למשל: get_movie_details) או אותיות גדולות בין מילים (Camel case) (למשל: getMovieDetails).
וכמובן את הטרמינולוגיה של אוביקטים במערכת, כאשר קוראים לאותו אוביקט בשמות שונים זה יוצר הרבה בלבול. למשל get_movie_details ובמקום אחר get_list_of_films .
החצנה של מונחים פנימיים – לעיתים קרובות יש נטייה להשתמש במונחים שאנו רגילים אליהם כאשר אנחנו מייצרים את ה-API שלנו. העדיפו להשתמש במונחים המקובלים בתעשייה או לכל הפחות מונחים שיהיו מובנים למשתמשים שלכם. אם בחברה שלכם מכנים כל הקרנה כהצגה (“show”) עדייף עדיף לקרוא לשדה בממשק במונח הנכון “Screening”.
החצנה של תהליכי עבודה פנימיים – זה הגיוני לגמרי שהתהליכים הפנימיים בחברה שלנו יהיו שונים מאוד ממה שנחשוף למשתמשים. למשל יכול להיות שאצלנו בחברה יש ממשק אחד להגדרת שעת הקרנה, ואז עוד ממשק להגדרת סרט, ואז ממשק נוסף ליצירת כרטיסים למכירה והפעולות הללו צריכות להתבצע לפי הסדר. אבל למשתמש שלנו לא איכפת מכל זה, הוא רוצה להוסיף הקרנה ולהתחיל למכור כרטיסים. אז אולי ניצור עבורו ממשק שמבצע את כל הפעולות הללו בממשק אחד ונחסוך לו זמן ומאמץ.
קחו בחשבון את אופי השימוש ונפחי המידע המועבר– קריאות API הן תקשורת בין שני צדדים, הקפידו לשמור על שני הצדדים. אתם לא רוצים להיות “מופצצים” במיליוני קריאות שיעמיסו על המערכת שלכם ואתם לא רוצים להחזיר כמויות מידע שעלולות “לחנוק” את הצד המבקש. במקרה שיש אפשרות לכמות גדולה של בקשות, ציינו זאת על מנת שאפשר יהיה להוסיף מנגנון הגנה (“throatling”) ובמקרה של שליחת כמות גדולה של מידע ציינו זאת על מנת שהצד השני יוכל להוסיף מנגנון קבלה מדורג (“pagination”). אני ממליץ בחום לתת למפתחים גבולות גזרה כגון ״לא סביר שלקוח יקרא ל API יותר מ 5 פעמים בשנייה״, כך נאפשר למפתחים להערך בהתאם. שימו לב שניתן גם להגדיר פעולות ספציפיות שיאפשרו התמודדות עם כמויות גדולות של מידע, כגון לבקש טווחים מסוים של התשובה.
הוספת מזהים לאוביקטים (אפשרות להתמקדות) – כאשר אנחנו מחזירים למשתמש רשימה של נתונים חשוב להחזיר גם מזהה (ID) של המידע שהחזרנו על מנת שאם המשתמש ירצה לתחקר אחד מהפריטים ברשימה הוא יוכל לצין את הפריט הספציפי על ידי המזהה.
הקלו על המשתמשים להצליח – נסו לוודא כי ברור ככל האפשר למשתמש באיזה ממשק הם צריכים להשתמש על מנת לקבל את המידע או לבצע את הפעולה שברצונם לבצע. אם יש טעות – החזירו תשובה מפורטת ככל האפשר לגבי מהי התקלה. למשל הנה דוגמא לתשובה גרועה: ״קלט לא תקין״. דוגמא טובה יותר תהיה ״ישנה בעיה בשדה name”, והדוגמה הכי טובה תהיה ״שגיאה: שדה name צריך להיות במבנה הבא: a-z*\d2″.
רמת הפירוט של התיעוד – הנושא של עד כמה לפרט באפיון של כל פיצ’ר הוא סוגיה לא פשוטה. כתבתי כבר על הנושא הזה באריכות אבל כאשר אנחנו מדברים על תיעוד של API חשוב לזכור שאנחנו לא מכירים את קהל היעד שלנו ולא מודעים לרמת הידע או המקצועיות שלהם. לכן אני ממליץ להרחיב יותר מאשר לקצר. כמובן שמומלץ לא להיכנס לתוך פרטי היישום של הממשק בתוך המערכות שלנו. חלק נרחב מהמהות של API הוא שאין צורך להבין כיצד הדברים עובדים מתחת לפני השטח.
דוגמאות לאפיוני API מוצלחים
יש אינספור מסמכי אפיון API ברשת. אחרי הכל המטרה של התיעוד הזה הוא שהמשתמשים שלנו יוכלו להשתמש בממשק שיצרנו עבורם. ניתן לראות ממשק פשוט ובעברית באתר של Voicenter. תרגישו חופשיים להיכנס לכל אחד מהממשקים שהם חושפים ולהעיף מבט על ההסברים.
אם אתם רוצים לראות דוגמאות למערכות יותר מורכבות אפשר להעיף מבט על תיעוד ה-API של חברת Stripe, של תיעוד ה-API של Firebase, או תיעוד ה-API של Shopify שמסודר ממש יפה לקטגוריות שמקלות על השימוש.
לסיכום
המטרה של המדריך הזה היא לעזור למנהלי מוצר בלי רקע טכני להבין מה זה API, וכיצד לאפיין אחד. ברור שקריאת הפוסט הזה לא תהפוך אתכם למומחים בתחום, אבל אני מקווה שהיא תעזור למנהלי מוצר חסרי ניסיון בתחום להימנע מהטעויות הנפוצות ביותר ולוודא שלא תשכחו אף אחד מהשלבים החשובים באפיון הממשק. עבור מנהלי מוצר מנוסים, מטרת המדריך הזה יותר להוות צ’קליסט לוודא שלא שכחנו כלום באפיון ה-API הבא שלנו.
המדריך הזה לא מושלם, ניתן להרחיב לגבי כל אחד מן הנושאים שדיברנו עליהם ויש נושאים נוספים חשובים כגון כיצד לוודא שה-API שלנו בשימוש, כיצד לבדוק כמה קל עבור המשתמשים להטמיע את ה-API בצד שלהם, כיצד לבדוק את הביצועים של ה-API עצמו ולשפר אם יש בעיות, כיצד לראות האם הוספת ה-API קידם את ה-KPI העסקיים של החברה, טכנולוגיות שונות ליישום ממשקים, מוצרים מובילים בתחום, ועוד. אבל כל אלו יאלצו לחכות למדריך מתקדם.
אם נתקלתם בנושאים נוספים שעזרו לכם באפיון ממשקים אני יותר מאשמח לשמוע ולעדכן את הפוסט הזה.
נעים מאוד,
אורי ליפשיץ
תודה רבה לכל מי שתרם לפוסט הזה בהצעות, המלצות, ודיוקים. ובמיוחד לאלון סנדלר, אבנר שחר קשתן, בוריס צקרסי, יניב ניסים סיסו, עומר רביב, ערן ארבל, רונן אברבנאל, ועוד כמה אנשים נפלאים שהשקיעו מזמנם לתת פידבק בכדי לשפר את המסמך הזה.