1 419
订阅者
-124 小时
-17 天
-130 天
帖子存档
1 419
# טיפ גיט: קומיט זה לא הסוף
השילוש הקדוש בעבודה עם גיט הוא רצף שמתכנתים מדקלמים כמעט מתוך שינה: add, commit ו push. ובעוד שיחסית אנשים מצליחים להשתמש ב git reset אחרי שעושים add לדבר הלא נכון, בקומיט הסיפור שונה לגמרי.
כמעט כל המתכנתים שראיתי שעובדים בגיט מרגישים שאחרי commit חייבים לעשות push.
בואו נפתח את זה יחד. כשאתם עושים קומיט אתם שומרים את הגירסא הנוכחית של הפרויקט שלכם בצד. יכול להיות שהגירסא ששמרתם טובה ושאתם רוצים להשתמש בה, אבל גם יכול להיות שעוד כמה רגעים תגלו שהיא לא כזו טובה. אולי יש איזו שגיאת כתיב שפספסתם, אולי איזו בדיקה הפסיקה לעבור ולא ראיתם. אולי אפילו יש עוד תיקון ששכחתם להכניס אבל צריך להיות שם.
שימו לב ל-4 קומיטים לדוגמא:
9a550c6 (HEAD -> master) actually this looks better in a class
e837614 changed some texts
3aa43e8 moved code to function
3785d2d intiial commit
ה diff בין הקומיט הישן ביותר לחדש ביותר נראה כך:
diff --git a/a.rb b/a.rb
index 15aaec7..de05881 100644
--- a/a.rb
+++ b/a.rb
@@ -1 +1,8 @@
-puts "hello world"
+class Greeter
+ def hi
+ puts "Hello World"
+ end
+end
+
+g = Greeter.new
+g.hi
במצב כזה מבט על לוג הפרויקט לא ממש עוזר לי להבין מה מבנה הקוד ומה קרה בכל שלב, אלא כולל הרבה מידע מיותר על שלבי ביניים שאולי עברו לי בראש בזמן שכתבתי את הקוד אבל אין להם שום חשיבות כשמסתכלים אחורה על ההיסטוריה.
מה שיפה בגיט זה שעד שלא עשיתי push אפשר לשנות בלי בעיה את מבנה וסדר הקומיטים ואף אחד לא ישים לב. הנה בפרויקט דוגמא הקטן שלי אני יכול לכתוב:
$ git reset --soft 3785d2d
$ git add .
$ git commit -m 'Changed code to use object oriented syntax'
וקיבלתי לוג הרבה יותר נקי:
6a4e1ad (HEAD -> master) Changed code to use object oriented syntax
3785d2d intiial commit
אני לא מפסיד כאן שום מידע כיוון שההתלבטויות שלי אם לכתוב את הקוד בתור פונקציה או באותיות קטנות או גדולות זה לא דברים שצריך לשמור אותם.
לכן הטיפ שלי להיום - לא קרה כלום אם עשיתם קומיט ושניה אחרי זה התחרטתם. קומיט אחד טוב עם הודעה מפורטת שמסבירה מה קרה שם ומה ההגיון עדיף בהרבה על 20 קומיטים שמתארים את כל מה שעבר עליכם באותו יום ולא עוזרים להבין מה קרה בקוד.
נ.ב. רוצים ללמוד יותר לעומק איך לעבוד ב git ולשחק עם קומיטים כאילו היו כדורי ג'אגלינג? יש לי קורס וידאו שתפור בדיוק עליכם. מתחילים כאן: https://www.tocode.co.il/bundles/git/1 419
# שלוש סיבות לשלב TypeScript בפרויקט ריאקט הבא שלכם
טייפסקריפט עשתה דרך ארוכה מאז יציאתה לאוויר העולם באוקטובר 2012, יחד עם כל עולם האינטרנט והפיתוח לאינטרנט. היום היא נתמכת בכל סביבות הפיתוח המרכזיות ובכל מערכות ההפעלה, אבל יותר חשוב מזה - בפרויקט ריאקט היא משתלבת עם התחביר של ריאקט כמו כפפה ליד. הנה שלוש סיבות לשלב TypeScript בפרויקט ריאקט הבא שלכם:
## היא תשמור עליכם מטעויות טפשיות, ורוב הזמן לא תפריע לעבוד
כשיש לנו מצד אחד את ההתקדמות של TypeScript בזיהוי הטיפוסים, ומצד שני את ריאקט שעוברת לכתיב של פונקציות ו Hooks - השילוב של TypeScript בפרויקט ריאקט הוא כמעט לא מורגש.
דוגמא טיפוסית לקומפוננטת TypeScript נראית כך:
import React, { useState } from "react";
export default function Person(props: {
name: string,
age: number
}) {
const { name, age } = props;
const canVote = age >= 18 ? "can" : "can't";
return (
<div>
<p>Hi! my name is {name} and I {canVote} vote</p>
</div>
)
}
נכון - הייתי צריך לספר ל TypeScript מה סוגי המשתנים שהגיעו ב Props, אבל זה מחיר קטן לשלם. התמורה אגב היא שבאופן אוטומטי TypeScript יודעת לבדוק שהעברתי את ה Props הנכונים איפה שצריך, ויודעת לשמור עליי כדי שלא אשתמש במידע בצורה לא נכונה. הקוד הבא לדוגמא לא יתקמפל:
function App() {
return (
<>
<Person age="18" name="bob" />
</>
)
}
## השלמות אוטומטיות יעבדו הרבה יותר טוב
אחת הבעיות שלי עם השלמה אוטומטית ב IDE היא שזה לא עובד. כלומר, ל IDE יש כוונות טובות ורוב הזמן הוא באמת מנסה להשלים את הפקודה, אבל תמיד יגיע הרגע שאתה מתחיל לכתוב משהו וההשלמה האוטומטית לא עובדת, ואז אין לך מושג אם זה בגלל שכתבת משהו לא נכון או בגלל שה IDE טועה.
ב TypeScript הבעיה הזאת כבר לא קורית: בזכות קבצי ההגדרות שמכסים כל היבט של שפת JavaScript, מאוד קל ל IDE לדעת בדיוק איזה שדות יש או אין לך על האוביקט ומה מותר לעשות איתם. אחרי המעבר ל TypeScript לא נצטרך יותר להתלבט אם לפונקציה שבודקת אם מחרוזת נמצאת בתוך מחרוזת אחרת קוראים includes או contains, או מה החתימה של useRef. הכל כבר קיים בתוך השפה.
## תוכלו ליהנות מתחביר חדש שעדיין לא הגיע ל JavaScript
אחרי המעבר ל TypeScript תוכלו ליהנות מאופרטור Optional Chaining שיחסוך לכם לבדוק כל פעם אם משהו הוא Null:
let x = foo?.bar.baz();
שזה בדיוק כמו לכתוב:
let x = (foo === null || foo === undefined) ?
undefined :
foo.bar.baz();
מאופרטור ה nullish coalescing שמתנהג ממש כמו || אבל בודק null במקום false, כך בשורה הבאה:
let x = foo ?? bar();
אם foo הוא null או undefined ניקח את הערך של bar, אבל אם foo הוא סתם false נשתמש בו. זו גירסא מתוחכמת יותר של || המאפשרת הגדרת ערכי ברירת מחדל למשתנים בוליאנים.
רוצים ללמוד עוד על TypeScript ו React ואיך הן עובדות יחד? ביום חמישי הקרוב אעביר כאן וובינר בנושא עם המון דוגמאות, תבניות נפוצות, בעיות שאתם עשויים להיתקל בהן ודרכי התמודדות. מוזמנים להצטרף בחינם בקישור: https://www.tocode.co.il/workshops/93.1 419
# שלבים לפיתרון בעיה
1. אני לא מבין מה רוצים ממני
2. אין לי מושג איך לגשת לזה
3. יש לי רעיון אבל אין לי מושג איך ליישם אותו
4. התחלתי ליישם את הרעיון אבל זה לא עבד - לא ברור לי למה
5. הבנתי למה הרעיון שלי לא עבד. עכשיו שוב אין לי שום רעיון.
6. ממשיכים את 2-5 בלולאה, לפעמים כמה עשרות פעמים. כל פעם לומדים עוד משהו על הבעיה ועל עוד דרך שלא עובדת.
7. הצלחתי ליישם פיתרון שעובד!
8. אה, אבל בעצם יש את מקרה הקצה הזה שלא חשבתי עליו.
9. יש לי רעיון איך לתקן את מקרה הקצה הבעייתי.
10. ממשיכים את 8-9 בלולאה, לפעמים כמה עשרות פעמים.
11. יש לי קוד שעובד!
12. מה המשימה הבאה?
הרבה פעמים אנחנו רוצים לדלג על הלולאות ב-6 וב-10, ומדמיינים שאם נצליח להגיע ל-11 זה סימן שלמדנו את הנושא, לא משנה איך הגענו לשם. אבל זה לא עובד ככה: עיקר הלימוד קורה בתוך הלולאות, ובחיפוש האינטנסיבי אחרי הרעיון הבא.
1 419
# בשביל מה את בונה את זה
אם המטרה שלכם היא לבנות מערכת כדאי מאוד להיעזר באיש מקצוע. למרות שפגשתי המון מתכנתים שמעדיפים ללמוד משהו בשביל לבנות בזה מערכת - כמעט תמיד התוצאה יוצאת הרבה יותר יקרה ופחות טובה ממה שהיינו מקבלים אם היינו לוקחים איש מקצוע שכבר מיומן בטכנולוגיה.
מצד שני אם המטרה היא ללמוד משהו חדש אז ברור שכדאי לבנות את התוכנה לבד ולנסות כמה שיותר רעיונות אפילו הכי הזויים שאתם יכולים לדמיין רק בשביל לראות מה עובד ומה לא. התחלנו את המסע הזה בשביל ללמוד וזה הולך להיות כיף בין אם תהיה מערכת בסוף ובין אם לא.
כשהמטרה היא לימודים ברור שדברים הולכים להסתבך, וברור שכמה שתשקיעי יותר זמן בהתמודדות עם ההסתבכויות את תלמדי טוב יותר.
הבעיות בחיים מתחילות כשאנחנו מתבלבלים בין המטרות שלנו, או כשיש התנגשות בין מטרות. לדוגמא - כשהבוס אומר שצריך לבנות מערכת חדשה ואנחנו רוצים ללמוד ריאקט. השילוב מייצר לחץ בלתי אפשרי, מצד אחד לבנות את המוצר הכי מהר שאפשר ולהוכיח שהבחירה שלנו היתה טובה, ומצד שני ללמוד תוך כדי תנועה ולקוות לקלוע במטרה כבר מהניסיון הראשון.
יותר קל להסתכל על החיים כמשחק לטווח ארוך: ללמוד כל הזמן טכנולוגיות חדשות עם פרויקטי צד ומערכות פחות חשובות, ולהיכנס לבצע פרויקטים אמיתיים וקריטיים לארגון רק בטכנולוגיות שכבר הגעתם איתן לרמת בשלות מסוימת.
1 419
# ארבעה רעיונות פשוטים לפרויקטים ב Arduino
התגובה הראשונה שאני מקבל מחברים כשאני מספר שקניתי ארדווינו היא סוג של פרצוף ושאלת "ומה אתה הולך לבנות עם זה?". ויש בזה משהו - כמעט כל דבר שתרצה לבנות מישהו כבר פיתח ומוכר די בזול. העולם נהיה כזה שאפשר לקנות כמעט כל גאדג'ט בגרושים. ובכל זאת יש כיף בלבנות דברים לבד, גם אם הם לא רובוטים תלת מימדיים או חלליות שטסות לירח. בקיצור אם נתקעתם עם ארדווינו ואתם מחפשים מה לעשות איתו, קבלו 4 רעיונות פשוטים שמורכבים אך ורק מנורות, נגדים וכפתורים ושיעזרו לכם להתאמן על תכנות וגם על חיבור מעגלים חשמליים:
## קלט סריאלי לנורת Led צבעונית
אם יש לכם נורת Led צבעונית תוכלו לבחור את הצבע שלה באמצעות הזרמת חשמל לרגל המתאימה (יש 3 רגליים שמייצגות את כמות האדום, ירוק וכחול בהתאמה). אחרי שתחברו ותבינו איך זה עובד נסו את התרגיל הבא: עדכנו את התוכנית כך שתקבל מהקלט הסריאלי קוד צבע, למשל
#872213 ואז תכוון את רמות האדום, ירוק וכחול כך שיוצג הצבע המתאים.
## מתג שמחליף בין 4 נורות
יודעים איך להדליק ולכבות נורת Led? מעולה, עכשיו קחו אתגר קטן נוסף וחברו 4 נורות Led וכפתור ל Arduino. הגדירו משתנה בתוכנית שיחזיק את הנורה שכרגע דולקת (ערכו זז מ-0 עד 3 ובחזרה ל-0), וכל לחיצה על הכפתור תעלה את המשתנה ב-1 וכך תחליף בין הנורה שכרגע דולקת.
זה נשמע פשוט אבל צריך לזכור בכל החלפה לכבות את הנורה הקודמת ולטפל במעגליות.
בונוס: במקום שהנורה הנוכחית תדלוק כל הזמן נסו לגרום לה להבהב.
## מונה לחיצות בינארי
יודעים לספור בבינארי? גם הארדווינו שלכם יודע. קחו את המעגל מהפרויקט הקודם ועדכנו את הקוד כך שלחיצה על הכפתור תציג בנורות את המספר הבינארי הבא - אפס מיוצג על ידי נורה כבויה ואחד על ידי נורה דולקת.
## משחק סיימון
האחרון בסידרה הוא סיימון כלומר משחק זיכרון מבוסס נורות. לוקחים את 4 הנורות שיש לנו ומוסיפים להן 4 כפתורים. בכל סיבוב המחשב מדליק ומכבה נורות לפי סדר אקראי (למשל צהוב, צהוב, כחול, אדום) וכשמסיים מגיע תור השחקן ללחוץ על הכפתורים שמתאימים לנורות שנדלקו.
יש לכם עוד רעיונות למשחקים פשוטים ומדליקים עם הארדווינו? ספרו בתגובות כדי שאוכל לבנות גם.1 419
# בואו נמצא סדרות של מספרים עוקבים ב Python
הנה שאלת ראיונות עבודה פשוטה שנתקלתי בה - נתון מערך של מספרים ואתם צריכים לכתוב קוד שימצא את הרצף הכי ארוך של מספרים עוקבים. לדוגמא במערך הזה:
arr = [1, 2, 3, 10, 2, 3, 4, 5, 6, 9, 9, 1, 2, 3, 1, 2, 3]
היינו רוצים לזהות שבאינדקס 4 של המערך יש רצף של 5 מספרים עוקבים, והוא הארוך ביותר מבין הרצפים במערך זה.
כשאני רואה כאלה שאלות האינטואיציה הראשונה שלי היא שכדאי להפריד בין הלוגיקה של "איפה יש רצפים" לבין הלוגיקה של חיפוש רצף ארוך ביותר. הראשונה כנראה ספציפית לשאלה ובשביל השניה בטח נוכל להשתמש במנגנונים קיימים של Python. במקרה שלנו אפשר לחשוב על המערך בתור אוסף של רצפים של מספרים עוקבים (חלקם ממש קצרים). במערך שבדוגמא נוכל למצוא את הרצפים הבאים של מספרים עוקבים:
(0, 3)
(3, 1)
(4, 5)
(9, 1)
(10, 1)
(11, 3)
(14, 3)
כל רצף מזוהה על ידי האינדקס בו מתחיל הרצף (המספר הראשון) ואורך הרצף (המספר השני). כך המערך מתחיל באינדקס 0 ברצף של שלושה מספרים עוקבים - המספרים 1, 2 ו-3 ואחריהם באינדקס 3 יש לנו רצף קצר יותר של מספר יחיד הוא המספר 10.
מרגע שזיהיתי שיש פה אוסף של רצפים אני יכול לקודד את הלוגיקה שמחפשת כאלה רצפים לפונקציה מסוג Generator, בואו נקרא לה consecutives. מימוש עשוי להיראות כך:
def consecutives(arr):
start = 0
i = start
while i < len(arr) - 1:
if arr[i] + 1 == arr[i + 1]:
i += 1
else:
yield(start, i - start + 1)
start = i + 1
i = start
yield(start, i- start + 1)
ואחרי שיש לנו את הפונקציה קל למצוא את כל הרצפים עם לולאת for רגילה:
for seq in consecutives(arr):
print(seq)
או למצוא את הרצף הכי ארוך עם פונקציית max:
print(max(consecutives(arr), key=lambda s: s[1]))
או למצוא את הרצף שסכום האיברים בו הוא הגדול ביותר (שוב עם max):
print(max(consecutives(arr), key=lambda s: sum(arr[s[0]:s[0]+s[1]])))
והתבנית שכדאי לזכור מכאן - הרבה פעמים שווה לנו להתאמץ לשנות קצת את הבעיה כדי שנוכל לפתור אותה בכלים שאנחנו כבר מכירים.1 419
# היום למדתי: למה חשוב לכתוב distinct כשסופרים ב SQL
הפוסט הבא הוא יותר תזכורת בשבילי מאשר בשבילכם, למרות שאם אתם כותבים SQL יכול להיות שגם לכם זה יבוא בהפתעה. מסתבר שהשאילתה הבאה לא עובדת טוב בכלל:
SELECT courses.*, count(lessons.id) as lessons_count,
count(course_labels.id) as labels_count
FROM "courses"
LEFT OUTER JOIN "course_labels" ON "course_labels"."course_id" = "courses"."id"
LEFT OUTER JOIN "lessons" ON "lessons"."course_id" = "courses"."id"
GROUP BY courses.id
סיפור הרקע הוא שיש לנו טבלת קורסים, טבלת שיעורים וטבלת תוויות. בכל קורס יש הרבה שיעורים ולכל קורס יש גישה להרבה תוויות דרך טבלת חיבור בשם course_labels. המטרה של השאילתה היא להוציא במכה אחת את כל הקורסים, יחד עם מספר התוויות שיש לכל קורס, יחד עם מספר השיעורים שיש בכל קורס.
הבעיה עם השאילתה היא שה join הכפול גורם לשכפול של כל השורות בטבלה השניה - במילים אחרות כך נראית התוצאה כשאני מוריד את ה count וה group by:
sqlite> SELECT courses.id, lessons.id as lessons_count, course_labels.id as labels_count_1 FROM "courses" LEFT OUTER JOIN "course_labels" ON "course_labels"."course_id" = "courses"."id" LEFT OUTER JOIN "lessons" ON "lessons"."course_id" = "courses"."id";
id|lessons_count|labels_count_1
1|1|6
1|2|6
1|3|6
1|5|6
2|4|
3||
ה id של ה course_label היחיד במערכת הבדיקה שלי הוא 6, והוא מופיע 4 פעמים כדי להתאים ל-4 שיעורים שיש בקורס.
הפיתרון במקרה של ספירה הוא ממש פשוט ומורכב מהמילה היחידה distinct. הנה השאילתה המתוקנת:
SELECT
courses.*,
count(distinct lessons.id) as lessons_count,
count(distinct course_labels.id) as labels_count_1
FROM "courses"
LEFT OUTER JOIN "course_labels" ON "course_labels"."course_id" = "courses"."id"
LEFT OUTER JOIN "lessons" ON "lessons"."course_id" = "courses"."id"
GROUP BY courses.id1 419
# קוד חכם מדי. קוד טיפש מדי.
קוד חכם מדי עושה את העבודה אבל צריך להכיר יותר מדי דברים בשביל להבין אותו והרבה אנשים לא יצליחו לתחזק אותו. דוגמת ריילס קצרה מקורס שהעברתי היום כללה טבלא של משתמשים, טבלא של קורסים וטבלא של שיעורים. כל שיעור שייך לקורס וכל קורס שייך למשתמש. השאלה היתה למצוא את רשימת השיעורים של משתמש מסוים, והתשובה החכמה מדי נראית כך:
Lesson.joins(course: :user).select('lessons.*', 'users.id as user_id').where('user_id = ?', user.id)
בשביל להבין את הקוד צריך להכיר מספיק טוב את joins בשביל להבין שיש פה join של שלוש טבלאות. נכון שזה מאוד גנרי ואפשר היה בקלות לבחור כאן משתמשים גם בהתבסס על תנאים אחרים, או אפילו לסנן לפי פרטים של הקורס, אבל כל החוכמה הזאת לא קשורה לשאלה.
גישה הרבה יותר מדויקת תיראה כך:
Lesson.where(course: user.courses)
קוד טיפש מדי עושה את העבודה כמו שצריך אבל לא מכסה את כל המקרים. הביטוי הרגולרי הבא הוא דרך טיפשה מדי כדי לזהות אם מילה מתחילה באות גדולה (שוב ברובי, למרות שביטויים רגולאריים עובדים בכל השפות):
word =~ /^[A-Z]/
זה עובד עבור מילים באנגלית, אבל לא מכסה את כל המקרים ויפול כשנעבור לשפה אחרת. קוד מדויק יותר נראה כך:
word =~ /^\p{Lu}/
והבעיה עם קוד שהוא מדבק: כשיש לכם קוד טיפש מדי במערכת אתם נוטים להגיד שממילא המערכת לא מטפלת במקרים מסוימים אז אפשר להמשיך לכתוב קוד טיפש שמתעלם מאותם המקרים גם במקומות אחרים, וכשיש לכם קוד חכם מדי במערכת אתם לא מבינים אותו ופשוט מעתיקים אותו לעוד מקומות שצריכים דברים דומים בשינויים קטנים.
גם אם הקוד עובד - כשהוא טיפש מדי, או חכם מדי, שווה להתאמץ ולתקן.1 419
# ומה תעשה כשזה נשבר?
יש ציטוט מפורסם שהאינטרנט טוען שהגיע מוורן באפט לפיו "רק בשפל אפשר לגלות מי שוחה בלי בגד ים". האנלוגיה (אם הבנתי נכון את המשפט) היא לעולם ההשקעות שם כשהכל הולך טוב כולם מרוויחים אבל רק כשהבורסה נופלת נוכל לגלות מי באמת מנהל נכון את הכסף שלו.
סיפור דומה אפשר לספר גם על קוד - הרבה אנשים יודעים ללכת לפי Tutorials ברשת, ויש אפילו לא מעט אנשים שיצליחו לבנות מערכת כשהכל הולך לפי התוכנית, אבל הכיף האמיתי קורה כשדברים לא עובדים כמו שכתוב בספר.
הדבר הראשון שכולם עושים כשמגיעים לשגיאה שאף פעם לא ראינו הוא להעתיק את השגיאה לגוגל ולקוות שמישהו ב Stack Overflow פתר אותה. הכיף האמיתי הוא המחקר שקורה אחרי: במקום לנסות לזרוק על הבעיה שלכם את כל הפיתרונות שמצאתם ב Stack Overflow ולקוות שאחד מהם יעבוד, עדיף להתיחס לכל פיתרון בתור ציון דרך או רמז, לקרוא וללמוד יותר טוב מה הבעיה שהכותב נתקל בה והאם היא דומה לבעיה שלכם, ואיך הפיתרון המוצע פותר את הבעיה ההיא.
המתכנתים הכי טובים שאני מכיר מחפשים בנרות את המקומות האלה שהקוד נשבר או שדברים לא ברורים קורים - אלה ההזדמנויות הכי טובות שלנו ללמוד יותר לעומק על המערכת.
1 419
# משתנים ב Ruby שאפשר לגשת אליהם מכל מקום
שפת רובי מציעה 3 דרכים לייצר משתנה גלובאלי - כלומר משתנה שאפשר לגשת אליו מכל מקום בתוכנית. הנה ה-3 בקצרה עם הצעה מתי להשתמש בכל דרך.
## קבועים
בכל מקום בתוכנית רובי תוכלו להגדיר קבוע, והקבוע שלכם יהיה נגיש מכל מקום אחר בתוכנית. כשמגדירים קבוע בתוך קלאס ורוצים לגשת אליו מבחוץ עליכם לציין את שם הקבוע המלא כלומר את שם הקלאס בתוכו הוא מוגדר, אחריו פעמיים נקודותיים ואז שם הקבוע.
קבוע ב Ruby נראה כמו משתנה אבל מתחיל באות גדולה, למרות שבדרך כלל נכתוב את כל שם הקבוע באות גדולה. רובי עצמה לא עושה מאמץ כדי למנוע מכם לשנות קבוע (ובגלל זה השם קצת מבלבל), אבל אנחנו מתכנתים טובים ולכן נשתדל לא לשנות קבועים.
התוכנית הבאה מגדירה קבוע מחוץ לפונקציה וניגשת אליו מתוך הפונקציה:
PASSWORDS = {
'one' => 'secret',
'two' => 'number'
}
def check_password(username, password)
PASSWORDS.key?(username) && PASSWORDS[username] == password
end
## משתנים גלובאליים
אם התחשק לכם לשנות את הקבועים שלכם תשמחו לשמוע שלרובי יש תמיכה במנגנון שנקרא משתנים גלובאליים אבל אף אחד לא באמת משתמש בו. משתנה גלובאלי ברובי מתחיל בסימן דולר, אפשר להגדיר אותו בכל מקום בתוכנית ולהשתמש בו מכל מקום אחר. מעט השימושים במשתנים אלה הם במשתנים הגלובאליים של השפה עצמה, לדוגמא המשתנה $_ יקבל בצורה אוטומטית מ gets כל פעם שהיא מופעלת את הערך האחרון שהיא קראה מהמשתמש.
התוכנית הבאה מגדירה משתנה גלובאלי ברובי ומשנה אותו מתוך פונקציה:
$count = 0
def tick
$count += 1
end
tick
tick
tick
puts $count
והתוכנית הבאה נעזרת ב $_ כדי לחסוך משתנה:
while gets
next if /^d/
print
end
התוכנית תדפיס את כל השורות פרט לאלה שמתחילות ב d: תחילה היא לוקחת טקסט מהמשתמש באמצעות gets. הטקסט יישמר אוטומטית במשתנה הגלובאלי $_, לאחר מכן היא בודקת אם $_ מתאים לביטוי הרגולרי (ואם כן מדלגת לקרוא עוד שורה) ולבסוף מדפיסה את תוכן המשתנה $_. וכן אם זה נשמע לכם קצת כמו השראה מפרל אתם כנראה צודקים.
## משתני מחלקה
הדרך השלישית והמקובלת ביותר לשמור מידע גלובאלי היא באמצעות משתני מחלקה, מה שקוראים במקומות אחרים משתנים סטטיים. הנה גירסא נוספת לקוד שסופר כמה פעמים פונקציה הופעלה הפעם עם משתנה מחלקה:
class Ticker
@count = 0
class << self
attr_accessor :count
end
end
def tick
Ticker.count += 1
end
tick
tick
tick
puts Ticker.count
מבנה זה נותן לנו את השליטה הטובה ביותר בקוד: במידת הצורך נוכל לכתוב לבד את פונקציות ה Setter וה Getter ולשלוט בגישה מבחוץ למשתנים הגלובאליים שלנו. בנוסף העובדה שכל משתנה מקבל תחילית של שם המחלקה שקשורה אליו עוזרת לסדר את המשתנים בתוך התוכנית.