תכונות התוכנה
כדי לכתוב קוד לא צריך לחשוב עמוק מדי על יכולות התוכנה שאנחנו הולכים לכתוב.
לעיתים תוכנה נוצרת כתוצאה מצורך יחידני ולאחר מכן הוספה של פתרונות לצרכים אחרים.
למשל תוכנת ה-IDE
- Integrated Development Environment
.
בפעם הראשונה היה צורך בתוכנה שמציגה את הקוד וחלון פקודות כדי לקמפל ולהריץ את הקוד.
לאחר מכן היה צורך לדבג את הקוד ולראות את המידע אודות הריצה - זכרון, שגיאות וכדו’
ולבסוף נוצרו תוכנות עם יכולות מתקדמות כמו ריצה של תהליכים מרובים, דיסיינגרים של חלונות ועוד…
לכל אורך תהליך הפיתוח, הם קיבלו פידבקים וחשבו על אילו עוד פיצ’רים המתכנתים רוצים.
כל יכולת של התוכנה מוסיפה לפונקציונאליות של התוכנה.
וזו הייתה ההתמקדמות הראשונית שלהם.
הפונקציונליות היא התכונה הראשונה לכל תוכנה - מה היא מסוגלת לעשות.
ככל שהתוכנה גדלה התחיל הצורך גם לחשוב מעבר לפונקציונליות,
האם צריך תמיכה בשפות נוספות?
האם הפיצ’רים החדשים גורעים מהביצועים?
האם שפת הפיתוח השתנתה וצריך לתמוך בשפות פופולריות נוספות?
כל השאלות האלו נענות בעזרת הגדרת תכונות העל של התוכנה.
יש אף סטנדרט שמגדיר את התכונות והתתי תכונות הנקרא - ISO/IEC 25010
.
חלק מהתכונות הגדולות הן:
- פונקציונליות
- אפקטיביות וביצועים
- שימושיות
- אבטחה
- תחזוקה
- תאימות ושימושיות בין מערכתית
אנחנו נתמקד באחרון מביניהם - תאימות ושימושיות בין מערכתית.
או במילה אחרת - Interoperability
.
Interoperability - תאימות
התכונה הזו מתארת כיצד התוכנה שלנו יכולה לעבוד מול מערכות אחרות.
לעיתים נפגוש את התכונה הזו בשלב ה-אינטגרציות
.
שלב האינטגרציות הוא השלב שבו לוקחים שתי מערכות ונותנים להם להתנשק.
וברצינות יותר, זה השלב הקריטי בו פוגשים את תת המערכות בתוך כל התהליך או המוצר.
כאן נשאלת השאלה - איך אנחנו מתכננים את זה מראש?
לא הכל כמובן נוכל לתכנן לפרטי פרטים, נציג כאן את הדרך הראשונה והמודרנית בהתמודדות עם כלים לתאימות בין מערכתית.
סנטדרטים
אחד העקרונות שעוזרים לתחום התוכנה להשיג תאימות בין מערכות אלו סטנדרטים.
סטנדרט בקצרה אומר - כולם עכשיו מבינים את אותה השפה.
בדרך כלל סטנדרטים מגדירים פרוטוקולים - ופרוטוקול מגדיר בתחום התוכנה איך המידע נראה וכיצד הוא מועבר.
סטנדרטים ופרוטוקולים נפוצים:
- TCP
- HTTP
- FTP
- OpenGL
- SQL
- XML
RFC - Requests For Comments
לרשימה:
https://en.wikipedia.org/wiki/List_of_RFCs
ואם אתם רוצים לצחוק קצת -
https://en.wikipedia.org/wiki/April_Fools%27_Day_Request_for_Comments
וכמו כן רשומות של הצעות להתנהגות תוכנתית:
https://en.wikipedia.org/wiki/Best_current_practice
Restful API and Json
Json
Json
- JavaScript Object Notation
.
לראשונה נוצר כחלק מ-js
אך היום כלל השפות כוללות מודולים לניהול json
.
הפורמט כתוב בצורה טקסטואלית שניתנת לדחיסה וגם לקריאה -
1 | { |
וכך זה נראה דחוס:{"name":"Bob","age":42}
REST API
Representational State Transfer
API זו ארכיטקטורה תוכנתית לשירותים אינטרנטיים.
העקרונות הבסיסיים:
- מודל שרת-קליינט
- זיהוי משאבים על ידי מזהה ייחודי
- ייצוג אחיד על מנת לעדכן את המידע בשרת
- Stateless - כל בקשה לשרת תהיה אחידה ולא ישמור מידע בין בקשות.
בעיקר כדי שלא יצטרכו לשלוח בקשה מסוימת לפני בקשה אחרת. - ניתן לשמור את המידע ב-Cache וההתנהגות לא תיפגע.
- היררכיה ושכבות למידע.
בניגוד להסכמות מסוימות כדי להגדיר API
כ-Restful
הוא אינו חייב להיות ב-Http
.
שירותים כמו C# WCF
היו יכולים לעבוד עם שירותי REST
גם ללא HTTP
.
אולם HTTP
ו-JSON
אלו כלים בשימוש מאוד נפוץ וקל לפתח שירותי אינטרנט בעזרתם.
HTTP על רגל אחת
לשירות יש כתובת, למשל האתר של נאסה:https://apod.nasa.gov/
.
לכל משאב יש תת-כתובת, זו הצורה שבה אנחנו יכולים לשלב היררכיה ושכבות למידע שלנו.
למשל כדי לגשת לתמונה היומית של נאס”א נוכל לגשת ל-https://apod.nasa.gov/apod/
.
וכדי לגשת למשאב נוכל לציין במפורש איזה משאב אנחנו רוצים בכתובת:https://apod.nasa.gov/apod/ap230520.html
לכל בקשה יש כמה דברים:
- כתובת
- מתודה/פעולה - GET/POST/PUT/DELETE
- מידע על הבקשה - headers
- במידה ויש לנו מידע לשלוח שלא כחלק מהכתובת אז - payload - גוף ההודעה.
בפוסט אחר הסברתי על כל אחד מהם:
הסבר על URL
שרת וקליינט בין שפות שונות
לאחר שהבנו את הבסיס להבנת השירותים - נוכל להיעזר בכלים שהצגנו על מנת לבנות מערכות מותאמות בשפות שונות.
את קוד הלמידה תוכלו למצוא כאן:
https://github.com/Ilya122/interoperability_learning_in_simplycode/tree/main/1_JsonHttp/MainServer
תורידו אותו ותוכלו להתנסות עם השרת ב-.net C#
.
בשביל לדבג צריך Visual Studio
.
ממליץ על ה-Community Edition 2022
.
יצירת השרת ב-C#
ל-.Net
ו-C#
יש מנגנון פשוט שנקרא Minmal web API
המבוסס Asp.Net
.
כדי ליצור פרויקט חדש שלו נוכל לפתוח בעזרת הפקודה:
1 | dotnet new web -o MainServer |
למשל ניקח את הבקשה הכי פשוטה:
1 | app.MapGet("/", () => "Hello to Cat world!"); |
כאשר ניגשים ל-API
בלי שום משאב זה יחזיר Hello to Cat World!
.
שיפור השירות
כעת נוסיף התנהגות לשירות שלנו.
נוכל להשיג את כמות החתולים בחתוליה,
נוכל להשיג את התמונה של חתול ספציפי,
ונוכל לעלות תמונה של חתול.
בקשות בעזרת curl
אחרי שמריצים את הAPI
curl
זוהי תוכנה נפוצה לשליחת בקשות.
לבדוק שהשירות למעלה:
1 | curl -X GET https://localhost:7264/ |
לבדוק את כמות החתולים:
1 | curl -X GET https://localhost:7264/cats |
לבקש תמונה ספציפית של חתול:
1 | curl -X GET https://localhost:7264/cats/1 |
לעלות תמונה של חתול:
1 | curl -v -k -H "image/jpeg" -F file=@newCat.jpg https://localhost:7264/cats |
שימו לב שהקובץ newCart.jpg
קיים ב-Current Directory
שאתם נמצאים בו.
כדי לבדוק שזה עובד תנסו לגשת לחתול שלישי - מכיוון שיש 2 חתולים זה יחזיר לא נמצא:https://localhost:7264/cats/3
לאחר מכן הריצו את הפקודה למעלה כדי לעלות חתול:
עכשיו כשהבנו איך זה עובד אפשר ליצור את הקליינט שלנו.
אתר החתולים
כדי לבנות את האתר נשתמש ב-cherrypy
ו-pyvibe
.
CherryPy
https://docs.cherrypy.dev/en/latest/
פריימוורק מינימליסטי לאתרים
PyVibe
חבילת פייתון לג’נרוט html
.
1 | import cherrypy |
אינטגרציה וארכיטקטורה
השתמשנו בכלים פשוטים ביותר כדי לבצע אינטגרציה בין הצד שמכיל את המידע ה-Cat API
שלנו.
שם גם ה-storage
.
בלי “קישור ישיר” אנחנו בונים אתר ומחברים אותו ל-API
בעזרת שני הכלים Http
ו-Json
.
כך אנחנו יכולים לברר אודות מצב החתולים בשטחים ולהשיג כל חתול בנפרד.
מה נפלא כאן?
את האתר בנינו בעזרת הכלים python
, html
ו-js
.
איפה כאן מסתתר קוד javascript
? בכפתור!
כאשר אנחנו מעבירים חתול אנחנו בעצם מבצעים הפנייה לג’אווה-סקריפםט.
את ה-api
בנינו בעזרת C#
.
למזלנו אין כאן צורך במסד נתונים אז חסכנו מאיתנו את הטרחה הזו!
אלטרנטיבות
נעשו במרוצת השנים טכנולוגיות שעובדות על גבי פרוטוקולים שונים כדי לנסות לפשט את צורת העבודה.
WCF
https://learn.microsoft.com/en-us/dotnet/framework/wcf/whats-wcf
טכנולוגיה ישנה אך המהות שלה לא השתנה - לקחת אובייקטים הכתובים ב-C#
, לסרלז אותם ולשלוח אותם מעל פרוטוקול מסוים.
ProtoBuff
השפה של גוגל לתיאור גנרי של אובייקטים על מנת לסרלז אותם ולשלוח אותם.
קישוריות בין שפות תכנות וה-ABI
בארכיטקטורה הקודמת יצרנו ממשק http
בו אנו יכולים לגשת משפה אחת לשפה שנייה.
ממשקים בין מחלקות וקריאות http
בדרך כלל נקראות - קריאות API
.
API
- Application Programming Interface
.
בכללי API
זה קוד שפונה לקוד אחר - ובדרך כלל איננו יודע על איך הוא ממומש.
אך יש שכבה מתחתיה שנקראת ABI
הגורמת לזה לעבוד.
ABI
- Application Binary Interface
.
החיבור בין C++ ל-פייתון
הקוד נמצא בתיקייה הזו - יש להוריד אותה ולחלץ לתיקייה.
https://github.com/Ilya122/interoperability_learning_in_simplycode/tree/main/2_CPP_ABI/CPP_API
קודם כל נגדיר פרוייקט קטן שמחשב משהו בעזרת C++
1 |
|
ה-PROGRAM_EXPORT
מוגדר כך:
1 |
הקוד הזה מגדיר מה מיוצא החוצה ומה נכנס.
עבור ווינדוס אנחנו צריכים לתת למחלקה את ההגדרה __declspec
במידה ואנחנו מוציאים מה-dll
צריך לשים:dllexport
.
במידה ואנחנו צורכים אותו, יש לציין dllimport
.
שיו לב שהפרוייקט מוגדר בעזרת cmake
.
כדי לבנות אותו יש לבצע את רצף הפקודות:
1 | mkdir build |
אם הינכם בווידוס וגם cmake
מותקן וגם vs
אז הוא ייפתח!
- ניתן להשתמש גם ב-
cmake-gui
.
איך אנחנו נבדוק - ABI
?
בווינדוס נבדוק בעזרת הכלי dumpbin
שנותן לנו אופציה להתסכל לתוך binary outputs
.
על הכלי ניתן לקרוא כאן:
https://learn.microsoft.com/en-us/cpp/build/reference/dumpbin-reference?view=msvc-170
הפקודה להרצה:
1 | dumpbin.exe /EXPORTS ProgramLib.dll |
במידה והכל עבד כראוי נראה:
1 | ordinal hint RVA name |
השמות המוזרים האלו הם שמות מוערבבים על מנת לתת מזהה ייחודי לכל דבר שאנחנו מייחצנים על מנת שהם לא ייתנגשו אחד בשני.
חיבור לפייתון בעזרת cppyy
cppyy
זו ספרייה שמייצרת בצורה אוטומטית את הגשרים בין קוד C++
לקוד פייתון.
כדי להתקין cppyy
:
1 | pip install cppyy |
האתר שלהם:
https://cppyy.readthedocs.io/en/latest/
למי שרוצה לדעת יותר, הטכנולוגיה בנויה על גבי Cling
:
https://github.com/vgvassilev/cling
החסרון העיקרי של הספריה הזו הוא כל התלויות של הספריה.
זה יוצר בעיתיות בלהתקין את הקוד שלנו בנקודות קצה מכיוון שאנחנו צריכים להתקין את כל התלויות.
1 | import cppyy |
תעתיקו את הקבצים המצויינים לאותה תיקייה והריצו את קוד הפייתון!
אם פעלתם נכונה אתם תראו את התוצאה:
1 | PyCalculator>py app.py |
נכון מדהים?
קישוריות בין פייתון ל-.Net
ראינו כיצד מקשרים בין פייתון ל-cpp
.
כעת נקשר בין פייתון לשפות .net
כמו- c#
נשתמש ב-pythonnet
.
כדי להתקין:
pip install pythonnet
מטרת pythonnet
היא להביא את עולם הפייתון לעולם הדוטנט והפוך.
זהו מימוש פייתון ב-clr
.
clr
זה Common Language Runtime
שהוא ה-Virtual Machine
של שפות .Net
.
שפות כגון - C#, VB, F#
.
כדי לראות את הקוד תוכלו לצפות בתיקייה השלישית:
https://github.com/Ilya122/interoperability_learning_in_simplycode/tree/main/3_CLR_Python
ספריה ב-C#
1 | public class NameGenerator |
הקוד מבצע משהו מאוד פשוט - מייצר שם רנדומלי לאדם.
כדי לבנות את הקוד נשתמש ב-dotnet publish -o out_path
אך כדי לבנות את הקוד בשביל שנוכל להשתמש בו בפייתון נצטרך להוסיף ל-csproj
שלנו את הקטע:
1 | <PropertyGroup> |
הקוד בפייתון
1 | import sys |
שימו לב שלתיקייה העתקתי כבר את הקבצים הבינאריים, אתם יכולים לשחק עם זה ולהוסיף מתודות משלכם.
בזכות מה שהוספנו מקודם יש לנו קובץ לטעינה בשם - MyLib.runtimeconfig.json
.
בהתחלה אנחנו טוענים את הקונפיגורציה ל-runtime
.
1 | rt = get_coreclr(runtime_config=r'MyLib.runtimeconfig.json') |
הקבצים המיוצרים בדוטנט נקראים “אסבמליים” או Assembly
.
כל קובץ dll
יכול להכיל אסמבלי רבים או אחד.
כדי לטעון את האסמבלי אנחנו מבצעים:
1 | result = clr.AddReference("MyLib") |
ולבסוף נוכל להשתמש בקוד ה-c#
בתוך פייתון!
1 | from MyLib import NameGenerator |
והתוצאה:
1 | InteropLearning\3_CLR_Python\Py>py PrintName.py |
סקריפטים שעובדים בתוך ה-Runtime
למדנו על שירותים ב-HTTP
.
למדנו אינטגרציה בין שפות כגון C#
ו-פייתון
.
כמו שפייתון
היא שפה דינאמית וניתן בזמן ריצה להכניס קוד גם השפה -chaiscript
היא שפה דינאמית המאפשרת ליצור אינטגרציה בין שפת סקריפט לשפה מקומפלת.
מה הסיבה שנרצה את זה בכלל?
בעזרת הטכניקה הזו ניתן לקחת חלק סטטי של המערכת ולהפוך אותה להיות מתוכנתת ודינאמית.
אחת הדוגמאות הבולטות מתחום המחשוב זה הכרטיס הגראפי.
כדי לקרוא יותר ניתן לקרוא מהפוסט למבוא:
Shader
זהו סקריפט שניתן לטעון אותו ובאופן דינאמי לשנות איך התמונה מרונדרת למסך.
באופן דינאמי אנו טוענים טקסט שמייצג קוד Glsl
.
הקוד משנה בצורה פשוטה את צבע התמונה.
באותו אופן נוכל לחבר שפת סקריפט למערכת שלנו כדי ליצור תת מערכת דינאמית.
Chaiscript and the Dynamic AI
לאתר של Chaiscript
:
http://chaiscript.com/
בדוגמא הבאה אנחנו הולכים לייצר משחק ניחושים אבל הפוך.
אתם חושבים על מספר ולא אומרים למחשב מהו - והוא צריך לנחש מה המספר.
נפצל את המערכת לכמה מערכות:
- בחירת המספר
- ניחוש מספר על ידי המחשב
- בדיקה האם המספר נכון או לא
- המשך המשחק בהתאם לבחירת המחשב
- אם המחשב לא ניחש החזרת תשובה ע”י המשתמש אם המספר הוא גדול, קטן או שווה למספר.
- חזרה ל-2 אם המחשב טעה.
- נצחון אם המחשב צדק.
אנחנו ניקח את שלב 2 ונהפוך אותו לסקריפטאבילי - זאת אומרת שנכתוב אותו לא ב-C++
אלה בשפת סקריפט.
ככה שניתן להחליף את האלגוריתם בלי לשנות ולקמפל את המערכת.
הקוד
ניתן למצוא אותו כאן:
https://github.com/Ilya122/interoperability_learning_in_simplycode/tree/main/4_CPP_ChaiScript
אני לא ארחיב יותר מדי - אני רוצה שתקראו את הקוד ותנסו להבין אותו.
1 | chaiscript::ChaiScript engine; |
המערכת נותנת לשפת הסקריפט כלים להתמודד איתם בשביל לכתוב אלגוריתם.
greater_or_smaller
נותנת אפשרות לשפת הסקריפט לבדוק את תוצאת המספר שניחש.get_min_number
ו -get_max_number
כדי לדעת מהם גבולות המשחק.- 3 משתנים גלובאליים שיוכל לשמור בהם את החישובים שלהם.
בסופו אנחנו טוענים את הסקריפט שאנחנו הולכים להשתמש בו.
הסקריפט כתוב לאלגוריתם חיפוש בינארי שהולך לאמצע של כל דבר והוא זוכר מהי התוצאה הנמוכה ביותר שניחש ומהי הגבוה ביותר שניחש עד כה.
1 | def RunAI() |
השפה עצמה בנויה כשפת ג’אווה-סקריפט והיא מאוד קלה לשימוש וללמידה.
ניתן להוסיף בה מגוון רחב של אובייקטים והיא עובדת עם C++
באופן מאוד צמוד.
היא כתובה ב-C++
מודרני!
כדי להשתמש בזה כל מה שאתם צריכים זה להוריד את הפרוייקט.
לבנות בעזרת Cmake
:
1 | cd 4_CPP_ChaiScript |
ומפה אתם יכולים לקמפל את הפרוייקט ולהתנסות מולו.
שימו לב שקובץ הסקריפט צריך להיות ליד קובץ ההרצה כדי שיוכל לטעון אותו- במידה ואתם מדבגים.
סיכום
תאימות בין מערכות יכולה להיות ברמה הגלובאלית - איך אובייקטים נראים ובאילו פרוטוקולים הם משתמשים.
תאימות יכולה להיות גם בין קבצים בינאריים, טקסטואליים או כל דבר שאנחנו קוראים לו “מערכת”.
זוהי תכונה מאוד חשובה של תוכנה ופוגשת אותנו באינטגריות וכל מקום שאנחנו מנסים לשדרג ולחבר מערכות אחת לשנייה.
כלים כמו Http
, Json
עזרו לאינטרנט לחבר בקלות רבה מערכות רבות אחת לשנייה.
כיום מעדיפים כלים פשוטים שבכל שפה ניתן להשתמש בה וחשוב להכיר את האספקט הזה של התוכנה.
בעיצוב מערכת אנו צריכים לקחת בחשבון את כלל התכונות שאנחנו רוצים מהמוצר כולל תאימותו למערכות אחרות כי לא פעם נעבוד מול המתחרים שלנו יד ביד.
וכמובן - אל תשכחו לקרוא על הסטנדרט ולעמוד בו, אחרת זה ייעלה לכם הרבה כסף לתקן טעויות.
תודה על הקריאה!