ar
Feedback
ToCode

ToCode

الذهاب إلى القناة على Telegram

טיפים קצרים למתכנתים מאת ינון פרק

إظهار المزيد
1 419
المشتركون
لا توجد بيانات24 ساعات
لا توجد بيانات7 أيام
-530 أيام
أرشيف المشاركات
ToCode
1 419
setState(() {
      _counter--;
    });
  }

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter Counter Example'),
      ),
      body: Center(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            IconButton(
              icon: const Icon(Icons.remove),
              onPressed: _decrementCounter,
            ),
            SizedBox(
              width: 100,
              child: TextField(
                controller: TextEditingController(text: _counter.toString()),
                textAlign: TextAlign.right,
                readOnly: true,
                decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                ),
              ),
            ),
            IconButton(
              icon: const Icon(Icons.add),
              onPressed: _incrementCounter,
            ),
          ],
        ),
      ),
    );
  }
}
אני לא יודע אם זה קלוד או שככה dart, אבל גירסת הפייתון נראית הרבה יותר טוב.

ToCode
1 419
חמש דקות עם flet עם כל האהבה לריאקט אני חייב להודות שלא הצלחתי ליהנות מכתיבת קוד React Native. תמיד היה יותר מדי Boilerplate ודברים לא עבדו מספיק כמו שרציתי או שלא נראו מספיק טוב על מכשירים שונים. אני יודע שיש המון אפליקציות טובות שכתובות בריאקט נייטיב ובטוח שהבעיה זה קודם כל אני אבל זה מה שיש ואני חושב שאני לא היחיד בסיפור הזה. מצד שני הרבה זמן גם התרחקתי מפלאטר בעיקר כי לא היה לי כח ל dart. לכן שמחתי למצוא לאחרונה את flet, סביבה לפיתוח יישומי flutter ב Python. הקוד יצא הרבה יותר נקי וממוקד בהשוואה למה שזכרתי את dart וכמעט לא היו התקנות. ככה זה עובד- התקנה ותוכנית ראשונה אני מפעיל PyCharm נכנס לתפריט החבילות ומתקין את החבילה flet. עכשיו יוצר קובץ חדש ומדביק את התוכן הבא (רובו מהתיעוד באתר של פלט עם תיבת טקסט שאני הוספתי):
import flet as ft


def main(page: ft.Page):
    page.title = "Flet counter example"
    page.vertical_alignment = ft.MainAxisAlignment.CENTER

    txt_number = ft.TextField(value="0",
                              text_align=ft.TextAlign.RIGHT,
                              width=100)

    def minus_click(e):
        txt_number.value = str(int(txt_number.value) - 1)
        page.update()

    def plus_click(e):
        txt_number.value = str(int(txt_number.value) + 1)
        page.update()

    page.add(
        ft.Row(
            [ft.Text("Counter Example", size=18)],
            alignment=ft.MainAxisAlignment.CENTER,
        ),
        ft.Row(
            [
                ft.IconButton(ft.icons.REMOVE, on_click=minus_click),
                txt_number,
                ft.IconButton(ft.icons.ADD, on_click=plus_click),
            ],
            alignment=ft.MainAxisAlignment.CENTER,
        )
    )

ft.app(main)
קראתי לקובץ demo1.py ונכנסתי למסוף בתוך ה pycharm. בתוך המסוף כתבתי:
flet run -r demo1.py
זה הספיק ל flet בשביל להציג ממשק גרפי על המסך שכלל תיבה עם מספר ושני כפתורים סביבה, אחד לפלוס ושני למינוס. לחיצות על הכפתורים כמובן שינו את המספר. כששיניתי את הקוד באופן אוטומטי הממשק על המסך התרענן כדי לשקף את הקוד החדש. אמריקה. אחרי זה יצאתי מהתוכנית וכתבתי במסוף:
flet run --web -r demo1.py
וזה הספיק בשביל ש flet יפתח שרת פיתוח, יריץ דפדפן שיתחבר אליו ויציג לי בדיוק את אותו ממשק בתוך הדפדפן. כמו שאמרתי - אמריקה. מאחורי הקלעים צריך להגיד, החבר'ה ב flet קצת מרמים. הם לא מתרגמים את הפייתון שלנו לפלאטר אלא משתמשים בפלאטר כדי להציג ממשק משתמש שבגדול נוצר דרך הפייתון שלנו. במלים אחרות: 1. הארכיטקטורה היא ממשק משתמש מרונדר בשרת. 2. יש שרת שזה יישום שכתוב ב go והוא מקבל JSON-ים שמתארים את ממשק המשתמש. 3. יש לקוח שזה אפליקציית פלאטר שמחוברת לשרת וקוראת ממנו איזה ממשק להציג. 4. שרת ה go מריץ את קוד הפייתון, הפייתון מעביר את ה JSON-ים ל go, ה go מייצר הגדרות פלאטר ושולח אותן לאפליקציית ה client. בצורה כזאת בפייתון אנחנו עובדים עם רכיבי UI של flet ולא רכיבים רגילים של פלאטר. כן פלאטר שם אבל הוא מוחבא טוב. מצאתי לא מעט התלהבות ברשת מ flet וגם מהמעט ששיחקתי איתו הכל עבד חלק ומהר, אבל אי אפשר להתבסס על "פלאטר" ולחשוב שאם אפשר לבנות משהו בפלאטר אז בטוח אפשר יהיה לבנות את זה ב flet. המטרה של flet היא בנייה מהירה של ממשקים לאפליקציה שכבר יש לכם, תוך שימוש בכלים ובסביבת העבודה הרגילה שלכם. השוואה ל dart ופלאטר אמיתי אני מודה שזכרתי ש Dart היתה שפה מאוד מסורבלת אז בשביל המשחק הלכתי ל Claude וביקשתי שיתרגם לי את הקוד ל dart. זה מה שקיבלתי:
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Counter Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _decrementCounter() {

ToCode
1 419
תרגיל SQL - מחיקת שורות כפולות נתונה טבלה עם פריטים שנוצרה על ידי הפקודה:
create table items(id integer primary key, name text);

INSERT INTO items (name) VALUES
    ('Item A'),
    ('Item B'),
    ('Item C'),
    ('Item A'),
    ('Item D'),
    ('Item E'),
    ('Item B'),
    ('Item F'),
    ('Item G'),
    ('Item A'); 
מחקו את כל השורות הכפולות, כלומר השאירו מקסימום שורה אחת לכל שם של פריט. פיתרון התרגיל הזה היה נראה לי ממש פשוט בקריאה ראשונה אבל אחרי זה כשהתחלתי לכתוב את הקוד זה הסתבך, אני לא יודע אם הבעיה היא אני או SQL אז מפרסם כאן עם הפיתרון שלי. אם יש לכם כיוונים פשוטים יותר אל תתביישו לשתף. התחלתי את הפיתרון עם row_number ו partition וככה אפשר לראות בקלות ערכים כפולים - אלה שה row_number אצלכם גדול מ-1:
select
    id,
    name,
    row_number() over (partition by name) as rn
from items
עכשיו בשביל להציג רק את המזהים של השורות הכפולות צריך להשתמש ב rn בתוך תנאי where, וזה דורש הגדרת CTE. סך הכל כך אני מציג את השורות הכפולות בלבד (מלבד הראשונה):
with items_rn as (
  select
    id,  
    name,
    row_number() over (partition by name) as rn
  from items)
select id from items_rn where rn > 1
ואפילו זה לא הסוף כי בשביל למחוק אותן צריך להשתמש בכל הבלוק הזה בתור sub query, מה שמביא אותנו ל:
delete from items where id in

(with items_rn as (
  select
    id,
    name,
    row_number() over (partition by name) as rn
  from items)
select id from items_rn where rn > 1);

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

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

ToCode
1 419
ספריות בסיסי נתונים וטיפול בהבדלים בין בסיסי הנתונים ב Rails יצרתי טבלה בבסיס הנתונים עם קוד שנראה בערך כך:
create_table :users do |t|
  t.string :username
  t.string :email
  t.timestamps
end
את הקוד הזה אפשר להפעיל מול כל בסיס נתונים וריילס כבר יבין לבד מה לעשות ואיך להתאים בין string ו timestamps לסוגי הנתונים של בסיס הנתונים הספציפי שבחרתם. גם סיקוולייז של node עובדת בצורה דומה ב Sequelize הממשק דורש יותר קוד אבל עדיין הספריה מטפלת בהבדלים בין בסיסי נתונים:
'use strict';

module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.createTable('Users', {
      id: {
        type: Sequelize.INTEGER,
        autoIncrement: true,
        primaryKey: true,
        allowNull: false
      },
      username: {
        type: Sequelize.STRING,
        allowNull: false
      },
      email: {
        type: Sequelize.STRING,
        allowNull: false
      },
      createdAt: {
        type: Sequelize.DATE,
        allowNull: false,
        defaultValue: Sequelize.NOW
      },
      updatedAt: {
        type: Sequelize.DATE,
        allowNull: false,
        defaultValue: Sequelize.NOW
      }
    });
  },

  down: async (queryInterface, Sequelize) => {
    await queryInterface.dropTable('Users');
  }
};
ספריות בסיסי נתונים מודרניות יותר לוקחות גישה שונה. זו דוגמה מהתיעוד של דריזל ליצירת טבלה:
export const users = mysqlTable('users', {
  id: bigint('id', { mode: 'number' }).primaryKey().autoincrement(),
  fullName: varchar('full_name', { length: 256 }),
}, (users) => ({
  nameIdx: index('name_idx').on(users.fullName),
}));
וזו מיגרציה בקיסלי שכתובה בצורה מפורשת עבור Postgresql:
  await db.schema
    .createTable('person')
    .addColumn('id', 'serial', (col) => col.primaryKey())
    .addColumn('first_name', 'varchar', (col) => col.notNull())
    .addColumn('last_name', 'varchar')
    .addColumn('gender', 'varchar(50)', (col) => col.notNull())
    .addColumn('created_at', 'timestamp', (col) =>
      col.defaultTo(sql\now()\).notNull(),
    )
    .execute()
למה הם עושים את זה? ומה עדיף? יש שני יתרונות לספריה שלא מטפלת בהבדלים בין בסיסי נתונים - הראשון הוא גודל הספריה, או יותר נכון הקוטן שלה. ספריה שצריכה לעשות פחות תהיה יותר קטנה, קלה יותר לתחזוקה ופיתוח ותוכל לאמץ פיצ'רים חדשים מהר יותר. אני מודה שאם אני הייתי כותב ספריית גישה לבסיס נתונים גם הייתי מעדיף לוותר על הקוד שמטפל בהבדלים בין בסיסי הנתונים ולחסוך המון כאב ראש. היתרון השני הוא השליטה שספריה כזאת יכולה לאפשר למתכנתים - שבגלל שעכשיו כותבים קוד ספציפי לבסיס נתונים יכולים להרגיש יותר בנוח להשתמש ביכולת מתקדמות יותר של בסיס נתונים ספציפי, לדוגמה אם אנחנו יודעים שאנחנו עובדים בפוסטגרס נוכל להשתמש בכל הפונקציות של פוסטגרס לעבודה עם JSON-ים. השאלה הפתוחה כאן היא באיזו מידה אנחנו צריכים או משתמשים באותו קוד ספריה שמטפל בהבדלים בין בסיסי נתונים, או האם בכלל אפשר לדמיין להחליף בסיס נתונים ושכל הקוד פשוט ימשיך לעבוד. לדעתי היכולת להחליף בסיסי נתונים יכולה לעזור בתחילת הפיתוח אם אנחנו עדיין לא בטוחים איזה בסיס נתונים יהיה הטוב ביותר עבור הפרויקט, אבל ככל שהפיתוח מתקדם מהר מאוד אנחנו משלבים ממילא יכולות ספציפיות של בסיס נתונים ומאבדים את היכולת לעבור. יש סיכוי מאוד נמוך שמישהו ירצה לקחת פרויקט פרודקשן ולהעביר אותו לבסיס נתונים מסוג אחר. אנחנו כן כמפתחים עובדים על מספר פרויקטים ופרויקטים שונים כן עובדים על בסיסי נתונים שונים, לכן מפתחי Rails יכולים לעבור בין פרויקט Rails שמתחבר ל MySQL לפרויקט ריילס שמתחבר לפוסטגרס ולהשתמש בידע שלהם בריילס כדי לתחזק ולפתח את המערכת, כמעט בלי שיצטרכו ללמוד דברים חדשים. מה דעתכם? יצא לכם להעביר פרויקט בין בסיסי נתונים, או לעבוד באותו זמן על פרויקטים שמתחברים לבסיסי נתונים מסוגים שונים? כמה חשוב לכם שספריית בסיסי הנתונים שלכם תעבוד בצורה זהה בין בסיסי הנתונים השונים ותסתיר מכם את ההבדלים ביניהם?

ToCode
1 419
טיפ Hono שימו לב לנתיבים שלא מסתיימים בלוכסן את הקוד הבא לקחתי מתוך התיעוד של hono כדי להגיש קבצים סטטיים:
app.use('/client/*', serveStatic({ root: './'}));
אם ניגשים לנתיב /client/foo.js יוגש הקובץ foo.js מתוך תיקיית client. אם ניגשים ל /client/index.html יוגש הקובץ index.html ואם ניגשים לנתיב /client/ יוגש גם כן הקובץ index.html כצפוי. אבל מה קורה אם ניגשים ל /client (בלי לוכסן בסוף)? הונו מנסה ללכת לקראתנו ואוטומטית מגיש שוב את תוכן הקובץ index.html. הבעיה היא שה URL נשאר בלי הלוכסן, ולכן אם index.html כולל הפניה לקובץ אחר ההפניה תהיה יחסית ל / ולא יחסית ל /client. לדוגמה נניח שבתוך index.html מופיעה השורה:
<link rel="stylesheet" href="style.css" />
גישה לאתר דרך הנתיב /client/ מחזירה את תוכן הקובץ index.html. בגלל שהנתיב מסתיים ב / הדפדפן מנסה לקבל את קובץ העיצוב מהנתיב /client/style.css והכל עובד. לעומת זאת גישה לאתר דרך /client עדיין מחזירה את תוכן הקובץ index.html, אבל הפעם בגלל שהתיקייה האחרונה בנתיב היא התיקייה הראשית / הדפדפן ינסה לטעון את /style.css בלי התחילית client, ייכשל והעיצוב לא יוצג. פיתרון מהיר הוא להוסיף הפניה מ /client ל /client/ עם הקוד הזה:
app.get('/client', (c) => {
  return c.redirect('/client/', 301); // Permanent redirect
});
app.use('/client/*', serveStatic({ root: './'}));
ואם אתם מכירים פיתרונות אחרים אל תתביישו לשתף בתגובות.

ToCode
1 419
איך לקרוא Code Review של Chat GPT הבעיה עם Chat GPT ו Code Reviews היא שאין ל GPT עדיין מספיק קונטקסט בשביל להבין למה בניתי דברים כמו שבניתי ולכן הוא ימליץ על Best Practices כלליים, גם כשזה לא הכרחי, וגם יכול לטעות ולחשוב שלא השתמשתי ב Best Practice מסוים אפילו שכן. הנה שתי דוגמאות קטנות שעזרו לי לראות מה GPT רואה ומה הוא מפספס. שיפור קוד רובי שלחתי לו לבדיקה את הפונקציה הבאה ברובי:
require 'set'

def count_valid_requests(uniqueCodes, requests)
    uniqueCodesSet = Set.new(uniqueCodes)
    return requests.count { |r| uniqueCodesSet.include?(r) }
end
הקוד עובד ולא כתוב רע אבל אפילו בשתי שורות של קוד יש פה כמה דברים שמתכנתי רובי לא אוהבים לראות - הסטנדרט לגבי שמות המשתנים ברובי הוא להשתמש בקו תחתי להפרדה בין המילים ולא להשתמש ב return בצורה מפורשת. ChatGPT שם לב לשתי הבעיות ויצר גירסה מתוקנת של הפונקציה בלי בעיה:
require 'set'

def count_valid_requests(unique_codes, requests)
  unique_codes_set = Set.new(unique_codes)
  requests.count { |request| unique_codes_set.include?(request) }
end
ככל שהקוד מסתבך הטיפים של ChatGPT עדיין בעלי ערך אבל דורשים יותר מאמץ בקריאה. הנה פונקציה נוספת ששלחתי לו, הפעם מפרויקט ריילס:
def cancel
    wi = WorkshopInstance.find(params[:id])
    authorize! :attend, wi
    wi.users.delete(current_user)

    render json: {
             attending: attending
           }
  end
כאן הפלט כבר היה הרבה יותר ארוך - ה GPT שם לב שאין לי קוד טיפול בשגיאות, ש find עלולה לזרוק שגיאה והמליץ להחליף אותה ב find_by ואחריה קוד לבדיקה שגיאה. אני לא אוהב את ההמלצה הזאת כי אם find כבר ממילא זורק שגיאה אז לא ברור למה להחליף אותו בפונקציה שלא זורקת שגיאה ואז להוסיף בדיקה ולזרוק את השגיאה בצורה יזומה. הוא כן שם לב שהשתמשתי במשתנה attending שלא מוגדר בפונקציה, והמליץ להחליף את delete ב delete_by שבפועל קוראת ל delete_all המהירה בהרבה - שני טיפים שכדאי ליישם. קוד JavaScript אחרי זה נתתי לו לקרוא את הקוד הבא ב JavaScript:
const evtSource = new EventSource("/count");
const ti = document.querySelector('input');

evtSource.onmessage = (event) => {
  ti.value = event.data;
};

document.querySelector('button').addEventListener('click', async () => {
  await fetch('/count', {
    method: "POST",
    body: JSON.stringify({ value: ti.value }),
    contentType: 'application/json',
  });
});
ושוב הוא התלונן קודם כל על זה שאין קוד טיפול בשגיאות (במקרה הזה הוא לא נחוץ), וטען (לדעתי לא בצדק) שאפשר לשפר ביצועים אם עושים את ה querySelector במרוכז ושומרים את התוצאות במשתנים. הוא גם חשב שצריך להפעיל parseInt על value ולבדוק שהתקבל מספר, למרות שאין לזה זכר בקוד שהדבקתי. מצד שני הוא מצד יפה את הטעות שלי בהגדרת הכותרת contentType, שצריכה להיות Content-Type. סך הכל אחוז ה False Positives הוא עדיין גבוה. באופן כללי כשיש זמן אני חושב שרצוי להדביק חלקים מהקוד שלנו ל Chat GPT כדי לקבל טיפים מועילים וללמוד יותר על הקוד, אבל לקחת בחשבון שתצטרכו להשקיע זמן לפענח את התשובה שלו ולהפריד עיקר מטפל.

ToCode
1 419
אבל מי יתחזק את זה? כמה סימנים חשודים שכדאי לשים לב כבר בזמן כתיבת הקוד שממש עוד רגע אי אפשר יהיה לתחזק אותו: 1. צריך להתקין תוכנות מיוחדות בשביל להריץ את הפרויקט, והתוכנות האלה חדשות במיוחד או משתנות לעתים קרובות. 2. הפרויקט משתמש בטכניקת עבודה שאף אחד לא חשב עליה קודם (זה גאוני! ידעתי שהיינו צריכים לבנות ORM בעצמנו). 3. הפרויקט משתמש בשפת תכנות ממש מיוחדת ואיזוטרית, או עדיין חדשה ומתעדכנת לעתים קרובות (כן Julia אני מסתכל עלייך). 4. אין דרך להפעיל את הפרויקט על מחשב פיתוח, הכל רץ רק בענן. הרצה מקומית משתמשת בסטאבים. 5. בחודשים האחרונים כל פעם שהיה תיקון קטן המפתחים לא הוסיפו בדיקה יחד עם התיקון כי לא היה זמן. 6. קוד משתנה אבל התיעוד שמלווה אותו נשאר ללא שינוי. 7. אף אחד לא יודע איך או מתי צריך לשדרג תלויות. כל אלה סימנים שאפשר לזהות אפילו לפני שמתחילים לעבוד על פרויקט, ויכולים לתת לכם אינדיקציה כמה זמן עוד אפשר יהיה להוסיף קוד בלי שהכל יתמוטט.

ToCode
1 419
בחירת כלים לפרויקט צד מישהו שיתף השבוע ברדיט פרויקט שולה מוקשים שכתב ביום. הסטאק הטכנולוגי? tailwind ו next.js, וכן זה כולל חיבור לדומיין והעלאה לרשת. הייתי שמח לראות את הקוד אבל אפילו בלי אני מהמר שאין שם ריאקט ראוטר וגם לא רידאקס, לא בדיקות ולא תיעוד. כשהמטרה היא לבנות משהו מהר לא צריך לשבור את הראש על כלים מתוחכמים מספיק להפעיל IDE ולהתחיל לכתוב קוד. כן צריך לשים לב לשתי טעויות שאנשים עושים סביב הצלחות כאלה- 1. מפתחים רבים חושבים שאם הם הצליחו לבנות פרויקט צד מהיר בסטאק טכנולוגי "פשוט", אז כדאי להשתמש באותו סטאק טכנולוגי גם לפרויקטים מסובכים. 2. מפתחים רבים אחרים חושבים שאין מצב לבנות משהו ביום כי רק התקנת הכלים והגדרות לפרויקט חדש כדי שיהיה בנוי כמו שיש להם בפרויקט המסובך בעבודה (רידאקס, טייפסקריפט, קוברנטס, בדיקות, תיעוד) לוקח שבוע. 3. מפתחים רבים אחרים חושבים שאם כבר הם בונים פרויקט צד עדיף לבנות משהו בסטאק טכנולוגי שהם לא מכירים, ושוב מבזבזים ימים ושבועות רק על בחירת הכלים. הגמישות שמאפשרת להתאים את הכלי לפרויקט, לבחור פרויקט קטן ולהצליח לבנות אותו ביום היא מרשימה - גם אם התוצאה היא בסך הכל משחק שולה מוקשים.