פרק קודם:
פייתון 26 - אסינכרוניות חלק במה נלמד
- כלים לאיכות קוד
- Code smells
- PyLint
- Bandit
- כלים נוספים ששווה בדיקה
כלי איכות קוד
כלים לבדיקת איכות הקוד רצים ומוודאים שהקוד שכתבנו אכן עושה את מה שרצינו,
שכתבנו אותו ללא בעיות לוגיות וכשלים שיכולים לגרום לתקלות.
יש מגוון רחב של כלים כאלו ואנחנו נתמקד בכלים שנקראים Static Code Analyzers
- כלים הרצים בצורה סטטית לפני ריצת הקוד שמוודאים שהקוד שלנו אכן תקין.
הבעיה בבדיקות אנושיות
בפרקים הקודמים למדנו איך לכתוב קוד בצורה מיטבית בכל נושא.
בכל פרוייקט שהוא - לאט לאט - נערמות לנו שורות על גבי שורות של קוד.
זה יוצר לנו בעיה:
עין אנושית צריכה לעבור על כל הקוד, לחפש בעיות ולתקן אותם.
המתכנתים שכתבו את הקוד לא תמיד יימצאו את כל הבעיות בעצמם - זו הבעיה בכתיבת קוד.
אז כמו כתיבת ספר - עורך ועמיתים נוספים עוברים על הכתוב ומוודאים שאין בעיות.
בשפה המקצועית זה נקרא Code Review
- בדיקת הקוד.
בשלב הזה גם המתכנתים שכתבו וגם המתכנתים שייבדקו את הקוד הולכים לעבור עליו שוב.
זהו שלב חשוב ולמרות שיש לנו כלים אוטומטיים - כדאי לבצע את השלב הזה.
אז מה הבעיה כאן אם כמות אנשים נכבדת עוברת על הקוד ומוודא שהכל תקין?
- עין אנושית בסופו של דבר נוטה להיכשל וסביר להניח שנפספס באגים.
למשל בעיות כתיב פשוטות שיכולות לפגוע:
רוב הכלים האוטומטיים כבר יודעים לזהות כשלים כאלו.
1 | def Functon(): |
- היכולת להתמקד בקוד בכל בדיקת קוד היא שעה-שעתיים.
ככל שממשיכים בבידקה איכות הבדיקה יורדת. - לעיתים אנשים אחרים לא זמינים לביצוע הבדיקה.
כדי לתקן את זה נוצרו כלים אוטומטיים שיכולים לבצע כל מיני סוגי בדיקות.
אז מה אנחנו צריכים לבדוק?
מהן הבדיקות שיש לבצע
- בדיקת פורמט וסטייל של הקוד.
ווידוא שהקוד נראה בצורה אחידה, ההזחות קיימות, רווחים סטנדרטיים.
למשל קוד כזה ייראה לנו מעט מוזר:
1 | a= 1 + 2-3* 2 |
כלי פורמט ייתקן לנו את זה מיד ל:
1 | a = 1 + 2 - 3 * 2 |
הצרה הקלאסית ביותר של מתכנתי פייתון זה הזחות או רווחים.
1 | def function(): |
- כלי למציאת בעיות פוטנציאליות או - Code smells
Code Smell
זהו מונח לכל קוד היכול להביע פוטנציאל לבעיות.
זוהי ראייה מאוד סובייקטיבית כי בהתאם לסטנדרטים של המתכנתים והמתודולוגיות שלהם - הם יכולים לראות בקוד מסוים כקוד בעייתי או קוד לא בעייתי.
קוד נפוץ שמעלה תהיות:
- קבצים ארוכים להפליא, קבצי קוד שמכילים אלפי שורות.
- המרות רבות של מידע לצרות מידע שונה - כל המרה טומנת בתוכה סיכון וככל שמבצעים יותר המרות כך גם הסיכון לבאגים גדל.
- פונקציה ארוכה מדי.
- מחלקה שמבצעת כמה דברים.
הכלים האוטומטיים לא תמיד מתריעים על כך - כדי לא לתייג פונקציות לא בעיות כבעלי כשלים.
בדרך כלל אנחנו נרצה לזהות בעיות פוטנציאליות כגון:
- לא יכל למצוא את הפונקציה, יכול להיות שטעינו בשם שלה.
- ערכים שלא אותחלו כראוי.
- פעולות מתטמיות לא אפשריות כגון חיסור באפס.
נרצה למצוא את כלל הכשלים הלוגיים לפני שנריץ את הקוד.
באגים אבטחתיים
בין אם זה שימוש בפונקציות ישנות, קוד לא מאובטח או חיבור לא מוצפן אנחנו נרצה לזהות כשלים אבטחתיים בקוד שלנו.קוד שלא בשימוש
בדרך כלל גם ה-IDE
שאנחנו משתמשים בו יתריע על קוד שלא בשימוש,
אך גם עבודת הלינטרים היא לבצע את הבידקות האלו.כלים לבדיקת הפונקציונליות הבסיסית
בפרק הזה לא נתמקד בהם - אלו כלים שמריצים בדיקות אוטומטיות על לוגיקת הקוד שלנו ומוודאה שהיא עושה אכן את מה שהיא אמורה לעשות.
יצאנו לנו לראות את זה בפרקים הקודמים - בדרך כלל הכלים האלו מריצים טסטים שאנחנו כתבנו, דוגמא לזה תהיה:
1 | def Add(a , b): |
- כלים רחביים לבדיקת המערכת
אלו כלים שרצים בקנה מידה רחב המוודא שכלל המערכת עובדת כראוי, ללא באגים, ללא כשלים אבטחתיים.
ולעיתים גם עובדים עם הכלים האלו בצורה ידנית כדי לוודא תקינות מערכת ע”י דגימת פרמטרים.
בדרך כלל מערכות כאלו נקראות “שליטה ובקרה”.
אלו כשלים יכולים להיות בכלים אוטומטיים?
- התרעה מוגזמת או בשפה המקצועית
False Positive
. - בכמות קוד רבה חלק המכלים יגזלו יותר זמן בבדיקה.
- כלים פשוטים לא ייזהו בעיות מורכבות יותר כמו
Multi threading
. - פוטנציאל באגים בכלים עצמם - הסנדלר הולך יחף.
Pylint
כדי להוריד יש להשתמש ב-pip
:pip install pylint
שימוש ב- PyLint
להלן קוד תקול:
1 | def addFunc(): |
בכל שורה ל- a
, b
, c
זהו מהי הבעיה.
הבעיה ב-a
שהפונקציה לא מחזירה למרות שהקוד מצפה להחזרה.
הבעיה ב-b
שהפונקציה נכתבה עם שגיאת כתיב ולכן לא קיימת.
הבעיה ב-c
שזה חילוק באפס.
נשמור את הקוד התקול בקובץ myFile.py
ונריץ מה-Commandline
את הפקודה pylint
עם שם הקובץ בצורה הבאה:
1 | pylint myFile.py |
התובנות שקיבלנו מה-pylint
:
- כל קובץ צריך להסתיים בשורה חדשה
1 | myFile.py:8:0: C0304: Final newline missing (missing-final-newline) |
- חסרה לנו דקומטנציה למודול
1 | myFile.py:1:0: C0114: Missing module docstring (missing-module-docstring) |
כדי להוסיף docstring
יש להוסיף:
1 | """ |
בתחילת הקובץ.
- שם הקובץ לא לפי הסטנדרט.
1 | myFile.py:1:0: C0103: Module name "myFile" doesn't conform to snake_case naming style (invalid-name) |
ניתן גם לשנות את זה בריצת הpylint
בהתאם לסטנדרטים שלנו.
ז”א לא חובה לעקוב אחרי כל שורה שהלינטרים מוציאים לנו אלה לדעת גם אנחנו כיצד הקוד שלנו צריך להיראות.
כדי לעשות רגקס משלנו לשם הקובץ נוכל להריץ אותו עם הפרמטר:
1 | pylint myFile.py --module-rgx=.* |
- חסר לנו
Doc string
על הפונקציה.
1 | myFile.py:1:0: C0116: Missing function or method docstring (missing-function-docstring) |
במידת הצורך ניתן לבטל גם את זה:
1 | pylint myFile.py --errors-only |
האופציה --errors-only
נותנת לנו רק שגיאות לוגיות ולכן כדאי להתחיל רק עם זה.
- שם של הפונקציה לא לפי הסטנדרט בברירת מחדל.
הריצה הדיפולטיבית מגיעה עם סט כלים שנבנה מראש - לא חייבים בהכרח לעקוב אחריהם וניתן להתעלם או לשנות את הקונפיגורציה של הכלי כך שיתאים לצרכים שלנו.
1 | myFile.py:1:0: C0103: Function name "addFunc" doesn't conform to snake_case naming style (invalid-name) |
- השגיאה האינדיקטיבית הראשונה שלנו.
1 | myFile.py:4:0: E1111: Assigning result of a function call, where the function has no return (assignment-from-no-return) |
אין ערך החזרה מהפונקציה ואנחנו מצפים לזה, כעת שהוא גילה לנו את זה אנחנו יכולים לחזור לקוד ולתקן!
- כמובן שהוא לא מזהה את הפונקציה שיש בה שגיאת כתיב.
1 | myFile.py:6:4: E0602: Undefined variable 'AddFunc' (undefined-variable) |
שימו לב שהכלי pylint
לא הודיע לנו על חילוק באפס!
לא להסתמך על הכלים בעיניים עצומות
כל כלי שבא לעזור לנו לפתח מגיע עם סט יכולות מובנה ולא תמיד הכלים מכסים את כלל התרחישים.
לכן אני ממליץ לקחת את הכלים בערבון מוגבל ולהשתמש בהם ככלי עזר ולא כתחליף להרצת סט בדיקות מקיף.pylint
הוא אחד מהכלים שייעזרו לנו לעלות את איכות הקוד אבל זה לא הכלי היחידי!
תרגול PyLint
ניתן למצוא מידע כאן:
Pylint Docs
הריצו את ה-
pylint
עם הרמה -HIGH
.הריצו את הכלי על תיקייה פרט לקובץ בשם
dontrun.py
הריצו את הכלי עם הגבלת כמות פרמטרים לפונקציה - 5 פרמטרים מקסימום
פתרונות:
pylint --confidence HIGH
pylint dontrun.py --ignore dontrun.py
pylint anotherFile.py --max-args 5
Ruff
Ruff
הוא כמו PyLint
אך הרבה הרבה יותר מהיר!
https://github.com/charliermarsh/ruff
אחרי שלמדנו את עקרונות הלינטינג מומלץ לעבור לספריה הזו מכיוון שהיא הרבה יותר זרירה מספריות אחרות.
Bandit
הכלי Bandit
ייעזור לנו לגלות בעיות אבטחיות בסקריפטים.
להלן קוד:
1 | import os |
כדי להריץ את הכלי נוכל לתת לו קובץ והוא ייעבור עליו:
bandit myFile.py
התוצאה:
1 |
|
- בעיתיות ה - Subprocess
הדבר הראשון שהוא מציג לנו זה הערה על המודולsubprocess
.
1 | import subprocess |
הרצה של סקריפטים או כלים חיצוניים לסקריפט שלנו אף פעם לא מוודאים שמה שיירוץ זה באמת מה שהתכוונו אליו.
דרך החלפה האקרים מיומנים יכולים להשתיל קוד זדוני מבלי שנשים לב.
איך פותרים את הבעיה הספציפית הזו?
בעדיפות לבצע import
או בדיקת Checksum
לכלים חיצוניים שאנחנו לא סומכים עליהם.
- Exec
1 | exec(open(scriptToRun).read()) |
הפונקציה exec
מקבלת טקסט חופשי ומריצה אותו.
במידה והטקסט הזה הוא קוד זדוני אז אנחנו נריץ בצורה עיוורת קוד שמטרתו להרוס ולפגוע.
אל תשמשו בזה אף פעם!
- הרצה של תהליכים
גם os.startfile(scriptToRun)
וגם p = subprocess.run(scriptToRun)
מריצים תהליך בשני פונקציות שורות.
הראשון יריץ תהליך ללא יכולת לקטוע אותו, שימו לב שבצורה השנייה יש לנו השמה למשתנה.
השני יתריע לנו על כך שאנחנו לא מבצעים בדיקה מה אנחנו מריצים.
בגלל השימוש ב-Environment Variable
זה מלה את הסיכון של הסקריפט הזה להריץ קוד זדוני.
טיפ אבטחתי
כאשר אתם כותבים קוד שיירוץ בשרת כלשהו כמו Django
תשימו לב לכל קלט שאתם מקבלים באופן חיצוני.
כמו כן אם אתם כותבים ספריות ציבוריות אל תשמשו בצורת קוד שיכולה להיות מוחלפת מבלי שתשימו לב כגון subprocess
או - exec
.
אולי הכוונה שלכם טובה אבל קוד לא מאובטח ינוצל לרעה בסופו של דבר.
אינטגרציה ל - IDE
IDE
- Integrated Development Environment
אלו כלים שנותנים לכם הכל.
זאת אומרת שלינטרים וכלים אוטומטיים חלקיים יהיו כבר מובנים כגון כלי בדיקה.
PyCharm
מי שמשתמש בכלי המדהים הזה יכול לערוך את ההגדרות שלו:
Configure PyCharm
VS Code
ב-VS Code
יש לנו הרחבות שנותנות לנו יכולות שונות.
למשל כמה הרחבות שלי יש:
כלים נוספים שכדאי להכיר
הצגתי לכם 2 כלים פשוטים שמכסים לכם חלק מהתרחישים.
יש כלים נוספים - מהירים יותר, ומכסים תרחישים שונים שיכולים לעזור לכם:
Flake8
הפלייק 8 ייעזור לכם בפרמוט וסטייל של הקוד:
Mypy
בודק טייפים בצורה מהימנה.
Black
פורמטר לקוד - מהיר ויעיל
בפרק הבא נעבור על סט כלים לבדיקות פונקציונליות הנקראים טסטים!
נראה איך כותבים טסטים נכונים ברמה הקטנה של הקוד, איך מתאימים קוד לטסטים ואיך פייתון כשפת סקריפט עוזרת לנו בעולם הטסטים גם בטכנולוגיות אחרות.