Skip to content

فصل ۱۱ — مطالعهٔ موردی: مهاجرت به پایگاه دادهٔ جدید

نوشتهٔ مشترک با Maggie Zhou، Staff Infrastructure Engineer، Slack Technologies, Inc.

در دومین فصل مطالعهٔ موردی، بازآرایی گروهی از مهندسان product engineering و تیم‌های زیرساخت Slack را بررسی می‌کنیم. پروژه بر یکپارچه‌سازی جداول عضویت کانال فصل قبل بنا شده بود. اگر مطالعهٔ موردی اول را نخوانده‌اید، توصیه می‌کنم بخوانید؛ context مهمی برای این فصل است.

برخلاف مطالعهٔ قبلی که عمدتاً با عملکرد انگیخته شده بود، این یکی chiefly به‌خاطر نیاز Slack به انعطاف بیشتر در محصول بود. عضویت کانال وابسته به shardهای workspace جداگانه ساخت featureهای پیچیده‌تر فراتر از یک workspace را سخت می‌کرد. می‌خواستیم سازمان‌های پیچیده با چند workspace در یک مجموعه کانال همکاری کنند و ارتباط بین مشتریان Slack متمایز — مثلاً هماهنگی شرکت با vendorها درون برنامه. برای unlock کردن این، باید دادهٔ عضویت کانال را بر اساس user و channel نه workspace reshard می‌کردیم. این بازآرایی چالش‌های migration پایگاه داده در مقیاس بزرگ، پروژه‌های چند فصل و تلاش‌های heavily cross-functional را نشان می‌دهد.

بازآرایی موفق بود چون درک قوی از مسئله و اینکه استراتژی evolving محصول چطور ما را از تصمیم‌های معماری گذشته فراتر برد (فصل ۲) داشتیم. پروژه را thoughtful برنامه‌ریزی کردیم و چند متغیر بیش از لازم را juggle کردیم، با دانستن که refactor ارزشمندتر می‌شود (فصل ۴). استراتژی rollout careful و tooling برای اجرای reliable ساختیم (فصل ۸). در کل تلاش، communication strategy ساده حفظ شد.

اگرچه در نهایت توانستیم محصول را در جهت‌های جدید گسترش دهیم، تقریباً دو برابر تخمین اولیه طول کشید. در تخمین‌ها خوش‌بین بودیم (فصل ۴)؛ بیش از یک سال برای کاری که شش ماه تصور می‌کردیم. پیامدهای محصول refactor را دست‌کم گرفتیم و تازه پس از چند ماه پیشرفت کم، از expertise مهندسان product leverage گرفتیم (فصل ۶).

مثل مطالعهٔ قبلی، با context شروع می‌کنیم: چرا توزیع داده bottleneck شد و انگیزهٔ Vitess. سپس راه‌حل و هر فاز پروژه.

دادهٔ workspace-sharded

برای درک مسائلی که می‌خواستیم حل کنیم، باید توزیع داده در MySQL را توصیف کنیم. قبل از refactor، اکثر داده بر اساس workspace shard می‌شد؛ workspace یعنی یک مشتری Slack. در مطالعهٔ قبلی در «معماری Slack ۱۰۱» لمس شد؛ شکل ۱۰-۳ توزیع مشتریان روی shardها را نشان می‌دهد.

سال‌ها خوب کار کرد، اما دو دلیل increasingly inconvenient شد:

اول، از نظر عملیاتی shardهای بزرگ workspace را سخت support می‌کردیم. shardهای بزرگ‌ترین مشتریان growing hotspotهای مکرر و problematic داشتند. مشتریان روی shardهای isolated به حجم داده‌ای نزدیک می‌شدند که دیگر upgrade سخت‌افزار ممکن نبود. بدون مکانیزم ساده split افقی، گیر کرده بودیم.

دوم، تغییرات مهم محصول actively مرز بین workspaceها را که در کد و داده uphold کرده بودیم می‌شکست. featureهایی برای bridge کردن چند workspace برای بزرگ‌ترین مشتریان و ارتباط مستقیم دو مشتری Slack در کانال مشترک launch کرده بودیم.

عدم تطابق vision محصول و معماری سیستم یعنی application ever more complex — نمونهٔ degradation به‌خاطر shift نیاز محصول (فصل ۲!). در سال قبل از این مطالعه، گاه برای یافتن کانال و عضویتش باید سه shard جدا query می‌زدیم. برای developer گیج‌کننده بود.

برای نگرانی‌های عملیاتی MySQL و scaling، گزینه‌های storage دیگر evaluate کردیم. پس از وزن‌کشی، Vitess — database clustering system ساخته‌شده در YouTube برای horizontal scaling MySQL — adopt شد. با migration به Vitess می‌توانستیم بر چیز دیگری غیر از workspace shard کنیم: فضا روی shardهای شلوغ و توزیع قابل‌فهم‌تر برای مهندسان.

Migration channels_members به Vitess

با این شرایط، جدول عضویت کانال channels_members را به Vitess migrate کردیم. یکی از پرترافیک‌ترین جداول بود؛ reshard کردنش فضا و بار قابل‌توجهی از شلوغ‌ترین workspace shardها آزاد می‌کرد. business logic گرفتن عضویت کانال‌های cross-workspace را هم ساده‌تر می‌کرد.

پروژه از تیم زیرساخت Vitess spearhead شد با کمک چند product engineer با دانش intimate الگوهای query برنامه. ترکیب برنده: مهندسان زیرساخت expertise سیستم پایگاه داده؛ Maggie در helm. product engineerها — از جمله من — insight برای scheme و sharding جدید و بازنویسی logic query.

با کانال #feat-vitess-channels شروع کردیم برای ایده و هماهنگی workstream. همه را دعوت کردیم و مستقیم به اولین task رفتیم.

scheme شarding

قبل از migration دادهٔ عضویت کانال به Vitess باید توزیع (کلید reshard) را تصمیم می‌گرفتیم. دو گزینه:

  • بر اساس کانال (channel_id): همهٔ عضویت‌های یک کانال با query یک shard
  • بر اساس کاربر (user_id): همهٔ عضویت‌های یک کاربر با query یک shard

پس از یکپارچه‌سازی مطالعهٔ اول، برداشت من اکثریت queryها عضویت کانال بود نه کاربر — Search، @channel، @here. نمونه‌ای از queryهای production به data warehouse log می‌شد. برای تأیید intuition که ترافیک channel_id-محور است، روی دادهٔ یک ماه query زدم (شکل ۱۱-۱).

شکل ۱۱-۱. تعداد query به channels_members فیلترشده با channel_id

یک product engineer با تجربهٔ بیشتر Vitess گفت sharding بر اساس user شاید بهتر باشد. از همان logها top 10 query پرتکرار فیلترشده با user_id را نشان داد (شکل ۱۱-۲). برای عملکرد خوب باید این رفتار را account می‌کردیم.

شکل ۱۱-۲. ده query پرتکرار به channels_members و فیلتر با user_id

هر دو را وزن دادیم، back-of-the-napkin math برای capacity. compromise: denormalize عضویت به دو جدول — یکی user-sharded، یکی channel-sharded — double-write برای هر دو use case تا point query برای هر دو ارزان باشد.

تدوین scheme جدید

باید scheme موجود workspace-sharded را hard look می‌کردیم و برای use caseهای user- و channel-sharded تغییر می‌دادیم. می‌توانستیم scheme موجود را به هر دو migrate کنیم، اما فرصت unique برای rethink طراحی اولیه بود. scheme هر کدام را نزدیک‌تر می‌بینیم؛ از user shard شروع می‌کنیم. مثال ۱۱-۱ scheme قبل از migration روی workspace shard است.

sql
-- Example 11-1. CREATE TABLE statement showing the existing channels_members table,
-- sharded by workspace

CREATE TABLE `channels_members` (
  `user_id` bigint(20) unsigned NOT NULL,
  `channel_id` bigint(20) unsigned NOT NULL,
  `team_id` bigint(20) unsigned NOT NULL,
  `date_joined` int(10) unsigned NOT NULL,
  `date_deleted` int(10) unsigned NOT NULL,
  `last_read` bigint(20) unsigned NOT NULL,
  ...
  `channel_type` tinyint(3) unsigned NOT NULL,
  `channel_privacy_type` tinyint(4) unsigned NOT NULL,
  ...
  `user_team_id` bigint(20) unsigned NOT NULL,
  PRIMARY KEY (`user_id`,`channel_id`)
)

جدول عضویت user-sharded

برای user-sharded اکثر schema اصلی را نگه داشتیم با یک استثنا: تغییر significant در نگهداری user ID. برای انگیزه، دو نوع user ID و منشأشان را خلاصه می‌کنیم.

Slack می‌خواست کسب‌وکارهای پیچیده با چند workspace (دپارتمان/واحد) راحت‌تر همکاری کنند. بدون centralization، ارتباط بین دپارتمان‌ها و مدیریت workspaceها سخت بود. بزرگ‌ترین مشتریان workspaceهای زیاد را زیر یک umbrella آوردند.

در grouping workspaceها باید userها sync می‌ماندند. مثال: Acme Corp با workspace مهندسی و customer experience. کارمند Acme یک حساب organization-level دارد. اگر مهندس باشید عضو workspace Engineering و Customer Experience هستید.

آنچه یک حساب به نظر می‌رسید، زیر hood چند حساب بود. در سطح organization یک canonical user ID؛ در هر workspace local user ID جدا. عضو Engineering و CX یعنی سه ID یکتا — یا به‌طور کلی n + 1 ID که n تعداد workspaceهای عضویت است.

ترجمه بین این IDها سریع exceedingly complicated و bug-prone شد. ظرف یک سال برنامهٔ جایگزینی local با canonical user ID. چون بیشتر داده به نوعی user ID اشاره می‌کند، rewrite invisible پیچیدگی بالایی داشت.

جدول workspace-sharded channels_members local user ID در user_id داشت. پروژهٔ canonicalization در جریان بود؛ تصمیم گرفتیم collaborate کنیم و canonical user ID در همهٔ ستون‌های user ID ذخیره کنیم.

scheme جدول channel-sharded

علاوه بر user ID، نگرانی write bandwidth جدول ثانویه channel-sharded بود. queryهای planned را بررسی کردیم. متوجه شدیم بیشتر ستون‌های جدول اصلی برای consumerها unused بودند، از جمله ستون‌های پربه‌روز مثل last_read. مثلاً query همهٔ عضویت‌های یک کانال معمولاً فقط user_id و user_team_id را استفاده می‌کرد. حذف ستون‌های غیرضروری write frequency را dramatically کم می‌کرد. مثال ۱۱-۲ scheme channel-sharded:

sql
-- Example 11-2. CREATE TABLE statement for the second of our new channels_members
-- tables, sharded by channel

CREATE TABLE `channels_members_bychan
  `user_id` bigint(20) unsigned NOT NULL,
  `channel_id` bigint(20) unsigned NOT NULL,
  `user_team_id` bigint(20) unsigned NOT NULL,
  `channel_team_id` bigint(20) unsigned NOT NULL,
  `date_joined` int(10) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`channel_id`,`user_id`)
)

نام team_id به channel_team_id تغییر یافت.

Detangle کردن JOINها

باید application logic را برای schemeهای جدید و Vitess cluster به‌روز می‌کردیم. خوشبختانه بیشتر straightforward بود و زود اکثر logic به‌روز شد.

سخت‌تر با queryهای پیچیده JOIN با جداول دیگر MySQL cluster بود. با انتقال جدول به cluster جدید، دیگر این JOINها support نمی‌شد؛ باید به point queryهای کوچکتر split و JOIN در application code انجام می‌شد.

از ابتدا می‌دانستیم handful JOIN split می‌شود. anticipate نکردیم بیشترشان core featureهای Slack و سال‌ها hand-tuned بودند. split یعنی risk از کند شدن notification تا data leak تا down شدن Slack. nervous بودیم اما باید ادامه می‌دادیم.

migration روزانه pause شد؛ فهرست ۲۰ query نگران‌کننده compile کردیم. بدون product expertise کافی برای detangle همه. تخمین: ماه‌ها بدون کمک product engineering. خوشبختانه product engineerها پاسخ دادند و process ساده برای split امن هر query ساختیم.

برای illustration، query مثال ۱۱-۳ — مجوز دیدن فایل — را walkthrough می‌کنیم.

sql
-- Example 11-3. A sample JOIN we needed to detangle; % symbolizes substitution syntax

SELECT COUNT(*)
FROM files_shares s
LEFT JOIN channels_members g
  ON g.team_id = s.team_id
  AND g.channel_id = s.channel_id
  AND g.user_id = %USER_ID
  AND g.date_deleted = 0
WHERE
  s.team_id = %TEAM_ID
AND s.file_id = %FILE_ID
LIMIT 1

اول کوچک‌ترین subset داده را که earliest fetch ممکن است identify می‌کردیم تا intersection زود minimize شود.

برای file visibility، از usage معمولاً تعداد محل share فایل از تعداد کانال‌های کاربر کمتر است (cardinality query هم verify می‌کند). پس اول محل share فایل، بعد اینکه کاربر در کدام‌یک عضو است — مثال ۱۱-۴:

sql
-- Example 11-4. The JOIN with files_shares split into two queries

SELECT DISTINCT channel_id
FROM files_shares
WHERE team_id=%TEAM_ID AND file_id=%FILE_ID

...

SELECT COUNT(*)
FROM channels_members
WHERE
  team_id=%TEAM_ID
  AND user_id=%USER_ID
  AND channel_id IN (%list:CHANNEL_IDS)
LIMIT 1

سپس coverage تست را verify کردیم؛ اگر نبود test case اضافه کردیم. logic جدید را در experiment برای rollout تدریجی و rollback سریع wrap کردیم. هر دو implementation را test کردیم، باگ fix، تکرار تا confidence. هر دو call را با timing instrument کردیم. مثال ۱۱-۵ outline تقریبی file visibility:

برای splitهای پرریسک (از جمله file visibility) با QA team در dev و production قبل از rollout بیشتر manually verify کردیم. اکثر JOINها critical functionality Slack بودند.

php
// Example 11-5. Function for determining whether a user can see a specific file

function file_can_see($team, $user, $file): bool {

  if (experiment_get_user('detangle_files_shares_query')) {
    $start = microtime_float();

      # First, we want to find all of the channels where
      # the file was shared. Because we can share a file to the
      # same channel multiple times, we may find multiple files_shares
      # rows with the same channel ID but different timestamps
      # at which it was shared.
      $channel_ids =
        ud_files_shares_get_distinct_channel_ids(
           $team,
           $file['id']
        );

      # Next, we want to find the intersection of the channels
      # the file was shared in ($channel_ids) and the channels the
      # user is in.
      $membership_counts =
        ud_channels_members_get_counts(
          $team,
          $user['id'],
           $channel_ids
        );

      $end = microtime_float() - $start;

      # If there is at least one membership row, then the user
      # can see the file. If not, the user cannot see the file.
      _files_can_see_unjoined_histogram()->observe($end);
      return ($membership_counts['count'] > 0);
  }

  $start = microtime_float();
  $sql .= "SELECT 1 FROM files_shares s
        LEFT JOIN channels_members g
        ON g.team_id = s.team_id
          AND g.channel_id = s.channel_id
          AND g.user_id = %USER_ID
          AND g.date_deleted=0
        WHERE s.team_id = %TEAM_ID
          AND s.file_id = %FILE_ID
          AND (g.user_id > 0) LIMIT 1";

  $bind = [
    'file_id' => $file['id'],
    'user_id' => $user['id'],
    'team_id' => $team['id']
  ];

    $ret = db_fetch_team($team, $sql, $bind);
    $end = microtime_float() - $start;
    _files_can_see_join_histogram()->observe($end);

    return (bool)db_single($ret);
}

implementation جدید را اول روی Slack داخلی قبل از مشتریان real فعال کردیم — برای metrics timing و اطمینان از نبود باگ.

workspace Slack quirks دارد و usage همیشاً مثل مشتریان نیست. litmus test خوب برای باگ زودهنگام، اما برای قضاوت latency اضافی detangled query مناسب نبود. برای subset JOINها latency روی workspace خودمان بدتر aggravated شد؛ با rollout به free team و مشتریان بزرگ‌تر metrics stabilize شد.

این process را برای تقریباً هر JOIN تکرار کردیم: slice، instrument، rollout تدریجی. استثنا: دو mentions query که ماه‌ها untouched ماند — JOIN با جداول در migration Vitess خودشان. defer تا subcomponentها جا بیفتند. پنج نفر حدود شش هفته on/off بین refactor و commitment دیگر برای اکثر JOINها.

اغلب refactor طبق plan پیش نمی‌رود؛ hurdleها اولویت را shuffle یا pause یک گام می‌کند. unsatisfying است اما گاه برای تحویل به‌موقع کل پروژه huge difference می‌کند.

اگر منتظر بقیه migrationهای وابسته می‌ماندیم، refactor ماه‌ها عقب می‌افتاد. با ادامهٔ اکثریت queryهای channels_members rewrite‌شده، headway داشتیم و issueها را زود دیدیم؛ وقتی mentions را revisit کردیم، جای پایدارتر بودیم.

rollout دشوار

وقتی migration channels_members شروع شد، حدود ۱۵٪ کل QPS روی Vitess بود. workloadهای critical مثل notification و جدول teams migrate و reshard شده بودند. tooling و dashboard برای ~۲۰ migration با compare dataset بین cluster قدیم و جدید ساخته شده بود.

channels_members unique بود: تنها ~۲۰٪ کل query load — تقریباً دو برابر QPS مدیریت‌شدهٔ Vitess تا آن زمان. scale یعنی nervous از issue غیرمنتظره؛ اما motivated برای offload از MySQL که زیر بار بزرگ‌ترین مشتریان struggle می‌کرد. بین سنگ و سخت‌کاف.

بهترین شرط: lean روی migration tooling قبلی Vitess.

rollout چهار mode سطح بالا:

  1. Backfill — double-write به cluster جدید (scheme جدید) و قدیم؛ backfill دادهٔ موجود از قدیم به جدید.
  2. Dark — read به هر دو cluster؛ compare و log diff؛ consumer نتیجهٔ cluster قدیم.
  3. Light — read به هر دو؛ compare و log diff؛ نتیجهٔ Vitess به application.
  4. Sunset — double-write ادامه؛ read فقط Vitess. downstream (مثل data warehouse) تا به‌روز شدن روی cluster قدیم. مشکل یعنی fix forward؛ rollback امن به legacy سخت.

deploy configuration سریع برای swap mode و ramp up/down. control granular برای tier مشتری و user در modeهای مختلف. tweak سریع هنگام issue.

حالت Backfill

هر migration با Backfill شروع می‌شد. هدف اول: آماده‌سازی backfill کامل برای migration read. برای اکثر migration قبلی write جدید تقریباً identical به قدیم بود. اینجا data model عوض می‌شد — rewrite SQL زیاد (مثل share_type، local به canonical user ID). با consolidation فصل ۱۰، queryهای نیازمند rewrite را راحت پیدا کردیم.

هدف دوم: مشکل performance write به cluster جدید. برای بیشتر migration، Backfill و Dark impact کمی در production داشتند چون:

  • Hacklang async cooperative multitasking query به هر دو cluster concurrent؛ timeout ۱ ثانیه روی Vitess — worst case penalty حداکثر ۱s منهای زمان query قدیم.
  • هنوز نتیجه Vitess به application برنمی‌گشت (Light mode).

با این migration فرض غلط بود. cluster user-sharded Vitess از قبل دادهٔ production پراستفاده (saved messages، notification) داشت. با ramp Backfill، resource Vitess saturate شد — timeout و error برای جداول critical. update/delete بدون sharding key (user_id) روی همه shard scatter می‌شد. config fix و ramp دوم؛ ۱۰۰٪ و Dark mode!

حالت Dark

Dark را جدی شروع کردیم: اکثر queryهای channels_members (از جمله JOINهای دردسرساز) برای read از Vitess rewrite شده؛ backfill ~۳+ ماه. سیستم migration اجازه می‌داد subset query در phase مختلف باشد — parallelization: Dark قبل از rewrite همه queryها.

دو هدف Dark: دوباره performance read cluster جدید؛ و diff داده.

عملکرد

با ramp read همزمان legacy و Vitess، handful query پر QPS تعداد alarming row برمی‌گرداند. QPS بالا + row زیاد = بزرگ‌ترین rows/sec در cluster. شکل ۱۱-۳: peak ~۹٬۰۰۰ row/sec از channels_members یک shard. آنقدر frequent و memory-intensive که OOM روی host! روزهای بعد ramp، ۱/۲۵۶ host هر روز OOM.

اول فکر کردیم cloud provider مقصر است. فهمیدیم config mishap یا bad luck نیست — ramp down برای isolate OOM.

شکل ۱۱-۳. row برگشتی از channels_members روی یک shard

شکل ۱۱-۴. گزارش وضعیت هفتگی دربارهٔ OOMها

پروژه high-priority در infra و engineering. از reliability DB، channels_members روی Vitess muscle memory بود. OOM elusive — کل تیم DB در #feat-vitess-channels debug از همه زاویه. resize memory MySQL، fragmentation، upgrade minor MySQL برای NUMA interleave policy buffer pool! همزمان JOIN بیشتر split و Dark load بیشتر — هر بار فکر کردیم OOM تمام شد، دوباره با ramp بیشتر.

پروژه از شش ماه گذشت — estimate اول را obliterate کرد؛ two steps forward one back. پس از هفته‌ها trial and error، storage دیگر Slack (monitoring، Search) با min_free_kbytes kernel خیلی کوچک مشکل داشت. مقدار بزرگ‌تر = kernel فضای بیشتر برای free کردن RAM. spike query با allocation ناگهانی RAM زیاد → OOM چون kernel سریع enough free نمی‌کرد. bump min_free_kbytes فشار حافظه را manage کرد و OOM را resolve کرد.

هشت ماه فقط در Dark — بیشتر از کل estimate اولیه پروژه؛ نزدیک دو سوم کل تلاش.

ناسازگاری داده

با config changes، ramp ۱۰۰٪ traffic Vitess بدون risk site-wide. تقریباً همه JOIN detangle؛ point query از Vitess. هدف: diff بین dataset جدید و قدیم — query concurrent به هر دو و log diff (legacy source of truth). aggregate diff؛ log primary key وقتی pair متفاوت.

هفته‌ها diff را comb کردیم. schema user-sharded اطلاعات بیشتر از workspace-sharded اصلی — متغیر بیشتر در rewrite. بهبود DX برای shared channel و Enterprise Grid = product logic tricky در هر query. potential mistake بیشتر از migration یک‌به‌یک جداول قبلی Vitess.

بخش زیاد diff از single problem — fix یک instance حجم diff را زیاد کم می‌کرد. مثلاً ستون متفاوت legacy vs Vitess → هر query mismatch. شکل ۱۱-۵: fix ignore column mismatch — diff channel-sharded از ۱۰٪ query به ۰٫۰۱٪.

شکل ۱۱-۵. کاهش diff روی جدول channel-sharded channels_members

نمای نزدیک نمودار پیام Slack شکل ۱۱-۵:

(نمودار در نسخهٔ چاپی)

همه diff آسان نبود. logic shared channel نادرست؛ mistake در backfill. کار tedious؛ product implication = درک عمیق application. تغییرات پشت feature flag/experiment اما consequence real در production — caution. crawl کند → resource بیشتر از product engineering.

افراد جدید life تازه آورد. pairing برای ramp سریع: debug diff، demo tooling Vitess، phased rollout، scheme جدید. tedious اما با arsenal بزرگ‌تر momentum boost و diffهای نهایی banish. به صفر diff نرسیدیم؛ ۹۹٫۹۹۹٪ correctness کافی — row channels_members با last_read سریع عوض می‌شود؛ discrepancy از read-after-write rapid قابل قبول. ۰٫۰۰۱٪ باقی: row بعد از diff converge می‌شد.

بستن Dark significant: ۱۰۰٪ traffic channels_members performant روی Vitess با نتیجه درست — crucial برای success. relief برای همه. آماده Light mode برای beta کوچک در شرکت.

حالت Light

Light: test-drive داده Vitess؛ swap traffic بدون regression user-facing. confidence از Dark؛ اما عضویت کانال core Slack — باگ serious. ramp careful: volunteer کوچک Slack → کل customer base.

بیشتر ok؛ اما گاه پس از join کانال، کاربر نمی‌توانست پیام بفرستد. ramp down experiment؛ query log روی host DB تا ۲ ساعت — grep modification membership row.

culprit: background process پس از join Grid user به کانال workspace-level — replace row با canonical user ID به local user ID. مشکل: schema Vitess عمداً canonical؛ بعد rewrite دیگر row پیدا نمی‌شد → block ارسال پیام.

چرا process وجود داشت؟ git history و conversation: paper over مشکل Enterprise Grid — placeholder row با canonical، update پس از rejoin. در Dark diff، QA چند دور، unit test ظاهر نشد — فقط در circumstance دقیق و uncommon.

determine کردیم دیگر لازم نیست — delete کل process. solved!

یک ماه ramp Light به همه مشتریان. confidence با volunteer → Slack خودمان → free tier → paying → Enterprise بزرگ. مشتری با بیشترین shared channel timeout روی API conversations.view — query Vitess channels_members timeout. volume پایین → alert در Dark نبود. rollback Light، fix query، ramp دوباره.

حالت Sunset

سه روز پس از Light برای همه، Sunset. double-write ادامه؛ read فقط Vitess. Sunset → ۲۲٪ کاهش load legacy overload. شکل ۱۱-۶ dip query روی workspace shard.

شکل ۱۱-۶. حذف read query از clusterهای legacy workspace-sharded

جمع‌بندی

پس از Sunset، task مهم باقی: پس از migrate data warehouse به Vitess، drop جداول workspace-sharded قدیمی channels_members — ~یک ماه بعد farewell. هفته‌ها بعد tidy کتابخانه unidata عضویت؛ unwind feature flag و double-write.

حذف write از legacy shard win بزرگ و به‌موقع: ۵۰٪ write کم؛ replication lag روی enterprise shard VLB (فصل ۱۰) eliminate — وقتی تحت فشار write مداوم struggle می‌کرد. روزهای قبل drop، lag تا ۲۰+ دقیقه. شکل ۱۱-۷ steep drop write VLB.

شکل ۱۱-۷. حذف write از shard VLB

شکل ۱۱-۸: نبود spike replication lag پس از حذف write.

شکل ۱۱-۸. دیگر replication lag نیست!

نمای نزدیک نمودار پیام Slack شکل ۱۱-۸:

(نمودار در نسخهٔ چاپی)

متأسفانه همزمان coronavirus spread می‌کرد؛ دفاتر shutdown و workforce remote. demand Slack spike — مشتری جدید breakneck، پیام بیشتر. کل infra از جمله ما winding down migration فوراً به scaling unprecedented shift کرد. relief از بستن refactor، اما فرصت proper revel in achievement نداشتیم.

با بستن پروژه، engineerهای دیگر scheme برای leverage جدول resharded. prototype feature حتی در SUNSET mode؛ پروژه‌های بعد multi-team برای data model جدید و ساده‌سازی query حول Grid و shared channel.

درس‌های آموخته‌شده

درس از migration channels_members به Vitess. ابتدا بهتر می‌توانست: estimate واقع‌بینانه‌تر، teammate مناسب زودتر. سپس موفقیت: scope اضافی deliberate، communication ساده.

تخمین واقع‌بینانه

وقتی migration channels_members شروع شد، migration Vitess زیاد انجام شده بود؛ tooling refine. estimate از migrationهای اخیر سریع‌تر — optimistically فرض کردیم این هم نه سخت‌تر از آخرین.

باید می‌دانستیم channels_members beast متفاوت: load بیش از همه migration قبلی؛ shard روی دو key user و channel؛ canonical user ID و تغییر meaningful schema. estimate باید این تصمیم‌ها را reflect می‌کرد.

surpass estimate → morale hit؛ leadership watchful eye. resource بیشتر secure شد — اما expectation در start set نشد.

estimate غیرواقعی consequence جدی‌تر: از دست priority، از دست faith leadership، hit career. با brainstorm pitfall و فصل ۴، expectation بهتر برای خود و stakeholder.

جذب هم‌تیمی‌های لازم

فرض: اکثر کار infra engineer. product engineer ad hoc. فقط وقتی JOIN detangle سخت شد resource significant product — آن موقع فهمیدیم کنار کسی که query را intimate می‌شناسد سریع‌تر کار می‌کنیم. involvement crucial در Dark طولانی و diff داده → رفتار عجیب product. از ابتدا present بودند → migration سریع‌تر و درست‌تر (JOINها)، زمان phase بعد کمتر.

فصل ۵: teammate فعلی همیشه مناسب نیست. refactor بزرگ cross-team/discipline. تیم start rarely set in stone. missing را پیدا و seek out. resource بیشتر → ask.

برنامه‌ریزی scope با دقت

تصمیم early: canonical user ID در همهٔ ستون user ID در schema Vitess channels_members. Slack می‌خواست canonical everywhere؛ phase اولیه قبل از اتمام migration table unlikely تمام می‌شد. scope عمداً increase — می‌توانستیم اول canonical روی legacy cluster، یا migrate بدون canonical و بعد در Vitess. believe کردیم همزمان time و effort save — اندازه‌گیری نداشتیم اما believe true شد!

فصل ۴: scope moderate برای اتمام reasonable. گاه scope اضافی worthwhile — در planning deliberate decide؛ stakeholder opinion و expectation align.

یک مکان واحد برای communication پروژه

lean روی #feat-vitess-channels: collaborate، coordinate، update. central point — همه message جدید را می‌دیدند. سوال، code review؛ response چند دقیقه. debug در thread. Light mode: volunteer bug report.

مهم‌تر: motivation. refactor drag، engineer on/off، Dark curveball — optimism سخت. گاه «You got this!» یا emoji روی status هفتگی. act کوچک support → morale. یک جا = join/leave بدون knowledge transfer سنگین؛ stakeholder check-in بدون ping مستقیم؛ support. فصل ۷.

طراحی rollout plan thoughtful

rollout چهار phase concrete. vision clear: opt-in company → free tier → paying → largest last. tooling reliable Vitess migration؛ ramp up/down سریع slice user. effective‌ترین: rollback فوری اگر impact detrimental — aggressive forward بدون ترس. مخصوصاً Light با volunteer.

thoughtful plan + execution باز هم handful bug — همه قبل rollout شناسایی impossible. control opt-in milestone + rollback swift → progress nimble؛ regression terrible قبل از incident serious.

جمع‌بندی

مهم‌ترین نکات migration channels_members از cluster workspace-sharded به user- و channel-sharded در Vitess:

  • تخمین واقع‌بینانه. optimism خوب است؛ deadline از دست رفته consequence جدی.
  • teammate لازم را جذب کنید؛ available/current شاید مناسب نباشند. resource جدید/بیشتر — ask.
  • scope پروژه با دقت. scope اضافی در planning account شود.
  • یک مکان communication پروژه انتخاب و stick کنید.
  • rollout plan thoughtful + tooling ramp up/down آسان.

نمایه

الف

abstractions, cleaning up — پاک‌سازی abstractionها، ۸۷
accessibility — دسترس‌پذیری، در degradation کد، ۳۰
active contributors — مشارکت‌کنندگان فعال، ۱۱۲، ۱۱۵
active education — آموزش فعال، ۱۶۱-۱۶۳
adoption, fostering — تقویت پذیرش، ۱۶۰
aggregate, commits in — commit در aggregate، ۶۵
Agile development teams — تیم‌های توسعه Agile، ۱۳۷
alignment sandwich strategy — استرategی alignment sandwich، ۱۰۴-۱۰۷
Allspaw, John — ۱۲۸
API (application programming interface) — API، ۲۹، ۳۲
architecture (Slack) — معماری (Slack)، ۱۷۴-۱۷۷
arithmetic symbols — نمادهای حسابی، ۴۷
ARM (Advanced RISC Machine)-based microprocessors — ریزپردازنده‌های ARM، ۳۱
artifacts, cleaning up — پاک‌سازی artifactها، ۸۷-۸۸، ۱۵۴
assignment operators — عملگرهای انتساب، ۴۷
async cooperative multitasking mode — حالت async cooperative multitasking، ۲۰۹
Atlassian — ۱۳۷
abstractions, cleaning up, in redundant database schemas case study — در مطالعهٔ scheme تکراری، ۱۸۹

ب

buy-in — پذیرش/حمایت، ۹۷-۱۱۰
buy-in, about — دربارهٔ buy-in، ۹۷
buy-in, managers and — buy-in و مدیران، ۹۸-۱۰۱
buy-in, refactoring and — buy-in و بازآرایی، ۱۰۹-۱۱۰
buy-in, strategies achieving — استرategی‌های دستیابی به buy-in، ۱۰۱-۱۰۹

ج

Carnegie, Dale — کارnegie، دیل
How to Win Friends and Influence PeopleHow to Win Friends and Influence People، ۱۰۴
case statement — case statement، ۵۰
case studies — مطالعات موردی، ۱۶۹-۲۲۲
case studies, about — دربارهٔ مطالعات موردی، ۱۶۹
case studies, migrating to a new database — مهاجرت به پایگاه دادهٔ جدید، ۱۹۷-۲۲۲
case studies, redundant database schemas — schemeهای پایگاه دادهٔ تکراری، ۱۷۱-۱۹۶
CFGs (Control Flow Graphs) — CFG (گراف جریان کنترل)، ۵۲
change frequencies — فرکانس تغییر، ۶۵
changes, keeping them small — کوچک نگه داشتن تغییرات، ۱۵۶
channel-sharded table schema — scheme جدول channel-sharded، ۲۰۳
channels, public versus private — کانال عمومی در برابر خصوصی، ۱۷۳
channels_members, migrating to Vitess — migration channels_members به Vitess، ۱۹۹-۲۰۳
chat transcripts — رونوشت گفتگو، ۶۲
checkValid function — تابع checkValid، ۱۹، ۲۵
clean-up items — موارد پاک‌سازی، ۱۵۴
cleaning up artifacts — پاک‌سازی artifactها، ۸۷-۸۸، ۱۵۴
cleaning up, in migrating to a new database case study — در مطالعهٔ migration DB، ۲۱۷-۲۱۹
cleaning up, in redundant database schemas case study — در مطالعهٔ scheme تکراری، ۱۹۰
cleanup crews, as a team type — تیم‌های cleanup، ۱۲۰
code — کد
code, analysis tools for — ابزار تحلیل کد، ۱۶۶
code, authorship of — نویسندگی کد، ۱۷، ۶۶
code, commented-out — کد comment-out‌شده، ۳۳
code, dead — کد مرده، ۸۷
code, extending — گسترش کد، ۱۸
code, half-refactored — نیمه-bازآرایی‌شده، ۱۸
code, history of, in redundant database schemas case study — تاریخچهٔ کد در مطالعهٔ scheme تکراری، ۱۹۳-۱۹۶
code, lines of — خطوط کد، ۵۵-۵۷
code, measuring complexity of — اندازه‌گیری پیچیدگی کد، ۴۷-۵۷
code, ownership of — مالکیت کد، ۱۶۷
code, unused, as pertains to code degradation — کد unused در degradation، ۳۲
code degradation — degradation کد، ۲۷-۴۲
code degradation, about — دربارهٔ degradation کد، ۲۷
code degradation, importance of — اهمیت degradation کد، ۲۸
code degradation, requirement shifts — shift نیاز، ۲۹-۳۶
code degradation, tech debt — بدهی فنی، ۳۶-۴۱
codebases — پایگاه‌های کد
codebases, complexity of — پیچیدگی پایگاه کد، ۱۳
codebases, defined — تعریف پایگاه کد، ۹
codebases, engineers and — مهندسان و پایگاه کد، ۴۰
commented-out code — کد comment-out‌شده، ۳۳
comments — commentها، ۵۶، ۸۷
commit messages — پیام commit، ۶۴
commits — commitها، ۶۵، ۱۵۶
commits in aggregate — commit در aggregate، ۶۵
communication — ارتباطات، ۱۳۱-۱۴۶
communication, about — دربارهٔ ارتباطات، ۱۳۱
communication, choosing a single place for — یک مکان واحد برای ارتباط، ۲۲۱
communication, during project execution — در اجرای پروژه، ۱۴۱-۱۴۵
communication, importance of good — اهمیت ارتباط خوب، ۱۹۲
communication, of progress — اطلاع پیشرفت، ۱۸۸
communication, outside teams — خارج از تیم‌ها، ۱۳۸-۱۴۶
communication, regular — منظم، ۱۳۲
communication, retrospectives — retrospective، ۱۳۷
communication, stand-ups — stand-up، ۱۳۳-۱۳۵
communication, weekly syncs — sync هفتگی، ۱۳۵-۱۳۷
communication, when kicking off projects — هنگام kickoff پروژه، ۱۳۸-۱۴۱
communication, within teams — درون تیم‌ها، ۱۳۲-۱۳۷
communication, working alone — کار تنها، ۱۴۵
comparison operators — عملگرهای مقایسه، ۴۷
compatibility, of devices — سازگاری دستگاه‌ها، ۳۰
complexity, measuring for code — اندازه‌گیری پیچیدگی کد، ۴۷-۵۷
complexity, of code — پیچیدگی کد، ۱۳
complexity, unnecessary, as a risk of refactoring — پیچیدگی غیرضروری، ریسک بازآرایی، ۱۲
conditionals, simplifying — ساده‌سازی شرط‌ها، ۲۱
consolidating tables — یکپارچه‌سازی جداول، ۱۸۰-۱۸۹
continuous deployment environments — محیط continuous deployment، ۸۱
CREATE TABLE statement — دستور CREATE TABLE، ۲۰۱

د

Dark mode — حالت Dark، ۸۱-۸۶، ۲۰۸، ۲۱۰-۲۱۵
data discrepancies — ناسازگاری داده، ۲۱۳-۲۱۵
data, workspace-sharded — داده workspace-sharded، ۱۹۸
dead code, cleaning up — پاک‌سازی کد مرده، ۸۷
departments, buy-in and — buy-in و دپارتمان‌ها، ۱۰۶
dependencies, external, as pertains to code degradation — وابستگی خارجی در degradation، ۳۲
detangling JOINs — detangle JOINها، ۲۰۳-۲۰۷
developer productivity — بهره‌وری developer، ۹
devices — دستگاه‌ها، ۳۰، ۱۰۲-۱۰۴
documentation — مستندسازی
documentation, about — دربارهٔ مستندسازی، ۶۰
documentation, consistency with location of — سازگاری با محل، ۱۳۸
documentation, formal — رسمی، ۶۱
documentation, informal — غیررسمی، ۶۲-۶۴
drafting plans — تدوین برنامه‌ها، ۷۱-۹۵
drafting plans, about — دربارهٔ تدوین برنامه، ۷۱
drafting plans, choosing rollout strategies — انتخاب استرategی rollout، ۸۰-۸۶
drafting plans, cleaning up artifacts — پاک‌سازی artifact، ۸۷-۸۸
drafting plans, defining end state — تعریف end state، ۷۲-۷۴
drafting plans, estimating — تخمین، ۹۰
drafting plans, identifying strategic intermediate milestones — نقاط عطف میانی راهبردی، ۷۶-۸۰
drafting plans, mapping path between start and end state — نگاشت مسیر start به end، ۷۴-۷۶
drafting plans, referencing metrics — ارجاع به معیارها، ۸۸-۹۰
drafting plans, refining — پالایش، ۹۴-۹۵
drafting plans, sharing with other team members — اشتراک با هم‌تیمی‌ها، ۹۱
drive-by refactorer — بازآرایی drive-by، ۱۶، ۱۶۸

ه

education — آموزش
education, about — دربارهٔ آموزش، ۱۶۱
education, active — فعال، ۱۶۱-۱۶۳
education, passive — passive، ۱۶۴
email transcripts — رونوشت ایمیل، ۶۲
end state — حالت پایانی
end state, defining your — تعریف end state، ۷۲-۷۴
end state, ideal versus acceptable — ideal در برابر acceptable، ۷۴
end state, mapping path between start state and — نگاشت مسیر start به end، ۷۴-۷۶
engineering gatherings — گردهمایی مهندسی، ۱۶۳
engineers — مهندسان
engineers, influence of — نفوذ مهندسان، ۱۰۶
engineers, seeking feedback from senior — feedback از senior، ۱۴۳-۱۴۵
engineers, soliciting feedback from — درخواست feedback، ۶۷
environmental changes, as pertains to code degradation — تغییرات محیطی در degradation، ۳۱
ergonomic interfaces — رابط‌های ergonomic، ۱۶۱
estimates — تخمین‌ها، ۹۰، ۲۱۹
Etsy — ۱۲۸
evidence, relying on — اتکا به evidence، ۱۰۷
execution plan — برنامهٔ اجرا، ۱۴۱-۱۴۳
execution strategies — استرategی‌های اجرا، ۱۴۷-۱۵۸
execution strategies, about — دربارهٔ استرategی اجرا، ۱۴۷
execution strategies, keeping a tally — نگه‌داشت tally، ۱۵۲-۱۵۵
execution strategies, productive programming — برنامه‌نویسی productive، ۱۵۵-۱۵۸
execution strategies, team building — team building، ۱۴۷-۱۵۲
EXPLAIN plans — planهای EXPLAIN، ۱۹۵
experts, identifying types of — شناسایی انواع expert، ۱۱۲
external dependencies, as pertains to code degradation — وابستگی خارجی، ۳۲
extracting magic numbers — استخراج magic number، ۲۲
extracting self-contained logic — استخراج logic self-contained، ۲۳-۲۶

و

Facebook — ۱۷۰
factoring — factoring، ۴
Feathers, Michael — Feathers، Michael
Working Effectively with Legacy CodeWorking Effectively with Legacy Code، ۵۸
feature flags/toggles — feature flag/toggle، ۴۰، ۸۱، ۸۷
feedback, seeking from senior engineers — feedback از senior engineer، ۱۴۳-۱۴۵
files, visibility of — دیدپذیری فایل، ۱۷۸
fixing bugs — رفع باگ، ۱۵۳
Flamework — ۱۷۰
Flickr — ۱۶۹
for loop — حلقه for، ۵۰، ۵۳
formal documentation — مستندسازی رسمی، ۶۱
functions, length of — طول توابع، ۵۶
fun, refactoring out of — بازآرایی از boredom/fun، ۱۶

ز

gates, guardrails versus — gate در برابر guardrail، ۱۶۶
generosity, in pitches — سخاوت در pitch، ۱۲۴
Glitch — ۱۶۹
Google Project Zero — ۳۱
guardrails, gates versus — guardrail در برابر gate، ۱۶۶

ح

Hack — ۱۷۰
Hacklang — ۲۰۹
Halstead Metrics — معیارهای Halstead، ۴۷-۴۹
Halstead, Maurice — Halstead، Maurice، ۴۷
Healthcare.gov — ۶
if statement — if statement، ۵۰، ۵۳

HHVM (HipHop Virtual Machine)

۱۷۰

How to Win Friends and Influence People (Carnegie)

۱۰۴

I

IBM POWER processors — ریزپردازنده IBM POWER، ۳۱
ideal versus acceptable end state — end state ideal در برابر acceptable، ۷۴
if statement — ۵۰، ۵۳
individuals, motivating — انگیزه دادن به افراد، ۱۵۰
informal documentation — مستندسازی غیررسمی، ۶۲-۶۴
initial conversation — گفتگوی اولیه، ۱۰۱
inlined numbers, extracting — استخراج عدد inline، ۲۲
influence of engineers — نفوذ مهندسان، ۱۰۶
Intel x86 microprocessors — ریزپردازنده Intel x86، ۳۱
interfaces, ergonomic — رابط ergonomic، ۱۶۱
iteration, speed of — سرعت iteration، ۴۰

J

JIRA — ۹۵
JOINs, detangling — detangle JOINها، ۲۰۳-۲۰۷

K

keeping changes small — کوچک نگه داشتن تغییرات، ۱۵۶

L

lessons learned, in migrating to a new database case study — درس‌ها در migration DB، ۲۱۹-۲۲۲
lessons learned, in redundant database schemas case study — درس‌ها در scheme تکراری، ۱۹۲
Light mode — حالت Light، ۸۱-۸۶، ۲۰۸، ۲۱۵
light/dark technique — تکنیک light/dark، ۸۱-۸۶
Lisp programming language — Lisp، ۳۲
local user IDs — local user ID، ۲۰۳
LOC (lines of code) — LOC (خطوط کد)، ۵۵-۵۷
logical operators — عملگر منطقی، ۴۷

M

magic numbers, extracting — استخراج magic number، ۲۲
maintenance — نگهداری، ۱۵۹-۱۶۸
maintenance, about — دربارهٔ نگهداری، ۱۵۹
maintenance, education — آموزش، ۱۶۱-۱۶۴
maintenance, fostering adoption — تقویت پذیرش، ۱۶۰
maintenance, integrating improvement into the culture — یکپارچه‌سازی بهبود در culture، ۱۶۷
maintenance, reinforcement — تقویت (reinforcement)، ۱۶۵-۱۶۷
maintenance work — کار نگهداری، ۱۰۸
managers, buy-in from — buy-in از مدیران، ۹۸-۱۰۱
mapping path between start state and end state — نگاشت start به end، ۷۴-۷۶
matchmaking — matchmaking، ۱۱۳-۱۱۷
McCabe, Thomas — McCabe، Thomas، ۵۰
measuring code complexity — اندازه‌گیری پیچیدگی کد، ۴۷-۵۷
measuring impact of refactor — اندازه‌گیری impact بازآرایی، ۴۶
measuring intermediate metrics — معیار میانی، ۱۵۲
meetings, use of technology during — فناوری در جلسات، ۱۳۳
Meltdown security vulnerability — آسیب‌پذیری امنیتی Meltdown، ۳۱
mentions — mentionها، ۱۷۸
metrics — معیارها
metrics, importance of — اهمیت معیارها، ۱۹۵
metrics, in pitches — در pitch، ۱۲۳
metrics, intermediate measurements of — اندازه‌گیری میانی، ۱۵۲
metrics, referencing in plans — ارجاع در برنامه، ۸۸
migrating channels_members to Vitess — migration channels_members به Vitess، ۱۹۹-۲۰۳
migrating to a new database case study — مطالعهٔ migration DB، ۱۹۷-۲۲۲
migrating to a new database case study, about — درباره، ۱۹۷، ۲۲۲
migrating to a new database case study, Backfill mode — Backfill mode، ۲۰۹
migrating to a new database case study, choosing single places for communication — یک مکان communication، ۲۲۱
migrating to a new database case study, cleaning up — پاک‌سازی، ۲۱۷-۲۱۹
migrating to a new database case study, Dark mode — Dark mode، ۲۱۰-۲۱۵
migrating to a new database case study, designing thoughtful rollout plans — rollout plan thoughtful، ۲۲۱
migrating to a new database case study, detangling JOINs — detangle JOIN، ۲۰۳-۲۰۷
migrating to a new database case study, developing new schemes — scheme جدید، ۲۰۱-۲۰۳
migrating to a new database case study, lessons learned — درس‌ها، ۲۱۹-۲۲۲
migrating to a new database case study, Light mode — Light mode، ۲۱۵
migrating to a new database case study, planning scope — برنامه‌ریزی scope، ۲۲۰
migrating to a new database case study, rollout — rollout، ۲۰۸-۲۱۶
migrating to a new database case study, setting realistic estimates — تخمین واقع‌بینانه، ۲۱۹
migrating to a new database case study, sharding scheme — scheme sharding، ۲۰۰
migrating to a new database case study, sourcing teammates — جذب هم‌تیمی، ۲۲۰
migrating to a new database case study, Sunset mode — Sunset mode، ۲۱۶
migrating to a new database case study, workspace-sharded data — داده workspace-sharded، ۱۹۸
migration strategies, developing — تدوین استرategi migration، ۱۸۳-۱۸۵
milestones — نقاط عطف
milestones, distinct metrics for — معیار متمایز، ۸۹
milestones, focusing on strategic — تمرکز راهبردی، ۱۹۵
milestones, identifying strategic intermediate — شناسایی میانی راهبردی، ۷۶-۸۰
motivating teams — انگیزه تیم، ۱۵۰-۱۵۲، ۱۸۷، ۱۹۴
MySQL — ۱۹۹

N

Nejmeh, Brian — ۵۳
Nonviolent Communication (Rosenberg)Nonviolent Communication (Rosenberg)، ۱۳۲
NPath complexity — پیچیدگی NPath، ۵۳-۵۵
NUMA (nonuniform memory access) interleave policy — سیاست interleave NUMA، ۲۱۲

O

office hours — office hours، ۱۶۳
onboarding materials — مواد onboarding، ۶۱
OOMs (out-of-memory errors) — OOM (خطای out-of-memory)، ۲۱۰
operands, in Halstead Metrics — operand در Halstead، ۴۷-۵۷
operators, in Halstead Metrics — operator در Halstead، ۴۷-۵۷
opportunity, in pitches — opportunity در pitch، ۱۲۴
organization, lack of — فقدان organization، ۳۹
out-of-scope items — موارد out-of-scope، ۱۵۴
owners, as a team type — owners به‌عنوان نوع تیم، ۱۱۷-۱۲۰
ownership, of code — مالکیت کد، ۱۶۷

P

PagerDuty — ۶۲، ۱۱۴
pair programming — pair programming، ۱۴۸-۱۵۰
passive education — آموزش passive، ۱۶۴
performance — عملکرد
performance, Dark mode and — Dark mode و عملکرد، ۲۱۰-۲۱۳
performance, refactoring and — بازآرایی و عملکرد، ۱۴
performance, refactoring for improved — بازآرایی برای بهبود عملکرد، ۴۶
perspective, in teams — perspective در تیم، ۹۲
PHP — ۱۷۰
PII (personally identifiable information) — PII (اطلاعات شناسایی شخصی)، ۱۶۰
pitches — pitch، ۱۲۲-۱۲۶
plans, drafting — تدوین برنامه (نگاه کنید به drafting plans)
playing hardball strategy — استرategi playing hardball، ۱۰۸
positive reinforcement — reinforcement مثبت، ۱۶۵
postmortems — postmortem، ۶۲، ۱۲۸
primeFactors function — تابع primeFactors، ۵۷
private channels — کانال خصوصی، ۱۷۳
product development, speed of — سرعت توسعه محصول، ۴۰
product requirements — نیازمندی محصول، ۱۴، ۳۳-۳۶
productivity, developer — بهره‌وری developer، ۹
Program Management in Design and Development — ۱۲۱
programming, choosing languages for — انتخاب زبان، ۳۶
programming, productive — برنامه‌نویسی productive، ۱۵۵-۱۵۸
progress — پیشرفت، ۱۸۶، ۱۸۸
progress announcements — اعلام پیشرفت، ۱۴۱
progressive linting — linting progressive، ۱۶۵
project management software — نرم‌افزار مدیریت پروژه، ۶۳
Prometheus — ۱۱۲
prototyping — prototyping، ۱۵۵
public channels — کانال عمومی، ۱۷۳

Q

quantifying progress — کمی‌سازی پیشرفت، ۱۸۶
queries, gathering scattered — جمع‌آوری query پراکنده، ۱۸۱-۱۸۳

R

range validation — اعتبارسنجی range، ۲۰
realistic scenario — سناریوی realistic، ۱۲۷
recency bias — bias تازگی (recency)، ۱۱۶
redundant database schemas case study — مطالعه scheme تکراری، ۱۷۱-۱۹۶
redundant database schemas case study, about — درباره، ۱۷۱، ۱۹۶
redundant database schemas case study, cleaning up — پاک‌سازی، ۱۹۰
redundant database schemas case study, code history — تاریخچه کد، ۱۹۳-۱۹۶
redundant database schemas case study, consolidating tables — یکپارچه جداول، ۱۸۰-۱۸۹
redundant database schemas case study, lessons learned from — درس‌ها، ۱۹۲
redundant database schemas case study, scalability problems — مشکلات مقیاس‌پذیری، ۱۷۷-۱۷۹
redundant database schemas case study, Slack — Slack، ۱۷۲-۱۷۷
redundant database schemas case study, Slack architecture — معماری Slack، ۱۷۴-۱۷۷
refactoring — بازآرایی
refactoring, about — دربارهٔ بازآرایی، ۳-۶
refactoring, at scale — بازآرایی در مقیاس، ۶-۸
refactoring, benefits of — مزایا، ۹-۱۱
refactoring, buy-in and — buy-in، ۱۰۹-۱۱۰
refactoring, drive-by — drive-by، ۱۶، ۱۶۸
refactoring, example of — مثال، ۱۸-۲۶
refactoring, for fun — برای fun، ۱۶
refactoring, for improved performance — برای عملکرد، ۴۶
refactoring, importance of — اهمیت، ۸
refactoring, measuring — اندازه‌گیری (نگاه کنید به starting state)
refactoring, new technology and — فناوری جدید، ۱۵
refactoring, out of boredom — از boredom، ۱۶
refactoring, performance and — عملکرد، ۱۴
refactoring, rewarding — پاداش، ۱۰۷
refactoring, risks of — ریسک‌ها، ۱۱-۱۳، ۹۹
refactoring, scope and — scope، ۱۳
refactoring, when not to use — چه وقت نه، ۱۶-۱۸
refactoring, when to use — چه وقت، ۱۳-۱۶
regressions, as a risk of refactoring — regression، ریسک، ۱۱
reinforcement, of refactoring — reinforcement بازآرایی، ۱۶۵-۱۶۷
reliability, of tests — reliability تست، ۵۹
repeatable steps, in plan — گام repeatable در برنامه، ۷۹
repeating, in pitches — تکرار در pitch، ۱۲۶
reputation — reputation، ۶۶-۶۹
RESTful service — سرویس RESTful، ۵
retrospectives — retrospective، ۱۳۷
risks, of refactoring — ریسک بازآرایی، ۱۱-۱۳، ۹۹
rollout strategies — استرategi rollout، ۸۰-۸۶، ۲۲۱
Rosenberg, Marshall — Rosenberg، Marshall
Nonviolent CommunicationNonviolent Communication، ۱۳۲

S

scalability — مقیاس‌پذیری، ۲۹، ۱۷۷-۱۷۹
scale, refactoring at — بازآرایی در مقیاس، ۶-۸
scenarios — سناریو، ۱۲۷
schemas, developing new — تدوین scheme جدید، ۲۰۱-۲۰۳
scope — scope، ۱۳، ۲۲۰
scope creep — scope creep، ۱۲، ۹۳
scope, reasonable, as a risk of refactoring — scope reasonable، ریسک، ۱۲
self-contained logic, extracting — استخراج logic self-contained، ۲۳-۲۶
senior engineers, seeking feedback from — feedback senior، ۱۴۳-۱۴۵
sharing plans with teammates — اشتراک برنامه، ۹۱-۹۳
SHRDLU programming language — SHRDLU، ۳۲
simplifying conditionals — ساده‌سازی شرط، ۲۱
skip-level — skip-level، ۱۰۵
Slack — Slack، ۷، ۱۶۹، ۱۷۲-۱۷۷
Smart DNA — Smart DNA، ۷۶، ۷۹، ۸۶، ۱۰۶، ۱۴۲
SMEs (subject matter experts) — SME (متخصص موضوع)، ۱۱۲
Software Design X-Rays (Tornhill)Software Design X-Rays (Tornhill)، ۶۵
Spectre security vulnerability — Spectre، ۳۱
stand-ups — stand-up، ۱۳۳-۱۳۵
starting state — حالت آغازین، ۴۵-۶۹
starting state, about — درباره، ۴۵، ۶۹
starting state, difficulty of measuring refactoring impact — سختی اندازه impact، ۴۶
starting state, documentation — مستندسازی، ۶۰-۶۴
starting state, mapping path between end state and — نگاشت به end state، ۷۴-۷۶
starting state, measuring code complexity — پیچیدگی کد، ۴۷-۵۷
starting state, reputation — reputation، ۶۶-۶۹
starting state, test coverage metrics — معیار پوشش تست، ۵۷-۶۰
starting state, version control — کنترل نسخه، ۶۴-۶۶
StatsD — ۱۱۲
strategies — استرategi
strategies, for achieving buy-in — دستیابی به buy-in، ۱۰۱-۱۰۹
strategies, migration — migration، ۱۸۳
strategies, rollout — rollout، ۸۰-۸۶، ۲۲۱
strength, of teams — قوت تیم، ۱۲۸
style guides — style guide، ۶۱
Sunset mode — Sunset mode، ۲۰۸، ۲۱۶
switch blocks — switch block، ۵۰
syncs, weekly — sync هفتگی، ۱۳۵-۱۳۷
system — system، ۴

T

tables, consolidating — یکپارچه جداول، ۱۸۰-۱۸۹
tally, keeping a — نگه‌داشت tally، ۱۵۲-۱۵۵
TDD (test-driven development) — TDD، ۵۷
team building — team building، ۱۴۷-۱۵۲
team building, about — درباره، ۱۴۷
team building, motivating everyone — انگیزه همه، ۱۵۰-۱۵۲
team building, pair programming — pair programming، ۱۴۸-۱۵۰
teams — تیم‌ها، ۱۱۱-۱۲۸
teams, about — دربارهٔ تیم‌ها، ۱۱۱
teams, fostering strong — تقویت تیم قوی، ۱۲۸
teams, identifying experts — شناسایی expert، ۱۱۲
teams, matchmaking — matchmaking، ۱۱۳-۱۱۷
teams, motivating — انگیزه، ۱۸۷، ۱۹۴
teams, outcomes — outcome، ۱۲۶-۱۲۸
teams, pitch — pitch، ۱۲۲-۱۲۶
teams, rallying teammates — rally هم‌تیمی، ۱۰۵
teams, sourcing teammates — جذب هم‌تیمی، ۲۲۰
teams, tiger — tiger team، ۱۲۱
teams, types of — انواع تیم، ۱۱۷-۱۲۱
tech debt — بدهی فنی
tech debt, lack of organization — فقدان organization، ۳۹
tech debt, speed of iteration and product development — سرعت iteration و محصول، ۴۰
tech debt, technology choices and — انتخاب فناوری، ۳۶-۳۹
technical program managers — مدیر برنامه فنی، ۶۴
technical specs — spec فنی، ۶۱
technology — فناوری
technology, choices in — انتخاب فناوری، ۳۶-۳۹
technology, refactoring and new — بازآرایی و فناوری جدید، ۱۵
technology, use of during meetings — در جلسات، ۱۳۳
test coverage — پوشش تست، ۵۷-۶۰، ۱۹۴
tests — تست‌ها
tests, importance of — اهمیت، ۱۵۷
tests, reliability of — reliability، ۵۹
tests, resiliency of — resiliency، ۵۹
tests, types of — انواع، ۵۹
thought process, complimenting — compliment فرایند فکر، ۱۰۳
tiger team — tiger team، ۱۲۱
Tiny Speck — Tiny Speck، ۱۶۹، ۱۸۴
tools, for code analysis — ابزار تحلیل کد، ۱۶۶
Tornhill, Adam — Tornhill، Adam
Software Design X-RaysSoftware Design X-Rays، ۶۵
trades, experts of many — expert چند trade، ۱۱۵
transparency, in teams — شفافیت در تیم، ۹۲
Trello — ۹۵
types — type، ۶۰

U

ultimatums — ultimatum، ۱۰۹
UML (Unified Modeling Language) — UML، ۶۱
unit tests, cleaning up — پاک‌سازی unit test، ۸۸
University of Utah — ۱۴۸
unused code, as pertains to code degradation — کد unused، ۳۲
useAverage argument — آرگومان useAverage، ۲۰، ۲۵
user-sharded membership table — جدول عضویت user-sharded، ۲۰۲

V

validateUser function — تابع validateUser، ۳۸
version control — کنترل نسخه
version control, about — درباره، ۶۴
version control, commit messages — پیام commit، ۶۴
version control, commits in aggregate — commit aggregate، ۶۵
visibility, of files — دیدپذیری فایل، ۱۷۸
Vitess, migrating channels_members to — migration به Vitess، ۱۹۹-۲۰۳

W

WAI (Web Accessibility Initiative) — WAI، ۳۰
weekly syncs — sync هفتگی، ۱۳۵-۱۳۷
while loop — while loop، ۵۰، ۵۳
Working Effectively with Legacy Code (Feathers)Working Effectively with Legacy Code، ۵۸
workshops — workshop، ۱۶۲
workspace-sharded data — داده workspace-sharded، ۱۹۸
worst-case scenario — worst-case، ۱۲۷

Z

Zend Engine II/III — Zend Engine II/III، ۱۷۰


دربارهٔ نویسنده

Maude Lemaire مهندس در Slack Technologies, Inc. است و روی مقیاس‌پذیر کردن محصول برای پشتیبانی از بزرگ‌ترین سازمان‌های جهان کار می‌کند. بیشتر وقتش را صرف پیگیری افراد، فراخوانی شبکه در حلقه، بازآرایی قطعات فزون‌دستانهٔ کد، یکپارچه‌سازی طرحواره‌های پایگاه دادهٔ تکراری و ساخت ابزار برای توسعه‌دهندگان دیگر می‌کند. Maude عمیقاً به تجربه‌ٔ توسعه‌دهنده اهمیت می‌دهد و در هر نقش، در سطوح مختلف پشته، راه‌های ساده‌تر و کارآمدتر ساختار کد را جست‌وجو کرده است.

Maude مدرک BSc. در رشته‌ٔ Honours Software Engineering از دانشگاه McGill دارد.

Colophon

حیوان روی جلد Refactoring at Scale گراز دریایی (Odobenus rosmarus) است؛ پستاندار دریایی بزرگ در مناطق قطب شمال و زیرقطب شمال.

گراز دریایی به‌خاطر دندان‌های بلند و تیز (شاخ‌دندان) شناخته می‌شود که در شکستن یخ، بالا آمدن از آب، برتری در گله و دفاع در برابر شکارچیان کمک می‌کند. پوست ضخیم با مو کم، رنگی از خاکستری تا قهوه‌ای-زرد. لایه‌ٔ چربی ضخیم‌تر گرما و انرژی ذخیره‌شده فراهم می‌کند.

این گوشت‌خوار کند‌حرکت در یخ و آب کم‌عمق زندگی می‌کند تا به غذا دسترسی آسان داشته باشد و فصلی مهاجرت می‌کند. بال‌پای جلو کوتاه و عقب بزرگ‌تر او را در آب پیش می‌برد؛ سبیل‌ها بیش از چشم برای ناوبری و شناسایی غذا به‌کار می‌روند. بیشتر صدف‌دوزی‌ها و سایر نرم‌تنان را می‌خورد؛ گاه پرندگان دریایی و حتی فک.

تغییر اقلیم جهانی و شکار انسان وضعیت حفاظت آن را «آسیب‌پذیر» (Vulnerable) قرار داده است. بسیاری از حیوانات روی جلدهای O’Reilly در معرض انقراض‌اند؛ همه برای جهان اهمیت دارند.

تصویر جلد اثر Karen Montgomery است، بر پایه‌ٔ حکاکی سیاه‌وسفید از Natural History of Animals اثر Vogt & Specht. فونت‌های جلد: Gilroy Semibold و Guardian Sans. فونت متن: Adobe Minion Pro؛ فونت سرفصل‌ها: Adobe Myriad Condensed؛ فونت کد: Ubuntu Mono از Dalton Maag.


محتوای بیشتری در oreilly.com/online-learning

©۲۰۱۹ O’Reilly Media, Inc. O’Reilly trademark ثبت‌شدهٔ O’Reilly Media, Inc. است.