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

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

פתרון AOC 2025 יום 4 (ומה קרה להערות)

12/12/2025

יום 4 של Advent Of Code הוא בסך הכל עוד גרסה של משחק החיים. אנחנו מקבלים קלט במטריצה שנראית בערך כך:

..@@.@@@@.
@@@.@.@.@@
@@@@@.@.@@
@.@@@@..@.
@@.@@@@.@@
.@@@@@@@.@
.@.@.@.@@@
@.@@@.@@@@
.@@@@@@@@.
@.@.@@@.@.

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

class Day4
  attr_accessor :map

  def initialize(fname)
    @map = {}

    File.read(fname).lines.each_with_index do |line, row|
      line.strip.chars.each_with_index do |char, column|
        map[[row, column]] = char
      end
    end
  end

  def part1
    map
      .filter {|k, v| v == "@" }
      .map {|k, v| [k, count_taken_neighbors(k), count_taken_neighbors(k) < 4 ] }
      .count {|(_, _, c)| c }
  end

  def part2
    removed = 0

    loop do
      next_remove_round = removable.keys
      break if next_remove_round.empty?

      removed += next_remove_round.size
      self.map = map.except(*next_remove_round)
    end

    removed
  end

  def removable
    map
      .filter {|k, v| v == "@" && count_taken_neighbors(k) < 4 }
  end

  def count_taken_neighbors((row, column))
    map.values_at(*neighbor_indexes(row, column)).filter {|v| v == "@" }.count
  end

  def neighbor_indexes(row, column)
    [
      [row-1, column-1],
      [row-1, column],
      [row-1, column+1],
      [row, column-1],
      [row, column+1],
      [row+1, column-1],
      [row+1, column],
      [row+1, column+1],
    ]
  end
end

if __FILE__ == $PROGRAM_NAME
  d = Day4.new('input.txt')
  pp d.part1
  pp d.part2
end

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

עכשיו לשאלה השניה מהכותרת - מה עם הערות? כל אחד חושב שהקוד שלו הוא שירה אבל האמת שרובכם בטח קוראים את הרובי הזה ולא מבינים מה רציתי מכם, מה זה הכוכבית בשם הפרמטר ל except, מה ההבדל בין size ל count, מה כל הקווים האנכיים ומהם המקרים הלא מטופלים. בעולם הישן הייתם יכולים להמשיך לחלום על תיעוד כי ממילא אף אחד לא כתב אותו. היום אפשר להדביק את הסקריפט הזה ל ChatGPT ולקבל את כל התמונה. זה מה שיוצא:

    # Day4
    #
    # This class loads a 2D grid of characters from an input file and performs two
    # computations ("part1" and "part2") on that grid. The grid is stored in a hash
    # mapping `[row, column]` coordinate pairs to single-character strings.
    #
    # The characters of interest are '@', which represent "taken" cells. The script
    # is effectively analyzing a grid of occupied/unoccupied positions and applying
    # neighbor-based rules to count or remove cells.
    #
    class Day4
      # @!attribute [rw] map
      #   @return [Hash{Array(Integer,Integer) => String}]
      #   A hash where keys are [row, column] coordinate pairs and values are
      #   characters from the input grid. This is the central data structure on
      #   which all computations operate.
      attr_accessor :map

      # Create a new grid from a filename.
      #
      # @param fname [String] path to the input file
      #
      # Reads the file line by line, strips whitespace, and inserts each character
      # into the `map` hash keyed by its (row, column) position. This establishes
      # the full input state for later analysis.
      def initialize(fname)
        @map = {}

        File.read(fname).lines.each_with_index do |line, row|
          line.strip.chars.each_with_index do |char, column|
            map[[row, column]] = char
          end
        end
      end

      # Compute Part 1's result.
      #
      # Part 1 counts how many '@' cells have **fewer than four '@' neighbors**.
      # The logic:
      #   1. Filter to only "taken" cells (value == '@')
      #   2. For each such cell, compute the number of '@' neighbors
      #   3. Count how many of those have < 4 neighbors
      #
      # @return [Integer] number of '@' cells with fewer than four '@' neighbors
      def part1
        map
          .filter { |_, v| v == "@" }
          .map { |k, v| [k, count_taken_neighbors(k), count_taken_neighbors(k) < 4] }
          .count { |(_, _, needs_removal)| needs_removal }
      end

      # Compute Part 2's result.
      #
      # Part 2 repeatedly removes removable '@' cells until none remain.
      # A cell is removable if it has fewer than four '@' neighbors (via #removable).
      #
      # This simulates a stabilizing pruning process: at each round, all currently
      # removable '@' cells are removed simultaneously. The process continues until
      # no '@' cell qualifies for removal. The method returns the number of cells
      # removed across all rounds.
      #
      # @return [Integer] total number of removed '@' cells
      def part2
        removed = 0

        loop do
          next_remove_round = removable.keys
          break if next_remove_round.empty?

          removed += next_remove_round.size
          self.map = map.except(*next_remove_round)
        end

        removed
      end

      # Determine which '@' cells are currently removable.
      #
      # A cell is removable if:
      #   - Its value is '@'
      #   - It has fewer than four '@' neighbors
      #
      # Used both by part1 (conceptually identical criteria) and part2 (for iterative
      # removal rounds).
      #
      # @return [Hash] subset of `map` containing only removable '@' entries
      def removable
        map
          .filter { |k, v| v == "@" && count_taken_neighbors(k) < 4 }
      end

      # Count how many neighbors of a given cell are '@'.
      #
      # @param row_column [Array(Integer,Integer)] the (row, column) location
      #
      # Uses #neighbor_indexes to obtain adjacent coordinates in an 8-connected
      # neighborhood, then counts the ones whose value in the map is '@'.
      #
      # @return [Integer] the number of occupied ('@') neighbors
      def count_taken_neighbors((row, column))
        map
          .values_at(*neighbor_indexes(row, column))
          .count { |v| v == "@" }
      end

      # Compute the 8 neighboring coordinates around (row, column).
      #
      # This includes diagonals:
      #
      #   (-1,-1) (-1,0) (-1,+1)
      #   ( 0,-1)   X    ( 0,+1)
      #   (+1,-1) (+1,0) (+1,+1)
      #
      # The returned coordinates may or may not exist in the map; callers handle
      # missing keys implicitly via Hash#values_at returning nil.
      #
      # @return [Array<Array(Integer,Integer)>] list of neighbor coordinate pairs
      def neighbor_indexes(row, column)
        [
          [row - 1, column - 1],
          [row - 1, column],
          [row - 1, column + 1],
          [row,     column - 1],
          [row,     column + 1],
          [row + 1, column - 1],
          [row + 1, column],
          [row + 1, column + 1],
        ]
      end
    end

    # If this file is run directly, load the puzzle input and print Part 1 and Part 2 solutions.
    if __FILE__ == $PROGRAM_NAME
      d = Day4.new('input.txt')
      pp d.part1
      pp d.part2
    end

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

על מה להסתכל

11/12/2025

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

  1. כמה טוב הספריה גדלה. משווים בין פרויקטים גדולים ובשלים בכל אחת מהספריות כדי להבין האם פרויקטים ב X נוטים להיות יותר קלים לתחזוקה מפרויקטים דומים ב Y.

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

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

  4. כמה מפתחים אני יכול למצוא לטכנולוגיה זו. כמה קל יהיה לי לגייס מפתחים לפרויקט.

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

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

פתרון בית ספר

10/12/2025

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

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

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

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

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

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

בואו נדבר על בדיקות ו AI

09/12/2025

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

השבוע אקח כיוון אחר לשיחה וארצה לדבר על הפוטנציאל.

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

היום עם AI אני מצליח לבצע את אותו Flow הרבה יותר מהר ועם תוצאות יותר אמינות. זה עובד ככה:

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

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

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

  4. לפעמים הוא מפספס Flow-ים ואז חוזרים על התהליך עם תוכנית בדיקות נוספת.

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

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

מוזמנים להצטרף בחינם נרשמים כאן:

https://www.tocode.co.il/talking_ai

אפילו AI לא הצליח לעזור לי ב CSS

08/12/2025

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

במקרים האלה ההבדל בין מפתחים אנושיים ל AI מאוד בולט (לפחות חלק מהמפתחים האנושיים. חלקנו עדיין מתעקשים להיות יותר AI מ AI):

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

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

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

  1. מה התכוונו לעשות פה עם ה CSS הזה?
  2. מנה את כל הגדרות העיצוב והסבר מה התרומה של כל הגדרה למטרה הכללית.
  3. הסבר איזה הגדרות עיצוב אפשר למחוק ומה יקרה לעיצוב אחרי כל שינוי.
  4. לוקחים צילום מסך, מוחקים את כל ה CSS ואז מבקשים שיכתוב CSS מסודר לצילום המצורף.

למי קראת מתקדם?

07/12/2025

בואו נדבר על "מתקדם". רוב המתכנתים שמסתכלים על ספריה בפעם הראשונה מחפשים את ה Getting Started ואת ה Tutorials (והיום אפילו זה לא, רק נותנים לקלוד לעבוד). ואז אנחנו פותחים דף תיעוד של ספריה כמו vue-i18n ויכולים מהר מאוד להבין איך להשתמש בספריה לפי התבנית הבאה:

const i18n = createI18n({
  locale: 'ja',
  fallbackLocale: 'en',
  messages: {
    en: {
      message: {
        hello: 'hello world'
      }
    },
    ja: {
      message: {
        hello: 'こんにちは、世界'
      }
    }
  }
})

אז הלכתי לקלוד, ג'מיני ו ChatGPT וביקשתי מכל אחד מהם לכתוב דמו קצר שמראה איך לשלב את vue-i18n ביישום שלי. התוצאה? כולם כתבו קוד שטוען את כל ההודעות בכל השפות בצורה סטטית לתוך קובץ ה JS כלומר מכניס את כל הטקסטים של כל השפות לבאנדל.

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

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

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

שלושה פתרונות ראשונים ל Advent Of Code 2025

06/12/2025

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

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

המשך קריאה

דברים שאני עושה היום אחרת בזכות ה AI

05/12/2025

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

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

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

  3. זורק קוד - תמיד אהבתי למחוק קוד אבל עכשיו עם AI אני אפילו הרבה פחות קשור אליו ממה שהייתי קודם. מימוש לא טוב? משהו לא מספיק ברור? לא נראה יפה? git restore ומנסים שוב. הקוד הספציפי איבד מחשיבותו. מימוש של פונקציה מיוצר בלחיצת כפתור. הקסם הוא בממשקים, בחיבורים, בתיעוד, במבנה הגדול יותר של המערכת.

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

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

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

למי צלצלו הפעמונים

04/12/2025

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

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

  2. מי מתעדף את התיקון - צריך להגיע לפרודקט בשביל להכניס פיצ'ר "הקטנת JavaScript"? זה עוצר ספרינט? נתפס ב Code Review? ואם שמתי לב אחרי המיזוג?

  3. מה בכלל צריך לתקן - מתקנים כל מה שזורק Warning? רק אם ה Warning ממש מפחיד? רק אם יש זמן?

יש היום המון מנגנונים אוטומטיים שצועקים עלינו כשהקוד מזייף וככל שיש יותר מהם כך אנחנו מפתחים המון מנגנונים שמאפשרים להתעלם מאותם מנגנונים אוטומטיים. שמים Husky? תוך רגע אנחנו מגלים איך לבטל אותו. חייבים לעבור בדיקות בשביל לדחוף גרסה? נשים את הבדיקה ב skip רק לגרסה הזו. אנחנו מתעלמים מהאזהרות כי הרבה מהן הן False Positives. מתוך 3 הודעות שקיבלתי היום ב Code Review מ AI שלושתן היו טעויות של ה AI וכולן בזבזו לי זמן יקר לקרוא ולהבין למה ה AI התכוון ולמה הוא טועה. באותו זמן קובץ ה JavaScript במערכת כבר עבר את ה 5 מגה ואף אחד כבר לא זוכר מתי האזהרה על זה התחילה להופיע.

כמה רעיונות שיכולים לעזור:

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

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

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

המטרה שלנו פשוטה - לפתח יותר מהר ועם פחות טעויות. מערכות תוכנה שצועקות על כולם על כל שטות לא עוזרות.

קוד שנראה טוב אבל הוא בעצם לא (היוש AI)

03/12/2025

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

כאן יש PR לפיצ'ר שביקשתי מקופיילוט לכתוב על פרויקט קוד פתוח שלי שנקרא לנגלטס. ביקשתי שיבנה מסך נגן שיראה שיר מיוטיוב ולידו את המילים, התרגום, טבלה עם אוצר מילים מהשיר ואפשרות להוריד את אוצר המלים לקובץ CSV: https://github.com/ynonp/langlets-rails/pull/71

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

המשך קריאה