הבלוג של ינון פרק

טיפים קצרים וחדשות למתכנתים

לכתוב קוד כאילו שיש זמן

27/06/2018

הדד ליין בעוד שלושה ימים, ה QA כל שעה על הקו עם באגים חדשים שמצאו ויש עוד פיצ'ר שכלל לא התחלתם לפתח. ועדיין-

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

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

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

אני לא חושב שרבים מכם ירצו לבוא לנקות איתי, אבל אם אתם בקטע של לכתוב יחד בדיקות יש עוד מספר מקומות לוובינר של יום חמישי. סילבוס וכפתור רישום בקישור:

https://www.tocode.co.il/workshops/33

תוכנית וובינרים לחודש יולי

26/06/2018

הי חברים,

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

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

ובחזרה ליולי. מתוכננים 4 וובינרים כולם ביום חמישי בבוקר כדי לסיים את השבוע עם חיוך. הוובינר הקרוב (עדיין של יוני) יהיה על פיתוח בדיקות אוטומטיות למערכות Web. אני מתכנן להתקין אתכם יחד את Selenium ו Capybara בתוך פרויקט פייתון ולבנות בדיקות למספר אתרים באינטרנט בתור דוגמא.

בשבועיים שלאחר מכן נבנה Web Application קטן מקצה לקצה. נכתוב תוכנית ציור קטנה בצד הלקוח עם JavaScript, HTML ו CSS; נחבר אותה לשרת של Firebase כדי לאפשר למספר משתמשים לצייר יחד על אותו הלוח ולאחר מכן נבנה מנגנון זיהוי משתמשים כך שהמשתמשים שלנו יוכלו לשמור את הציורים שלהם ולפתוח חדרי ציור נוספים ולהזמין אליהם חברים. בסיום שני החלקים תקבלו תמונה טובה של תהליך הפיתוח ואני מקווה שגם את הביטחון ללכת ולבנות דברים חדשים בעצמכם מקצה לקצה.

את החודש נסיים עם וובינר בנושא שיפור ביצועים ב React. נדבר על איך מודדים כמה זמן לוקח לריאקט לעשות כל דבר, מה משפיע על זמני התגובה של היישום, איך Pure Components עוזרים לשפר זמני ריצה וכמובן על Code Splitting וטעינה דינמית של חלקים מהיישום.

כל הרשימה וכפתורי ההצטרפות בעמוד הוובינרים בכתובת: https://www.tocode.co.il/workshops

נתראה, ינון

ארכיטקטורה

25/06/2018

יהיו מקרים שתכתבו קוד אחרי שביליתם שעות בחדר השרטוטים ותכננתם כל דבר איפה ישב. במצבים כאלה כדאי קודם לכתוב שלד ריק עבור כל המחלקות וכל הפונקציות שאתם בונים ורק אחר כך ללכת למלא אותו בקוד.

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

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

זוזו הצידה, אני יודע BFS

24/06/2018

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

המשך קריאה

השיטה הבטוחה למצוא עבודה כמפתח אפליקציות

23/06/2018

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

ומה לגבי הדרך הבטוחה למצוא עבודה במפתחת Web? מסתבר שגם את זה אתם יודעים: מוצאים אתר שאתם אוהבים ובונים גירסת קוד פתוח שלו. אחרי זה עושים את זה שוב, ושוב ושוב. אחרי עשרה אתרים יתחילו להגיע ההצעות.

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

כן קורס וחברים וה Webinars כאן יעזרו לכם תוך כדי המסע להתמודד עם הקשיים ויתנו מוטיבציה להמשיך. אבל ההתחלה היא המחויבות לבנות 10 אפליקציות או 10 אתרים או מה שלא בחרתם. זאת הדרך היחידה שאני מכיר.

הבאג המבלבל של השבוע

22/06/2018

פרס הבאג המבלבל של השבוע חייב ללכת לתוכנית הבאה:

members = ['one', 'two', 'three', 'four', 'five']
count = 0

for item in members:
    if item[0] == 't':
        count =+ 1

print(count)

ראיתם את הבעיה? אם לא קחו רגע לחשוב על זה. במקום לספור כמה מילים מתחילות ב t ולהדפיס 2 התוכנית מדפיסה תמיד 1.

וזה ברור כשעוצרים לקרוא את הקוד.

השורה:

count =+ 1

אולי חוקית בפייתון, אבל בשביל לספור צריך להשתמש ב:

count += 1

ולא - זה לא ייחודי לפייתון. וכן Linter טוב מזהה בעיות כאלה בשניה. תהנו מהסופ"ש ונסו לא לכתוב באגים מבלבלים.

בדיקות אוטומטיות לאתרים עם Python ו Selenium

21/06/2018

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

בשבוע הבא ביום חמישי בבוקר אעביר Webinar פתוח לקהל הרחב בנושא בדיקות אוטומטיות בו נכתוב יחד בדיקות אוטומטיות ב Python ו Selenium לאתרים קיימים. לינק להרשמה מופיע בסוף הפוסט. עד אז כמה דוגמאות קוד זריזות שתראו מה הולך להיות שם ואולי תשחקו עם זה גם לפני הוובינר ותבואו עם שאלות.

קובץ בדיקות אוטומטיות ב Python מכיל מחלקה היורשת מ unittest.TestCase. הנה דוגמא לקובץ עם הבדיקה הכי פשוטה שהצלחתי לחשוב עליה:

import unittest

class MyTestCase(unittest.TestCase):
    def test_something(self):
        self.assertEqual(True, True)


if __name__ == '__main__':
    unittest.main()

הרצה של הקובץ מציגה את הפלט:

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

מה שאומר שהבדיקה עברה בהצלחה. שינוי קטן בבדיקה כדי להכשיל אותה יראה כך:

import unittest

class MyTestCase(unittest.TestCase):
    def test_something(self):
        self.assertEqual(True, False)


if __name__ == '__main__':
    unittest.main()

שימו לב ששיניתי את המילה True ל False בשורת ה assertEqual וכעת הפלט נראה כך:

F
======================================================================
FAIL: test_something (__main__.MyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "simpletest.py", line 5, in test_something
    self.assertEqual(True, False)
AssertionError: True != False

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)

עד לכאן זה היה קל: בדיקה אוטומטית היא סקריפט פייתון שמריץ איזשהו קוד השוואה. כשהבדיקה מצליחה נקבל על המסך הדפסה קצרה עם המילה OK וכשהבדיקה נכשלת נקבל פירוט של הכישלון בצירוף ההודעה FAILED.

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

הקוד הבא למשל ייכנס לדף רשימת הפוסטים בבלוג וידפיס על המסך את כותרת הדף:

from selenium import webdriver

driver = webdriver.Firefox()
driver.get('https://www.tocode.co.il/blog')
print(driver.title)

driver.close()

שילוב בין השניים הוא שיאפשר לנו לכתוב בדיקות אוטומטיות. כך לדוגמא נוכל לבדוק שבעמוד הבית באתר זה מופיעים בדיוק 4 קישורים לקורסים:

import unittest
from selenium import webdriver

class MyTestCase(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox()

    def tearDown(self):
        self.driver.close()

    def test_something(self):
        self.driver.get('https://www.tocode.co.il/')
        course_links = self.driver.find_elements_by_css_selector('.nm-block a[href^="/bundles/"]')

        self.assertEqual(4, len(course_links))


if __name__ == '__main__':
    unittest.main()

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

https://zoom.us/meeting/register/3abdb0d0b6f403b7c5b9141539e44ee6

מה כל כך הפריע לי בניוזלטר של רפליט השבוע

20/06/2018

הדרך הכי טובה לכתוב קוד מטעה היא להתעלם מ Style Guides של השפה. במיוחד היום כשיש המון שפות תכנות וכל הזמן רואים דוגמאות קוד בשפות חדשות ונגיד את האמת יש גם הרבה שפות שדומות אחת לשניה. כשאתם כותבים רובי כמו שכולם כותבים רובי אני מיד מבין שזה רובי. אבל כשאתם כותבים רובי כמו שכותבים פייתון זה מבלבל.

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

require 'newsletter.rb'
puts greeting(user)

עד לפה הכל טוב ואז הם עוברים לספר על אירועים וכל הדברים שקורים שם ברפליט (באמת נשמע כמו אחלה חברה וגם האתר מוצלח). ואז בסוף הפרידה הכואבת:

newsletter.close()

הסוגריים כמובן מסיפור אחר.

כשאתם כותבים קוד במיוחד אם זה קוד ש(הרבה) אנשים אחרים הולכים לראות- תעשו טובה ולכו לקרוא קודם את ה Style Guide. לא כדאי להיתפס מחוץ לאופנה. קישורים? קבלו:

רפליט, שהוא אחד האתרים הכי מדליקים שפגשתי לאחרונה:

repl.it

וכללי ההתנהגות של רובי, שלא יתפסו אתכם עם סוגריים במקום הלא נכון:

https://github.com/rubocop-hq/ruby-style-guide

נשבר? שיישבר. האלטרנטיבה יותר גרועה

19/06/2018

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

<a href="https://www.google.com'>go to google</a>

רואים את הבעיה? גם אני לא ראיתי. אבל אם מסתכלים טוב רואים שיש מרכאות כפולות בצד אחד של הכתובת וגרש בודד בצד השני.

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

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

על שמות משתנים ופונקציות

18/06/2018

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

גירסא 1:

from random import randint

x = randint(1, 100)
while True:
    y = int(input('Please guess the value: '))
    if randint(1, 100) > 80:
        messages = ['Too large', 'Too small']
        print(messages[randint(0, 1)])

    else:
        if x > y:
            print('Too small')
        elif x < y:
            print('Too large')
        else:
            print('Bingo! You win')
            break

גירסא 2:

from random import randint

def should_lie(*_, lying_frequency=20):
    return randint(1, 100) < lying_frequency

def random_message():
    messages = ['Too large', 'Too small']
    return messages[randint(0, 1)]

secret_value = randint(1, 100)

while True:
    user_guess = int(input('Please guess the value: '))

    if should_lie(lying_frequency=20):
        print(random_message())
    else:
        if secret_value > user_guess:
            print('Too small')
        elif secret_value < user_guess:
            print('Too large')
        else:
            print('Bingo! You win')
            break

המעבר מגירסא 1 ל-2 דורש מעט מאוד מחשבה. כל מה שצריך הוא להבין את מטרת התוכנית ולתת שמות שמתאימים למטרה. אבל כשמגיעים לגירסא 2 חודש אחרי ברור לגמרי מה המשמעות של כל דבר. אפילו שהתוצאה ארוכה יותר בכמה שורות.