1 419
订阅者
-224 小时
-17 天
-130 天
帖子存档
1 419
3. לצורך Debug או מעקב הודעות - אפשר להגדיר סרביס ששומר את כל ההודעות שעוברות ב Exchange לבסיס הנתונים וכך אנחנו יכולים לוודא שהודעות מסוג מסוים לא ילכו לאיבוד.
בעולם האמיתי נוכל להגדיר Exchange לכל סוג אירוע ותור עבור כל תהליך שצריך לטפל באירוע. בעזרת Fanout Exchange כל התורים יקבלו במקביל את ההודעה על האירוע וכל סרביס יוכל לבצע את החלק שלו בטיפול.
1 419
# איך ולמה להקים Fanout Exchange ב RabbitMQ
תור ההודעות RabbitMQ הוא אחד האהובים עליי בגלל תיעוד מעולה והתקנה פשוטה. בין היכולות החזקות של רביט היא האפשרות לנהל את שליחת ההודעות באמצעות רכיב שנקרא Exchnage. בואו נראה איך להשתמש בו כדי לשלוח הודעה למספר רב של נמענים.
## הגדרת Fanout Exchange
האקסצ'יינג' הוא המנגנון שאחראי על קבלת הודעה ושליחתה לתורים הרלוונטים. ב RabbitMQ יש 4 סוגים של Exchange:
1. Direct Exchange
2. Fanout Exchange
3. Topic Exchange
4. Headers Exchange
הראשון, Direct Exchange, פשוט שולח את ההודעה לתור שמתאים לה לפי מפתח הניתוב של ההודעה (שזה בדרך כלל שם התור אליו היא מיועדת). השני, fanout, עליו נדבר בפוסט זה, משכפל כל הודעה ושולח עותק שלה לכל התורים ב Exchange. ב Topic Exchange ההודעה משוכפלת ונשלחת לתורים מסוימים לפי מילות קוד במפתח הניתוב והסוג הרביעי מאפשר שליחה לפי אוביקט JSON של קריטריונים מורכבים יותר המצורף לכל הודעה.
ב Python, הפקודה:
channel.exchange_declare(exchange='demo', exchange_type='fanout')
מגדירה Exchange לפי ה type שנבחר ועם השם שעובר לפרמטר exchange.
## שליחת הודעות
אחרי שהגדרנו את ה Exchange אנחנו יכולים לשלוח אליו הודעה עם הפקודה:
channel.basic_publish(exchange='demo',
routing_key='hello',
body='Hello World!')
ולמרות שאני מעביר ערך למשתנה routing_key המחשב מתעלם מערך זה מאחר ו Fanout Exchange פשוט משכפל את ההודעה לכל התורים.
התוכנית המלאה ב Python שתתחבר ל RabbitMQ על המחשב המקומי, תגדיר את ה Exchange ותשלח הודעה נראית כך:
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='demo', exchange_type='fanout')
channel.basic_publish(exchange='demo',
routing_key='hello',
body='Hello World!')
print(" [x] Sent 'Hello World!'")
## קבלת הודעות
בצד המקבל אנחנו יוצרים תור הודעות ומחברים אותו ל Exchange שיצרנו. בשביל שכל תהליך ייצור תור הודעות משלו אני מעביר מחרוזת ריקה בתור שם התור, וזה גורם ל Rabbit לבחור בשבילי את השם. הקוד הבא יוצר תור חדש ומחבר אותו ל Exchange:
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue
channel.queue_bind(exchange='demo', queue=queue_name)
אחרי שאני מפעיל את הקוד הזה מכמה תוכניות שרצות במקביל אני מקבל Exchange מרכזי עם הרבה תורים שמחוברים אליו. בגלל שסוג ה Exchange הוא fanout, כל הודעה שתגיע ל Exchange תישלח אוטומטית לכל התורים.
התוכנית המלאה ב Python שתתחבר ל RabbitMQ על המחשב המקומי, תיצור Exchange, תחבר אליו תור ותאזין להודעות בתור נראית כך:
import pika
connection = pika.BlockingConnection(
pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='demo', exchange_type='fanout')
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue
channel.queue_bind(exchange='demo', queue=queue_name)
print(' [*] Waiting for logs. To exit press CTRL+C')
def callback(ch, method, properties, body):
print(" [x] %r" % body)
channel.basic_consume(
queue=queue_name, on_message_callback=callback, auto_ack=True)
channel.start_consuming()
עכשיו מתחיל הכיף: נוכל להפעיל במקביל מספר עותקים של תוכנית קריאת ההודעות, כל עותק בחלון חדש. בחלון אחרון נפעיל את התוכנית ששולחת הודעה ואז נראה במקביל בכל החלונות שמאזינים את שורת ההדפסה מקוד הקריאה.
## למה זה טוב
שליחת הודעה למספר תורים במקביל מאפשרת טיפול במגוון של מצבים:
1. עבור לוגים - אפשר להגדיר מספר תוכניות שיקראו הודעות לוג, כל אחת תכתוב את ההודעה ליעד אחר: תוכנית אחת תכתוב לקובץ, שניה לבסיס הנתונים ושלישית תשלח את הלוג למאגר לוגים בענן.
2. עבור מספר תהליכים שקורים במקביל בעקבות אירוע - למשל כשמשתמש נרשם למערכת נרצה גם לשלוח לו אימייל, וגם לסמן בסרביס של הסטטיסטיקה אירוע של הצטרפות למערכת. שני תהליכים אלה לא קשורים והם מתרחשים בסרביסים שונים, ולכן נוח להשתמש ב Message Queue כדי לטפל בשניהם.1 419
# ואם היום לא בא לי
אנחנו אוהבים לחשוב על מוטיבציה בתור משהו שלא תלוי בנו: יש דברים ש"בא לי" עליהם, ואחרים ש"לא בא לי לעשות":
בא לי לראות יוטיוב; לא בא לי לקרוא ספר.
בא לי לעשות ספורט; לא בא לי לאכול פיצה.
בא לי לבנות פיצ'ר חדש; לא בא לי לחקור זליגת זיכרון ישנה.
אבל אם נעצור רגע להסתכל על התמונה הגדולה ניווכח, שגם אם השליטה שלנו על "הרצונות" שלנו היא לא ישירה, עדיין יש לנו השפעה לא רעה עליהם באמצעות שינוי הסביבה. יש יותר סיכוי שיתחשק לי לעשות ספורט אם כל האנשים סביבי עושים ספורט ומדברים על זה. יש יותר סיכוי שיתחשק לי לבדוק טכנולוגיה מסוימת חדשה אם ביום יום שלי אני כל הזמן קורא על טכנולוגיות חדשות.
הרבה פעמים אנחנו חושבים שיהיה הרבה יותר קל להשקיע את הזמן בלימודים אם רק אמצא משהו שמעניין אותי, או שאחרי שאכנס לקורס מעניין כבר "יבוא לי" גם ללמוד בבית. הניסיון שלי כמעט כל פעם הראה את ההיפך, כלומר בשביל לקבל מוטיבציה, בשביל ש"יבוא לי", צריך קודם לארגן את החיים מסביב לדבר שאני רוצה ללמוד, לשריין את הזמן וליצור סדר יום סביב הדבר שאני רוצה ללמוד או לעשות.
1 419
# חוסך עבודה או חוסך הבנה
זה לא אותו דבר ולשניהם יש מקום:
אני יודע מעט מאוד על איך מערכת הפעלה קוראת קובץ Executable, אבל עדיין מצליח לבנות בקלות קבצי הפעלה ותוכניות באמצעות שפות תכנות מדרגה גבוהה יותר. אני כותב קוד Java => הקומפיילר של Java הופך את הקוד ל Bytecode => המכונה הוירטואלית של Java מתרגמת בזמן אמת את הקוד לשפת מכונה => מערכת ההפעלה מבצעת את הפקודות בשפת המכונה. העבודה ב Java, או בכל שפת תכנות אחרת, חוסכת לי הבנה.
ולמרות שאני יודע די הרבה על Webpack ומבנה פרויקט React, אני עדיין אעדיף להתחיל פרויקט חדש עם create-react-app וכשיגיע הזמן להפעיל eject ולהתחיל לתפעל את העניינים בעצמי. החיסכון בעבודה בהתחלה מאפשר לי לקפוץ מהר יותר לכתיבת הקוד, שזה מה שרציתי לעשות מלכתחילה.
כן חשוב להיות מיושרים וברורים מה אנחנו מנסים לחסוך ולוודא שמשתמשים בכלי הנכון. ספריית next.js היא דרך מעולה לחסוך עבודה בהקמת תשתית ל Server Side Rendering, אבל אם אתם לא מבינים איך SSR עובד יהיה לכם מאוד קשה לפתור בעיות שבוודאות יצוצו. מצד שני להבין איך המעבד עובד לא יהפוך אתכם למתכנתי Clojure טובים יותר, כי שפה פונקציונאלית כמו Clojure מגיעה עם עולם תוכן ועולם מושגים שלה.
כשמסתכלים על ספריה חדשה שווה לשאול קודם כל: "מה הכלי הזה אמור לחסוך לי?" ו"האם זה החיסכון שחיפשתי?"
1 419
# המקסימום האפשרי
אחד העקרונות הראשונים שלמדתי בבית ספר היה עיקרון ה"מינימום הנדרש". זה עיקרון ידוע של העולם התעשייתי שאומר שאם אפשר להגיע למטרה בפחות השקעה אז זה כדאי. לדוגמה מפעל שמצליח לייצר כסא בפחות השקעה יוכל להרוויח יותר על הכסא או להוריד את המחיר ולמכור יותר כיסאות.
וכך בתור תלמידים למדנו שאם אפשר ללמוד 10 שעות ולקבל 100 אז אין טעם ללמוד 20 שעות (כי ממילא לא תקבל יותר מ 100).
הבעיה מתחילה כשאנחנו מנסים להביא את העיקרון הזה לעולם העבודה. חברים מהדור שלי, ועוד הרבה יותר מזה המילניאלים, מגלים שרוב העבודות דורשות יצירתיות, מנהיגות ויכולת להמשיך ללמוד כל הזמן. אבל אפילו אלה מאיתנו שמצליחים למצוא עבודת בית-חרושת שבה אפשר להסתדר עם "המינימום הנדרש" מגלים מהר מאוד שהם לא יכולים להתמיד בה. גם אנחנו העובדים מרגישים את הריקנות בעבודה מסוג זה ומחפשים להתפתח.
יהיה נחמד אם בתי הספר של העתיד יתחילו ללמד ילדים על עיקרון "המקסימום האפשרי" - והוא העיקרון שבסביבות מתאימות, ככל שנשקיע יותר כך נקבל תוצאה יותר טובה. לדוגמה:
1. ככל שתלמדי יותר שפות תכנות, כך יהיה לך קל יותר ללמוד את השפה הבאה.
2. ככל שתבני יותר משחקים, כך יהיה לך קל יותר לבנות את המשחק הבא.
3. ככל שתעבירי יותר הרצאות כך תגיעי יותר מוכנה להרצאה הבאה.
לא בשביל הציון. לא בשביל המשכורת. לא בשביל הקידום. פשוט כי אפשר.
1 419
# פירוק כפול ב JavaScript
מתכנתי JavaScript רבים כבר יודעים לעבוד עם Destructuring כדי לשבור מערך למספר משתנים, לדוגמה הקוד הבא שומר ב x את הערך 10 וב y את הערך 20:
const [x, y] = [10, 20];
ב React אנחנו משתמשים במנגנון זה הרבה כשמפעילים את הפונקציה useState. הפונקציה מחזירה מערך ואנחנו רגילים לכתוב:
const [value, setValue] = useState("");
בעיה מעניינת בכתיב הזה מתגלה כשאנחנו רוצים ליצור משתנה שלישי שיכיל את המערך כולו, בנוסף לשני המשתנים לכל אלמנט. אם נחזור לריאקט אפשר לדמיין אלמנט Input שיקבל ב property משתנה State ופונקציית עדכון וישתמש בהם כדי לשמור את המידע בסטייט של הקומפוננטה שיצרה אותו. משהו בסגנון הזה:
function Input(props) {
const [value, setValue] = props.model;
return (
<input
type="text"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
}
function App() {
const model = useState("");
const [value, setValue] = model;
return (
<div>
<p>Hello {value}</p>
<Input model={model} />
</div>
);
}
ואחרי שראינו את זה בפעולה אפשר להמשיך ולשאול אם אפשר לקצר את שתי השורות הראשונות בקומפוננטה App? למשל האם אפשר לכתוב את הקוד הבא:
const model = [value, setValue] = useState("");
והתשובה מורכבת.
הקוד יעבוד (לפחות בחלק מסביבות ההרצה) אבל לא יעשה את מה שרציתם שהוא יעשה. בכתיב כזה המילה const משפיעה רק על המשתנה הראשון model, והמשתנים value ו setValue יהיו משתנים גלובאליים. לכן הקוד יעבוד בסביבות שמאפשרות הגדרת משתנים גלובאליים בלי var, const או let. בכל מקרה אנחנו יודעים שמשתנים גלובאליים ב JavaScript רק מביאים צרות ולכן גם אם הכתיב עובד לא מומלץ להשתמש בו.
מה כן אפשר? הגירסה הבאה עובדת ועושה בדיוק את מה שצריך, אבל לא בטוח שהיא יותר פשוטה מהגירסה הראשונה:
export default function App() {
const model = useState(""),
[value, setValue] = model;
return (
<div className="App">
<p>Hello {value}</p>
<Input model={model} />
</div>
);
}1 419
# בגרות באנגלית: חלק שני
בניסוי אתמול ראינו איך להוריד שאלוני בגרות באנגלית מהרשת ולשמור אותם על המחשב וגם להוציא את הטקסט מתוכם ולגלות סטטיסטיקה מעניינת על הטקסט באמצעות תוכנית פייתון.
היום אני רוצה להמשיך את הניסוי כדי ללמוד עוד כמה דברים על פיתון ועבודה עם טקסטים, ולקבל מידע יותר אמין על איזה מילים כדאי ללמוד לבגרות באנגלית.
אם לקחתם את הקוד אתמול ואולי ניסיתם להדפיס חלק מהמילים יכולתם לגלות שהמילים house ו houses נספרות כשתי מילים שונות, וכך גם go, goes ו going. בנוסף אולי שמתם לב ששמות כמו George, Bill ו Jane נספרו בתור מילים.
בואו נתקן את שתי הבעיות בעזרת ספריית nltk.
ספריית nltk או Natural Language Toolkit כוללת אינסוף פונקציות שעוזרות לנו לעבוד עם טקסטים בצורה נקיה ומאפשרת גישה לאינספור משאבים טקסטואלים שאפשר להתאמן עליהם כשכותבים תוכניות לניתוח שפה. אנחנו נשתמש בשתי יכולות של הספריה:
1. היכולת לבצע Stemming למילה, כלומר לקחת את המילים house ו houses, להבין שזו אותה מילה ולהחזיר את הצורה המקורית של המילה - house.
2. מאגר השמות הפרטיים שמגיע בתוך הספריה שיאפשר לנו לזהות האם מילה מסוימת היא שם פרטי.
את הספריה מתקינים עם:
pip install nltk
ובתוך התוכנית נשתמש בה עם ה import-ים הבאים:
from nltk.stem import PorterStemmer
from nltk.tokenize import word_tokenize
import nltk.corpus
נתחיל עם מאגר השמות. הקוד הבא שומר במשתנה all_names קבוצה של כל השמות שמופיעים במאגר של nltk:
names = nltk.corpus.names
all_names = set(names.words('male.txt') + names.words('female.txt'))
לפני שנוכל להריץ אותו נצטרך להתקין את מאגר השמות באמצעות כתיבה והרצת התוכנית הבאה:
import nltk
nltk.download('names')
בחזרה לקוד שלנו, החלק השני של התוכנית יהיה להשתמש בפונקציית stem כדי לזהות הטיות של מילה. הקוד הבא ממחיש את השימוש בפונקציה:
# import these modules
from nltk.stem import PorterStemmer
from nltk.tokenize import word_tokenize
ps = PorterStemmer()
# choose some words to be stemmed
words = ["program", "programs", "programer", "programing", "programers"]
for w in words:
print(w, " : ", ps.stem(w))
התוצאה של כל ההדפסות היא המילה program.
התוכנית שלי אחרי עדכון נראית כך:
import requests, textract, re, os.path
from functools import reduce
from nltk.stem import PorterStemmer
from nltk.tokenize import word_tokenize
import nltk.corpus
names = nltk.corpus.names
all_names = set(names.words('male.txt') + names.words('female.txt'))
index_url = 'https://meyda.education.gov.il/bagmgr/Ajax.ashx?search=1&sheelon=&miktzoa=16&safa=1&pagesize=10&page=1'
r = requests.get(index_url)
urls = [q["question"] for q in r.json()]
total_words = {}
ps = PorterStemmer()
s = requests.Session()
for url in urls:
m = re.search(r'([^/]+\.pdf)', url)
if m is None: continue
filename = m[0]
if not os.path.isfile(filename):
r = s.get(url)
with open(filename, 'wb') as f:
f.write(r.content)
text = textract.process(filename).decode('utf8')
words = [
ps.stem(w.lower()) for w in re.findall(r'\b[a-zA-Z_]+\b', text)
if w not in all_names
]
print(f"Test {filename} has {len(words)} different words")
total_words[filename] = set(words)
all_words = reduce(lambda acc, val: acc | val, total_words.values())
print(f"All tests had a total of {len(all_words)} different words")1 419
נ.ב. ניסויים מסוג זה הם שהופכים את לימודי התכנות למהנים הרבה יותר. כשאתם מוצאים רעיון שמעניין אתכם, אל תהססו להשתמש בפייתון כדי לבדוק אותו. גם אם זה לוקח זמן וגם אם זה לא בדיוק בחומר של הקורס - אלה הדברים הקטנים שעושים את ההבדל.
1 419
# אלף מילים
הבלשן הגרמני יהואכים גרזגא הרגיש שאנגלית היא שפה הרבה יותר מדי מסובכת בשביל לתפקד בתור שפה בינלאומית: חוקי הדקדוק שלה מטורפים, יש המון מילים ובואו לא נתחיל לדבר על הגייה. בשביל שיהיה לעולם יותר קל לתקשר, הוא המציא או יותר נכון גילה סוג-של-אנגלית בשם "אנגלית גלובאלית" או בקיצור BGE שמכילה רק את כללי הדקדוק הבסיסיים ביותר ודורשת לימוד רק של אלף מילים. הטענה היא שעם ה BGE אפשר יהיה לתקשר בכל העולם מספיק טוב כדי שיבינו אתכם ושאתם תבינו אותם.
אלף מילים נשמע לי יחסית מעט אז חשבתי לבדוק את זה מול נתונים אמיתיים. מאחר ואני יודע פייתון ומשרד החינוך מפרסם את כל בחינות הבגרות הישנות באינטרנט, חשבתי שיהיה מעניין לבדוק כמה מילים שונות צריך בשביל להיות מסוגלים להבין בחינת בגרות באנגלית, והאם כל שנה הם משתמשים במילים אחרות.
תוצאות? מיד אחרי הסקריפט שמחשב את הנתונים...
## איך למשוך את כל מבחני הבגרות הישנים בשפת Python
משרד החינוך מפרסם את כל מבחני הבגרות הישנים בתור קבצי PDF וגם מספק לנו API נחמד בעזרתו אפשר לגלות את הכתובת של כל שאלון. ה URL הבא מחזיר JSON עם כל המידע על מבחני הבגרות הישנים באנגלית:
index_url = 'https://meyda.education.gov.il/bagmgr/Ajax.ashx?search=1&sheelon=&miktzoa=16&safa=1&pagesize=20&page=1'
התוצאה היא מערך של אוביקטים שלכל אחד מהם יש מאפיין בשם question שמכיל URL לשאלון ספציפי. את ה URL מצאתי דרך דף השאלונים של משרד החינוך עצמו בעמוד הזה.
## איך למצוא כמה מילים שונות יש בכל שאלון
כל שאלון הוא קובץ PDF. ב Python הספריה textract יודעת להוציא את הטקסט מהמון קבצים שונים ובין השאר מ PDF-ים. השימוש בספריה הוא בסך הכל:
text = textract.process(filename).decode('utf8')
אחרי שיש לנו את הקטסט אנחנו יכולים לשבור אותו למילים עם ביטוי רגולארי:
words = [w.lower() for w in re.findall(r'\b[a-zA-Z_]+\b', text)]
שימו לב שהשתמשתי באותיות אנגליות בלבד כדי לא לקבל מילים בעברית ובערבית מדף ההוראות שפותח את הבחינה.
## הסקריפט המלא והתוצאות
זה הסקריפט המלא. בשביל להריץ תצטרכו להתקין את textract ו requests, ושימו לב שהתקנת textract על Windows דורשת כמה צעדים מסובכים אז לכו לפי ההוראות שם:
import requests, textract, re
index_url = 'https://meyda.education.gov.il/bagmgr/Ajax.ashx?search=1&sheelon=&miktzoa=16&safa=1&pagesize=20&page=1'
r = requests.get(index_url)
urls = [q["question"] for q in r.json()]
total_words = set()
s = requests.Session()
for url in urls:
m = re.search(r'([^/]+\.pdf)', url)
if m is None: continue
r = s.get(url)
filename = m[0]
with open(filename, 'wb') as f:
f.write(r.content)
text = textract.process(filename).decode('utf8')
words = [w.lower() for w in re.findall(r'\b[a-zA-Z_]+\b', text)]
print(f"Test {filename} has {len(words)} different words")
total_words.update(words)
print(f"All tests had a total of {len(total_words)} different words")
והתוצאות? עושה רושם שמשרד החינוך גם קרא את גרזגא כי אלף מילים יכסו את כל אוצר המילים שתצטרכו בשביל בגרויות באנגלית (לפחות לפי 20 השאלונים הראשונים ברשימה):
Test 16381.pdf has 721 different words
Test 16382.pdf has 674 different words
Test 16384.pdf has 760 different words
Test 16471.pdf has 855 different words
Test 16481.pdf has 885 different words
Test 16484.pdf has 622 different words
Test 16582.pdf has 812 different words
Test 16584.pdf has 759 different words
Test 16381.pdf has 755 different words
Test 16382.pdf has 632 different words
Test 16384.pdf has 691 different words
Test 16471.pdf has 961 different words
Test 16481.pdf has 900 different words
Test 16484.pdf has 710 different words
Test 16582.pdf has 840 different words
Test 16584.pdf has 810 different words
Test 16381.pdf has 772 different words
Test 16382.pdf has 661 different words
Test 16384.pdf has 660 different words
Test 16471.pdf has 933 different words
All tests had a total of 1232 different words1 419
# הדרך הכי טובה לאבד מוטיבציה
הדרך הכי טובה לאבד מוטיבציה היא להסתכל על התוצאות: האם הצלחתי לפתור את התרגיל? האם התקבלתי לעבודה? כמה אנשים עשו לי "לייק" בסטאק אוברפלו או האם ענו לי על ה Pull Request ששלחתי?
וזה גרוע גם אם התוצאה חיובית וגם אם שלילית.
כשהתוצאה שלילית, לדוגמה אם התחלתי קורס ואני לא מצליח לפתור את אחד התרגילים או אפילו את כולם, אני בקלות יכול לקבל את הרושם ש"זה לא בשבילי" ולוותר מהר מדי; כשבעצם הדבר הנכון לעשות הוא למצוא משימות שיותר מתאימות לרמה שלי ולהתקדם בקצב שלי.
למרבה ההפתעה גם תוצאה חיובית מביאה השפעה שלילית על המוטיבציה. תוצאה חיובית מקבעת דימוי עצמי ותפיסת עולם בה ההצלחה נמדדת לפי אירועים חיצוניים ומעודדת אותנו להסתכל על התוצאה והאישור החיצוני גם בהמשך. בסופו של דבר כשהתוצאה השלילית תגיע הנפילה רק תהיה יותר כואבת.
אז מה המסקנה? להתעלם לגמרי מהתוצאות? ללכת עם הראש בקיר בלי קשר להצלחה שלי? גם על זה אני לא ממליץ. אנחנו משתמשים בקלט חיצוני (תוצאות) כדי לשפר את התהליך באיטרציה עד שנגיע לקצב ולסוג הלימוד האופטימלי עבורנו.
ניקח דוגמה קונקרטית: נניח שהתחלתם ללמוד קורס Python כאן באתר וראיתם את כל הרצאות הוידאו של הפרק הראשון ואז אתם מגיעים לדף התרגיל הראשון, ושם נהיה לכם חושך בעיניים כי אתם לא מצליחים לפתור אפילו סעיף אחד. בהסתכלות רק על התוצאות אפשר להגיע למסקנה שהקורס לא בשבילכם או יותר גרוע שפייתון לא בשבילכם ולחתוך. אבל המתכנתת החכמה תגיד תסתכל על התוצאה - לא הצלחתי אף תרגיל - בתור עוד סימן בתהליך הלימוד. אני יודעת ש Python זה בשבילי. אני יודעת שבסוף אגיע לפתור את התרגילים האלה, אבל כנראה רצתי מהר מדי. ואז היא תיקח צעד אחורה ותתחיל לצפות בקורס מההתחלה, הפעם תוך כדי צפיה בהרצאות הוידאו היא גם תבנה אצלה את הקוד שבוידאו. אחרי זה היא תוכל למחוק את התוצאה ולבנות אצלה את הקוד מאפס בלי הוידאו. במהלך העבודה היא תוכל לרשום לעצמה שאלות או רעיונות לתרגילים פשוטים ולפתור אותם, ובסופו של תהליך שאולי ייקח חודשיים-שלושה היא תצליח לפתור את דף התרגילים הראשון והוא אפילו יראה לה פשוט.
מי מאתנו שעבר את מערכת החינוך גדל עם התחושה שיש זמן לימוד נורמלי וצורת לימוד נורמלית לכל נושא. אם לוקח לי יותר זמן או שאני צריך ללמוד בדרך אחרת אז זה סימן שהנושא אינו בשבילי. זה מסר הרסני ואנחנו צריכים לעבוד קשה כדי למחוק אותו מהראש. פה, עכשיו, בהייטק בארץ, יש מחסור אמיתי במיומנות. זאת לא תחרות וזה לא משנה כמה זמן ייקח לכם ללמוד. הדבר החשוב הוא להתמיד מספיק כדי להגיע לצד השני.
1 419
# לי זה לקח חודשיים
כשלמדתי Qt בפעם הראשונה לקראת פרויקט רציני ידעתי שאני צריך להגיע מוכן לפרויקט - לוחות הזמנים של הפרויקט היו קצרים ועדיף היה לצמצם כמה שאפשר את אי הוודאות לפני. הלקוח היה מספיק אדיב כדי להאמין בי שאצליח ואכן לפני תחילת הפרויקט השקעתי חודשיים מלאים רק בלימוד הפריימוורק.
במהלך החודשיים קראתי את כל התיעוד (ועוד כמעט כל חומר שמצאתי) וכתבתי עשרות תוכניות קטנות שמכסות צדדים שונים של הדבר אותו תכננו לבנות בפרויקט. וזה עבד, או לפחות עבד הכי טוב שאפשר היה בהתחשב בנסיבות. לפרויקט הגעתי מוכן ובשבועיים פיתוח הצלחנו לבנות משהו עובד. הלקוח היה מרוצה וגם אני.
בעקבות פירסום שראיתי לקורס Qt התחלתי לחשוב - החודשיים שהשקעתי באמת היו אפקטיביים, אבל האם היה אפשר לקצר אותם? האם קורס מרוכז היה עוזר לי להגיע לאותה רמה בהשקעה של 5 ימי עבודה בלבד?
הייתי מאוד רוצה לענות בחיוב. אבל איך שאני לא מסובב את הזיכרון אני לא רואה את זה קורה.
השעות שהשקעתי בדיבוג תוכניות לא היו לשווא: הן עזרו לי להבין איך מחפשים בעיות ב Qt ואיך בסוף למצוא פיתרונות טובים. הניסיונות לכתוב קוד בעזרת כלים לא מתאימים עזרו לי להבין מה מתאים למה ובסוף בפרויקט האמיתי להבין באיזה כלי כדאי לי להשתמש לכל בעיה. אפילו השעות שהשקעתי בהקמת הסביבה ופיתרון בעיות לכאורה טפשיות, הפכו אותי למיומן יותר כשהייתי צריך להתקין סביבה בפרויקט אמיתי. אם מישהו היה "חותך החוצה" מהלימוד את כל הזמנים האבודים ומצליח לקצר לי לכאורה רק את "הזמן האפקטיבי" הייתי מפסיד 90% מהלימוד.
לי זה לקח חודשיים, ואם אני צריך לבנות מסלול לימוד לחבר שיעזור לו ללמוד Qt זה בדיוק יהיה אורך המסלול (ואגב, בניתי מסלול כזה, קוראים לו קורס Qt פה באתר). אז מה בכל זאת אפשר לעשות עם קורס של 5 ימים? שני רעיונות:
1. אפשר לקחת את הקורס לפני שמתחילים ללמוד כדי לקבל כיוון של "מה זה בכלל" Qt. הקורס לא יחסוך את החודשיים, אבל הוא ייתן להם קונטקסט.
2. אפשר לקחת את הקורס אחרי החודשיים ולפני תחילת הפרויקט, כדי לוודא שלא פספסתי כלום ולעזור ליישר את אי ההבנות שעוד נותרו מהלימוד העצמי.
לוקח זמן לפתח מיומנות. האינטרס שלנו בתור מתכנתים הוא למצוא כמה שיותר זמן להשקיע בבניית המיומנות, במקום לחפש את "השיטה" שתקצר למינימום את הזמן הזה.
