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

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

מה זה API Gateway והאם גם אני צריך אחד

15/06/2021

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

בשביל להבין איך API Gateway מתפקד או למה צריך אותו, בואו נדמיין מערכת Micro Services של חנות דיגיטלית. במערכת יכולים להיות לנו הסרביסים הבאים:

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

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

  3. סרביס הזמנות ותשלומים.

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

  5. סרביס סטטיסטיקות שאחראי על איסוף סטטיסטיקות של תנועה באתר כדי לעזור ל Product לשפר את המערכת.

בתוך מערכת כזאת אפשר לדמיין קוד Front End שאחראי להצגת דף הבית של גולש שחוזר לאתר אחרי שכבר קנה מוצרים בעבר:

  1. הוא יצטרך לתקשר עם סרביס קטלוג המוצרים כדי לזהות איזה מוצרים "מקודמים" ומופיעים עכשיו בדף הבית.

  2. הוא יצטרך לתקשר עם סרביס ההמלצות, כדי לראות אם יש המלצות אישיות לאותו גולש.

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

  4. הוא יצטרך לתקשר עם סרביס הסטטיסטיקות כל פעם שמשתמש מבצע פעולה באתר.

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

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

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

הפיתרון לכל הבעיות נקרא API Gateway. זה לא כלי אלא תבנית פיתוח, ולמעשה יש המון כלים שיכולים לתפקד בתור API Gateway, והרבה פעמים נראה מערכות שמשלבות כמה מהם. בתבנית API Gateway אנחנו בונים שירות בכניסה למערכת שיחבר את כל הסרביסים שלנו, ובגלל זה לפעמים הוא נקרא גם Backend for Frontend.

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

אבל יש עוד כמה דברים ש API Gateway יכול לעשות:

  1. ה Gateway יוסיף "מזהה בקשה" לכל בקשה שנכנסת למערכת, וכל הסרביסים משתמשים במזהה זה בכתיבה ללוג. כך קל לנו להסתכל בלוג ולהבין איזה בקשות קשורות, גם בין סרביסים שונים.

  2. ה Gateway יוכל לטפל ב Caching של תשובות כדי להוריד עומס מהסרביסים הפנימיים.

  3. ה Gateway יוכל לטפל ב Rate Limit או לחסום בוטים.

  4. אם חלק מהסרביסים למטה, ה Gateway הוא במקום טוב לזהות את זה מהר ולהעביר את העומס לסרביסים אחרים.

  5. ה Gateway יוכל לתעדף משתמשים מסוימים באמצעות העברתם לסרביסים פנויים יותר.

רק בגלל שהחלטתם להשתמש ב API Gateway אל תחשבו שאתם נעולים לכלי אחד ספציפי או יחיד במערכת. אין בעיה להרים שרת NGINX או HAProxy בכניסה למערכת כדי לטפל ב Rate Limit, ומאחוריו שרת Express כדי לבצע Request Aggregation. הדבר החשוב הוא להסתכל על ה Gateway בתור סרביס שיכול להיות מורכב מכמה תחנות ואחראי על תחומי עבודה מסוימים.

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

יותר מדי כלים?

14/06/2021

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

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

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

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

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

איך לסגור את האתר בשבת עם Haproxy ו Lua

13/06/2021

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

טריק נחמד שאפשר לעשות עם haproxy הוא להרחיב אותו באמצעות Lua. באופן רגיל אנחנו יכולים להשתמש ב ACL-ים כדי לנווט בקשות לשירותים מסוימים לפי תוכן הבקשה, לדוגמה השורה הבאה בקובץ הקונפיגורציה:

http-request deny if { path -i -m beg /api/ } { src 10.0.0.0/16 }

תעצור בקשות שמגיעות מהרשת 10.0.0.0/16 ומיועדות לנתיב שמתחיל ב /api. או השורה הזאת:

redirect scheme https if !{ ssl_fc }

תשלח ללקוח HTTP Redirect אם הוא לא פנה ב HTTPS.

אבל הדבר הגדול באמת הוא שאנחנו יכולים להוסיף פונקציות כמו src ו path בעצמנו באמצעות קוד lua. לדוגמה קוד lua הבא:

core.register_fetches("dow", function(txn)
  return os.date("*t").wday
end)

מייצר ל Haproxy פונקציה חדשה בשם dow שמחזירה את היום בשבוע (מתחיל מ-1 ליום ראשון).

עכשיו נניח ששמרתי את קוד ה lua מהדוגמה בקובץ /usr/local/etc/haproxy/dow.lua, ונניח שיש לי שני שרתי אפליקציה על הרשת, אחד בשם web שמציג את התוכן האמיתי שלי והשני בשם closed שמציג דף שאומר שהאתר סגור כעת; אז אני יכול לכתוב את קובץ הגדרות ה haproxy.cfg הבא כדי לסגור את האתר בסופי שבוע:

global
  log /dev/log  local0
  log /dev/log  local1 notice
  user haproxy
  group haproxy
  daemon
  lua-load /usr/local/etc/haproxy/dow.lua

defaults
  log global
  mode  http
  timeout connect 10s
  timeout client 30s
  timeout server 30s
  option  httplog
  option  dontlognull

frontend default
  bind :80
  use_backend closed if { lua.dow() eq 6 } || { lua.dow() eq 7 }
  default_backend web

backend web
  server s1 web:80

backend closed
  server s1 closed:80

הבלוק המעניין הוא הבלוק frontend ובפרט השורות:

use_backend closed if { lua.dow() eq 6 } || { lua.dow() eq 7 }
default_backend web

הפונקציה lua.dow היא פונקציית ה lua שכתבתי שמחזירה את היום בשבוע, והשורה בבלוג הגלובל:

lua-load /usr/local/etc/haproxy/dow.lua

היא שהיתה אחראית לטעינת קובץ ה lua וציון הנתיב אליו.

מסתדר

12/06/2021

  • "איך אתה ב git?"
  • "מסתדר. יודע ליצור ענפים, לעשות קומיטים, למזג. מה שצריך אני עושה ומקסימום כשאני נתקע אני תמיד מוצא ב Stack Overflow את הדרך"

  • "איך אתה ב Java?"

  • "ב Java אני די טוב. כתבתי יישומי צד-שרת גדולים וגם תיקנתי בעיות ביצועים ונעילות ב DB. אני יודע לכתוב Design Patterns ומבין טוב ארכיטקטורה. אין לי בעיה להיכנס לכל מערכת ולכתוב איזה פיצ'ר שצריך".

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

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

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

  • "ובאיזה שפת תכנות את ממש מצטיינת?"

  • "מה את יודעת על שפת התכנות הזאת שרק מעטים יודעים?"

  • "איזה דבר גילית על שפת התכנות הזאת שממש הפתיע אותך?"

  • "איזה הרצאה הכי אהבת מהכנס המקצועי האחרון שהיה על טכנולוגיה זו? ולמה?"

  • "איך היית ממליצה למישהו חדש ללמוד את הטכנולוגיה הזו מאפס?"

  • "איזה טעויות כולם עושים בתחילת הדרך בטכנולוגיה זו, שאת כבר לא עושה?"

  • "ומה עשית כדי להכיר כל כך טוב את הטכנולוגיה הזו?"

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

למה צריך שורת פקודה כשיש GUI? (טיפ AWS)

11/06/2021

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

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

הפקודה:

$ aws dynamodb list-tables

מדפיסה JSON עם רשימת כל הטבלאות:

{
    "TableNames": [
        "Table1",
        "Table2",
        "Table3"
    ]
}

נשלח אותו ל jq כדי לקבל רק את השמות:

 AWS_PAGER="" aws dynamodb list-tables | jq '.TableNames[]'
"Table1"
"Table2"
"Table3"

ונמשיך עם xargs בשביל למחוק אחת אחת:

$ AWS_PAGER="" aws dynamodb list-tables | jq '.TableNames[]'| xargs -n 1 aws dynamodb delete-table --table-name

האם היה נחמד לקבל ממשק GUI יותר נוח מאמזון? ברור. ועדיין עדיף ללמוד לעבוד עם ה CLI מאשר לבזבז שעה על מחיקת אוביקטים וניווט ב GUI.

אונליין ואופליין

10/06/2021

עכשיו שהקורונה נגמרה מסתבר שאין שום קונפליקט בין אירועי אונליין לאופליין - לשניהם יש מקום.

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

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

והאופליין? כמות המיטאפים שמתוכננים החודש עם הכותרת "מפגש פרונטאלי ראשון אחרי הקורונה" וכמות האנשים שבאים אליהם מזכירה לנו שהרבה יותר קל לנו ליצור קשרים עם אנשים כשאנחנו איתם באותו מרחב פיזי, ושאנשים רבים התגעגעו לחוויה הזאת ומחפשים אותה. אם גם לכם זה היה חסר שווה להעיף מבט בלינק https://www.meetup.com/cities/il/tel_aviv-yafo/events/ ולראות אם יש אירוע שמעניין אתכם ומסתדר בשעות.

הוקס עם התניה

09/06/2021

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

function MyProjects () {
  const { data: user } = useSWR('/api/user')
  if (!user) {
    return 'loading...';
  }

  const { data: projects } = useSWR('/api/projects?uid=' + user.id)
  if (!projects) return 'loading...'

  return 'You have ' + projects.length + ' projects'
}

וזה חלום כי ה useSWR השני הוא בהפעלה "מותנית", לפעמים הוא יבוצע ולפעמים לא, וזה אסור לפי חוקי ה Hooks.

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

function MyUser() {
  const { data: user } = useSWR('/api/user')

  if (!user) {
    return 'loading...';
  }

  return (
    <MyProjects user={user} />
  );
}

function MyProjects () {
  const { user } = props;
  const { data: projects } = useSWR('/api/projects?uid=' + user.id)

  if (!projects) return 'loading...'

  return 'You have ' + projects.length + ' projects'
}

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

אופציה שניה וטובה יותר היא מה שעשו ב SWR ומה ששווה לבנות גם ב Hooks שלכם: הכנסת הלוגיקה לתוך ה Hook. ב SWR אפשר לכתוב את אותו הקוד כך:

function MyProjects () {
  const { data: user } = useSWR('/api/user')
  const { data: projects } = useSWR(() => '/api/projects?uid=' + user.id)
  // When passing a function, SWR will use the return
  // value as `key`. If the function throws or returns
  // falsy, SWR will know that some dependencies are not
  // ready. In this case `user.id` throws when `user`
  // isn't loaded.

  if (!projects) return 'loading...'
  return 'You have ' + projects.length + ' projects'
}

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

  if (typeof key === 'function') {
    try {
      key = key()
    } catch (err) {
      // dependencies not ready
      key = ''
    }
  }

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

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

סימניות

08/06/2021

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

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

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

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

כשצריך להקפיא קוד, בדיקה שנכשלת היא הסימניה הטובה ביותר.

שלוש שאלות (ותשובות) על תקיעות

07/06/2021

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

המשך קריאה

ניסיון אפקטיבי (או: מה ללמוד עכשיו)

06/06/2021

"אני מתכנת ווב. התחלתי לכתוב אתרים ב Perl/CGI עוד ב 1998, מעתיק קודים מהאינטרנט כדי להציג מונה ביקורים וכאלה. אחר כך למדתי JavaScript כדי להראות באנרים מהבהבים וזזים וכמובן CSS. את PHP לא אהבתי למרות שעבדתי איתו יחסית הרבה. החל מ 2010 אני מתכנת Front End כותב אך ורק קוד צד לקוח ב JavaScript, TypeScript וכמובן בכל ה Frameworks שהולכים היום."


"אני מתכנתת צד-שרת. התחלתי לכתוב שרתים ב EJB1 עוד ב 1998 ומאז עד 2010 המשכתי לכתוב XML-ים, לתרגם אותם ולשלוח אותם בין מערכות. כשהעולם כולו עבר ל JSON שמחתי להתחיל לכתוב חלקים קטנים באפליקציה ב Node.JS ולהחליף את ה Java ב Scala. היום אני מפתחת בעיקר Serverless על AWS כותבת פונקציות Lambda שעובדות הרבה יותר טוב מה EJB המסורבל מפעם."


"התחלתי לכתוב אפליקציות מובייל ב 2005 עם J2ME. הממשק היה קשוח ומעט מאוד אנשים חיפשו אפליקציות מובייל באותה תקופה, אבל אני שמח שהיה לי שכל לעבור לפתח לאייפון איך שיצא ומשם להמשיך לכתוב אפליקציות אנדרואיד (זה היה קל עם הניסיון שכבר היה לי ב Java). כשהגיע שיגעון ה Cross Platform הייתי צריך ללמוד JavaScript וכלים מוזרים כמו פונגאפ, אבל מהר מאוד זה עבר והמשכנו ל React Native ו Flutter. היום אני מפתח Flutter ומשלב קוד Cross Platform עם קוד Native בכל פלטפורמה כדי להגיע לחווית משתמש אופטימלית"


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

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