فرض کنید سه تیم مختلف برای حذف اطلاعات از محصول، سه تجربه متفاوت طراحی کردهاند. تیم اول قبل از حذف یک Dialog تأیید نمایش میدهد، تیم دوم داخل همان Dialog درباره پیامدهای حذف توضیح میدهد و تیم سوم اصلاً از Confirmation استفاده نمیکند و بعد از حذف، امکان Undo را در اختیار کاربر قرار میدهد.
نکته جالب اینجاست که هر سه تیم از Design System استفاده کردهاند. Buttonها از Library رسمی آمدهاند، Dialog همان Component تعریفشده در سیستم است، رنگها و Typography از Tokenهای مشترک استفاده میکنند و حتی Iconها هم مطابق استاندارد هستند. بنابراین اگر فقط میزان استفاده از Componentها را بررسی کنیم، هر سه تیم کاملاً مطابق Design System عمل کردهاند، اما تجربهای که کاربر دریافت میکند همچنان متفاوت است.
اینجاست که تفاوت میان Component و Pattern اهمیت پیدا میکند.
Componentهای مشترک لزوماً تجربه مشترک نمیسازند
یکی از کارهایی که Design Systemها بهخوبی انجام میدهند، استاندارد کردن اجزای Interface است. سیستم مشخص میکند Button چه Stateهایی داشته باشد، Input خطا را چگونه نمایش دهد، Dialog چه ساختاری داشته باشد و Snackbar از نظر ظاهر و رفتار چگونه کار کند.
اما بسیاری از تصمیمهایی که تجربه کاربر را شکل میدهند داخل یک Component اتفاق نمیافتند. برای مثال، Component مربوط به Dialog میتواند ساختار Header، Content و Actionها را مشخص کند، اما به ما نمیگوید چه زمانی اصلاً باید Dialog نمایش دهیم، آیا هر اقدام خطرناکی نیازمند Confirmation است، چه زمانی Undo انتخاب بهتری است یا قبل از یک اقدام غیرقابلبازگشت چه اطلاعاتی باید به کاربر نشان داده شود.
اینها دیگر صرفاً تصمیمهای مربوط به UI نیستند، بلکه تصمیمهایی درباره نحوه حل یک مسئله تکرارشونده در تجربه کاربر هستند. این همان جایی است که Patternها در Design System معنا پیدا میکنند.
شاید چیزی که کم داریم Component جدید نباشد
وقتی چند تیم با یک مسئله مشابه روبهرو میشوند، واکنش طبیعی این است که برای آن یک Component جدید بسازیم. برای مثال، اگر چند محصول برای حذف اطلاعات Confirmation مشابهی دارند، ممکن است تصمیم بگیریم یک Component اختصاصی برای Delete Confirmation ایجاد کنیم.
این راهحل در ابتدا منطقی به نظر میرسد، اما خیلی زود نیازهای متفاوت ظاهر میشوند. یک تیم برای Archive کردن رفتار دیگری میخواهد، تیم دیگری باید داخل Confirmation یک Checkbox قرار دهد و محصول دیگری نیاز دارد قبل از Action یک Warning جدی نمایش دهد. Componentی که قرار بود مسئله سادهای را حل کند، کمکم شروع به جذب منطق چند Use Case متفاوت میکند و API آن پیچیدهتر میشود.
درحالیکه شاید از ابتدا مسئله کمبود Component نبوده باشد. تیمها Dialog، Button، Alert و Snackbar را از قبل در اختیار داشتهاند؛ چیزی که نداشتهاند یک منطق مشترک برای تصمیمگیری درباره اقدامات حساس بوده است.
برای مثال، یک Pattern میتواند مشخص کند که اگر Action بهراحتی قابل بازگشت است، بهتر است بهجای متوقف کردن کاربر با Confirmation امکان Undo در اختیار او قرار بگیرد. اگر Action پیامد جدی و غیرقابلبازگشتی دارد، Confirmation اهمیت بیشتری پیدا میکند و اگر پیامد تصمیم برای کاربر واضح نیست، باید قبل از انجام Action توضیح دهیم دقیقاً چه اتفاقی خواهد افتاد.
در چنین شرایطی، Design System بهجای تحمیل یک UI ثابت، منطق پشت انتخاب UI را استاندارد میکند.
تفاوت Component و Pattern فقط در اندازه آنها نیست
گاهی Pattern را بهاشتباه یک Component بزرگتر در نظر میگیریم؛ انگار Button یک Component کوچک است و Form یا Confirmation Flow چون از چند Component تشکیل شدهاند، Pattern محسوب میشوند.
اما تفاوت اصلی در اندازه نیست، بلکه در نوع مسئلهای است که حل میکنند.
یک Component معمولاً مشخص میکند یک بخش از Interface چگونه ساخته و استفاده شود، درحالیکه Pattern راهنمایی میکند وقتی با یک مسئله مشخص در تجربه کاربر مواجه شدیم، چه تصمیمهایی بگیریم و چگونه از Componentهای موجود برای حل آن استفاده کنیم.
برای مثال، Text Field یک Component است، اما نحوه Validation یک Form میتواند Pattern باشد. Dialog یک Component است، اما مدیریت یک Destructive Action میتواند Pattern باشد. Snackbar یک Component است، اما نحوه ارائه Feedback بعد از انجام یک Action میتواند بخشی از یک Pattern باشد.
به همین دلیل، ارزش Pattern فقط در این نیست که چند Component را کنار هم قرار میدهد؛ ارزش اصلی آن در ثبت و تکرار یک تصمیم UX است.
ممکن است در سطح Component Consistent باشیم، اما در سطح Experience نه
این تفاوت یک مسئله مهم دیگر را هم آشکار میکند. ممکن است آمار Design System نشان دهد که بخش بزرگی از محصولات از Componentهای رسمی استفاده میکنند و Adoption سیستم هم بالا به نظر برسد، اما وقتی Flowهای واقعی محصولات را کنار هم قرار میدهیم، متوجه شویم یک مسئله مشابه در هر محصول به شکل متفاوتی حل شده است.
از نگاه Design System همهچیز درست به نظر میرسد، چون Button، Dialog، Input و سایر اجزا از Library آمدهاند، اما کاربر Library ما را نمیبیند. کاربر فقط تجربه محصول را میبیند.
اگر حذف اطلاعات در یک بخش با Confirmation انجام شود، در بخش دیگری بلافاصله اتفاق بیفتد و جای دیگری نیازمند چند مرحله باشد، استفاده از Button مشترک بهتنهایی تجربه Consistent ایجاد نمیکند.
به همین دلیل، بلوغ یک Design System فقط به این نیست که چه تعداد Component را استاندارد کرده است. در مرحلهای بالاتر باید ببینیم آیا تصمیمهایی که با این Componentها گرفته میشوند هم منطق مشترکی دارند یا نه.
Pattern قرار نیست همه محصولات را شبیه هم کند
البته اینجا نباید به سمت افراط دیگری برویم و برای هر مسئله یک Flow ثابت تعریف کنیم که تمام تیمها مجبور باشند دقیقاً همان را اجرا کنند.
برای مثال، یک Pattern برای Empty State میتواند اصول مشترکی داشته باشد؛ باید وضعیت را برای کاربر توضیح دهد، در صورت نیاز قدم بعدی را مشخص کند و Action مناسبی ارائه دهد. بااینحال Empty State مربوط به اولین ورود کاربر به محصول الزاماً نباید دقیقاً شبیه وضعیت بدون نتیجه در Search باشد، چون Context، هدف کاربر و قدم بعدی در این دو موقعیت متفاوت است.
بنابراین Pattern خوب معمولاً یک Template غیرقابلتغییر نیست. Pattern بیشتر یک چارچوب تصمیمگیری است که مشخص میکند چه اصولی ثابتاند، چه تصمیمهایی باید گرفته شوند و کدام بخشها میتوانند براساس Context محصول تغییر کنند.
این تفاوت مهمی است، چون هدف Pattern حذف اختیار تیم محصول نیست؛ هدف این است که تیمها برای مسائل تکرارشونده مجبور نباشند هر بار تمام تصمیمهای UX را از صفر بگیرند.
یک Pattern خوب فقط مجموعهای از Screenshotها نیست
یکی دیگر از مشکلاتی که ممکن است در Pattern Libraryها ببینیم این است که Pattern به یک نمونه UI تبدیل میشود. تصویری از یک Empty State یا Error State در Documentation قرار میدهیم و انتظار داریم تیمهای دیگر متوجه شوند چطور باید از آن استفاده کنند.
اما اگر فقط نتیجه نهایی را نشان دهیم، احتمال زیادی وجود دارد که Designer همان UI را در Context دیگری کپی کند، بدون اینکه بداند چرا این راهحل انتخاب شده است.
مستندات Pattern باید علاوه بر نمونه بصری توضیح دهند که این Pattern چه مسئلهای را حل میکند، چه زمانی مناسب است، چه زمانی نباید از آن استفاده شود، چه اصولی در تمام حالتها ثابت هستند و کدام بخشها براساس Context قابل تغییرند.
حتی نمایش چند نمونه متفاوت از یک Pattern میتواند مفیدتر از ارائه یک نمونه ایدهآل باشد، چون به تیمها کمک میکند بفهمند منطق مشترک بین نمونهها چیست، نه اینکه صرفاً ظاهر یکی از آنها را کپی کنند.
گاهی Pattern باید قبل از Component شکل بگیرد
یکی از زاویههای جالب این بحث این است که همیشه لازم نیست ابتدا Component بسازیم و بعد برای نحوه استفاده از آن Pattern تعریف کنیم. گاهی مسیر بهتر دقیقاً برعکس است.
فرض کنید چند محصول با مسئله مشابهی مثل Bulk Action روبهرو شدهاند و هرکدام راهحلی برای آن ساختهاند. شاید در این مرحله هنوز زود باشد که یک Component عمومی وارد Core کنیم، چون هنوز نمیدانیم کدام قسمتهای این راهحلها واقعاً مشترک و پایدار هستند.
در چنین شرایطی میتوانیم ابتدا تجربههای مختلف را کنار هم قرار دهیم، نقاط مشترک را پیدا کنیم و یک Pattern اولیه برای مسئله تعریف کنیم. با استفاده بیشتر از آن Pattern، بهمرور مشخص میشود چه بخشهایی واقعاً ثابت هستند و چه بخشهایی براساس Context تغییر میکنند.
اگر بعد از مدتی متوجه شویم بخشی از راهحل تقریباً در تمام محصولات به شکل یکسان تکرار میشود، آن بخش میتواند کاندیدای خوبی برای تبدیل شدن به Component باشد.
این مسیر کمک میکند قبل از اینکه مسئله را بهاندازه کافی بشناسیم، برای آن Abstraction نسازیم. درواقع گاهی Pattern میتواند مرحلهای برای یادگیری قبل از ساخت Component باشد.
از کجا بفهمیم به Pattern نیاز داریم؟
یکی از نشانههای مهم زمانی است که چند تیم از Componentهای درست استفاده میکنند، اما برای یک مسئله مشابه تصمیمهای UX متفاوتی میگیرند.
اگر یک تیم Error را داخل Form نمایش میدهد، تیم دیگر از Toast استفاده میکند و تیم سوم کاربر را به صفحه دیگری میفرستد، شاید مشکل کمبود Error Component نباشد. اگر هر محصول Empty State متفاوتی دارد، شاید نیازی به ساخت EmptyStateComponent پیچیدهتر نداشته باشیم و ابتدا باید مشخص کنیم یک Empty State خوب در Contextهای مختلف چه اصولی دارد.
در چنین موقعیتهایی، قبل از اینکه Component جدیدی بسازیم بهتر است بپرسیم:
آیا چیزی که در محصولات تکرار شده یک UI مشترک است، یا یک مسئله مشترک؟
اگر UI واقعاً پایدار و تکرارشونده باشد، Component میتواند پاسخ مناسبی باشد. اما اگر مسئله مشترک است و راهحل آن براساس Context تغییر میکند، احتمالاً Pattern ابزار مناسبتری است.
پس چرا به هر دو نیاز داریم؟
Componentها و Patternها دو سطح متفاوت از Design System را پوشش میدهند. Componentها Building Blockهای مشترکی در اختیار تیمها قرار میدهند تا لازم نباشد عناصر پایه Interface بارها ساخته شوند، درحالیکه Patternها دانش و تصمیمهای مشترک درباره نحوه حل مسائل تکرارشونده را در اختیار تیمها میگذارند.
اگر فقط Pattern داشته باشیم و Component مشترکی وجود نداشته باشد، پیادهسازیها پراکنده میشوند. اگر فقط Component داشته باشیم و Pattern نداشته باشیم، ممکن است Interface محصولات از نظر بصری شبیه هم باشد، اما رفتار و تجربه آنها همچنان متفاوت باقی بماند.
شاید به همین دلیل، یکی از نشانههای بلوغ Design System این باشد که تیم بهجای اینکه برای هر تکرار فوراً بپرسد «چه Component جدیدی باید بسازیم؟»، ابتدا سؤال دقیقتری مطرح کند:
چیزی که اینجا باید استاندارد شود، خود UI است یا منطق حل مسئله؟
چون در یک Design System بالغ، همیشه چیزی که باید Reusable شود یک قطعه Interface نیست؛ گاهی چیزی که ارزش استفاده مجدد دارد، تصمیمی است که پشت آن Interface گرفتهایم.
کامنتها
…