שלושה דברים שלמדתי מהקוד של Gumroad
אז Gumroad עברו לקוד פתוח וזו הזדמנות מצוינת ללמוד על מבנה פרויקט ריילס גדול של מערכת אמיתית. אני בטוח שבימים הקרובים אבלה יותר זמן עם הריפו שלהם אבל הנה שלושה דברים מרכזיים שקופצים לעין:
1. מודלים שטוחים, קונסרנים מקוננים
יש המון מודלים בגאמרוד ולמרות זאת כולם באותה תיקיה. מודל מייצג טבלה בבסיס הנתונים ושמירת כל המודלים באותה תיקיה מסדרת את תיקיית models בצורה מקבילה לסכימה וכך קל למצוא דברים. מצד שני מבנה תיקיות במערכת קבצים כן עוזר לנו להתמצא אז את הלוגיקה הם כתבו בקבצי concerns שמסודרים בתיקיות. אין להם בעיה עם Concern-ים שנטענים רק ממודל אחד למשל המודול Follower::AudienceMember שנטען רק מתוך:
class Follower < ApplicationRecord
include ExternalId
include TimestampScopes
include Follower::From
include Deletable
include ConfirmedFollowerEvent::FollowerCallbacks
include Follower::AudienceMember
2. בדיקות בכל מקום
מבדיקה מדגמית כל מודל שנכנסתי אליו הכיל קוד בדיקה, לדוגמה:
# frozen_string_literal: true
require "spec_helper"
RSpec.describe Community do
subject(:community) { build(:community) }
describe "associations" do
it { is_expected.to belong_to(:seller).class_name("User") }
it { is_expected.to belong_to(:resource) }
it { is_expected.to have_many(:community_chat_messages).dependent(:destroy) }
it { is_expected.to have_many(:last_read_community_chat_messages).dependent(:destroy) }
it { is_expected.to have_many(:community_chat_recaps).dependent(:destroy) }
end
describe "validations" do
it { is_expected.to validate_uniqueness_of(:seller_id).scoped_to([:resource_id, :resource_type, :deleted_at]) }
end
describe "#name" do
it "returns the resource name" do
community = build(:community, resource: create(:product, name: "Test product"))
expect(community.name).to eq("Test product")
end
end
describe "#thumbnail_url" do
it "returns the resource thumbnail url for email" do
community = build(:community, resource: create(:product))
expect(community.thumbnail_url).to eq(ActionController::Base.helpers.asset_url("native_types/thumbnails/digital.png"))
end
end
end
אני מודה שבחלק מהמקומות הבדיקה דורשת קצת מאמץ בקריאה, לדוגמה הבדיקה הבאה:
it "returns affiliates sorted by # of products" do
order = [affiliate_user_1, affiliate_user_3, affiliate_user_2]
expect(seller.direct_affiliates.sorted_by(key: "products", direction: "asc")).to eq(order)
expect(seller.direct_affiliates.sorted_by(key: "products", direction: "desc")).to eq(order.reverse)
end
מחייבת אותי לגלול לתחילת הקובץ כדי להבין איזה משתמש נוצר עם כמה מוצרים ואישית הייתי מעדיף לראות את ה create צמוד לקוד הבדיקה, אבל בואו - כמות הבדיקות והמגוון מרשימים. יש להם בדיקות מודלים, בדיקות לקונטרולרים ובדיקות מערכת.
3. פרונטאנד נראה מאתגר
גאמרוד משתמשים בריילס עבור השרת וריאקט לצד לקוח. אני לא מצאתי בדיקות לקומפוננטות בצד הפרונטאנד וגם הקוד עצמו היה נראה לי הרבה פחות מסודר: קבצים של מאות ואלפי שורות, פונקציות שמוגדרות בתוך הקומפוננטות, קוד ולוגיקה בתוך JSX, ובאופן כללי הרגשה של פחות תשומת לב.
דוגמה קטנה האפקט הבא שנועד להגדיל גובה של textarea כשהתוכן משתנה:
React.useEffect(() => {
if (!ref.current) return;
ref.current.style.height = "inherit";
ref.current.style.height = `${ref.current.scrollHeight}px`;
}, [props.value]);
שהיה נכון יותר לכתוב אותו בתור layout effect או הכי טוב לוותר עליו לגמרי ולהשתמש ב CSS.
או במבט יותר גבוה הבחירה לשמור אוביקט בתוך קונטקסט למשל ב DomainSettings.ts שלהם:
type DomainSettings = {
scheme: string;
appDomain: string;
rootDomain: string;
shortDomain: string;
discoverDomain: string;
thirdPartyAnalyticsDomain: string;
};
const Context = React.createContext<DomainSettings | null>(null);
שאומרת שכל פעם שאיזשהו מפתח באוביקט ישתנה כל הקומפוננטות שמקשיבות גם למפתחות אחרים יתרנדרו מחדש, מה שפוגע בביצועים.
סך הכל כל הכבוד לגאמרוד על השיתוף והפתיחות. מעבר לקוד פתוח פותח הזדמנויות לקהילה לגדול ולמפתחים אחרים ללמוד ובמיוחד כשמדובר על מערכת פרודקשן אמיתית. זה הקוד בגיטהאב שתוכלו גם להנות וללמוד: