بدون کد خود عاشق نشوید

Summarize this content to 400 words in Persian Lang
من فقط صدها خط کدی را که دیروز نوشتم حذف کردم و 32 خط کد جدید را جایگزین آنها کردم. این برای ویژگی TheOpenPresenter بود که برای نشان دادن اینکه آیا صدا در حال پخش است یا خیر.
هر چند وقت یکبار، من روی عملکردی کار می کنم که اجرای آن کاملاً ساده به نظر می رسد. در این مورد، من فقط باید این نماد را هنگام پخش صدا نشان دهم.
به اندازه کافی ساده هر یک از اینها یک صحنه حاوی چندین پلاگین است. هر افزونه دارای ویژگی های خاص خود است isPlaying . ما می توانیم مقادیر را بین افزونه ها ادغام کنیم و اگر پرچم درست باشد، می توانیم نماد را نشان دهیم.
معماری یک راه حل
مسئله اصلی نحوه دسترسی به این داده ها است. ببینید، ما میتوانیم مستقیماً به دادهها دسترسی داشته باشیم. اما هر افزونه می تواند شمای خاص خود را داشته باشد. در حالی که برخی از افزونه ها ممکن است ساده باشند در حال پخش است اموال، برخی دیگر ممکن است برای نشان دادن وضعیت بازی خود به چیز پیچیده تری نیاز داشته باشند.
ساده است.
این همان الگویی است که TheOpenPresenter برای بسیاری از افزونه های خود استفاده می کند. و در حالی که ما در آن هستیم، می توانیم آن را به یک انتزاع کنیم وضعیت صحنه شی بنابراین اگر زمانی به حالت دیگری نیاز داشتیم، میتوانیم آن را در اینجا اضافه کنیم. در اینجا ممکن است برای این افزونه به نظر برسد:
// The pattern we use for plugins
serverPluginApi.onPluginDataCreated(pluginName, onPluginDataCreated);
serverPluginApi.onPluginDataLoaded(pluginName, onPluginDataLoaded);
serverPluginApi.registerRemoteViewWebComponent(
pluginName,
remoteWebComponentTag,
);
// Example of how the new API might look like
serverPluginApi.registerSceneState(
pluginName,
(_, rendererData) => {
return {
audioIsPlaying: !!rendererData.find((x) => x.isPlaying),
}
},
);
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
مدیریت سرور
توجه داشته باشید که کد بالا در سرور مدیریت می شود. این به این دلیل است که TheOpenPresenter از 3 مؤلفه جداگانه تشکیل شده است:
کنترل از راه دور – جایی که این نشانه صوتی نشان داده می شود
رندر – صدا را پخش می کند
سرور – این دو را به هم متصل می کند
در حالت ایدهآل، ما باید این را در قسمت جلویی (ریموت) مدیریت کنیم تا بار اضافی به سرور اضافه نکنیم. با این حال، ثبت این عملکرد ممکن است کثیف باشد. فرانت اند ما از یک معماری میکرو پیشانی بارگذاری شده با اجزای وب استفاده می کند.
ناحیه قرمز رنگ زیر پوسته React است. منطقه سبز از طریق اجزای وب بارگذاری می شود و توسط هر افزونه مدیریت می شود.
توجه داشته باشید که نماد صدا در سمت چپ پوسته قرار دارد. چگونه عملکرد مورد نیاز خود را به پوسته ارائه کنیم؟ ما میتوانیم یک تابع JS را در بستهبندی کامپوننتهای وب قرار دهیم، اما در درازمدت به نظر میرسد درهم و برهم باشد.
به نظر می رسد انجام این کار در سرور راه مناسبی برای انجام این کار باشد.
لوله کشی داده ها از طریق
با این تصمیم، زمان اجرا فرا رسیده است. چند کار برای انجام دادن وجود دارد:
API افزونه را ایجاد کنید
این داده ها را در قسمت جلو ارائه دهید
UI را مصرف و به روز کنید
در حال اجرا
من شما را با جزئیات خسته نمی کنم، بنابراین در اینجا یک مرور کلی وجود دارد. API کاملاً ساده نبود زیرا داده های ما می تواند کاملاً گیج کننده باشد. به طور خلاصه: یک صحنه می تواند چندین پلاگین داشته باشد. و ممکن است چندین رندر وجود داشته باشد که هر کدام یک صحنه را به روشی متفاوت مشاهده می کنند. بنابراین یک افزونه می تواند چندین رندر داشته باشد که آن را به روش های مختلف نشان می دهد. اما با کمی دستکاری داده ها، مشکل حل شد.
مصرف و به روز رسانی UI
مصرف ارزش ساده بود. من در نظر داشتم از پروتکل آگاهی Yjs برای ارائه داده استفاده کنم زیرا زمان واقعی است و چارچوب از قبل در محل موجود است. وضعیت به این ترتیب ذخیره می شود. با این حال، گنجاندن این داده ها از سرور مشکل خودش است. بنابراین تصمیم گرفتم به جای آن از GraphQL استفاده کنم – پروتکلی که ما برای هر چیز دیگری در پلتفرم استفاده می کنیم.
بنابراین تنها کاری که باید انجام دهیم این است که نقطه پایانی را فراخوانی کنیم، با استفاده از اشتراک GraphQL به آن گوش دهیم و در صورت نیاز نماد را نشان دهیم. انجام شد.
ارائه این داده ها به فرانت اند
خوشبختانه، ما از Postgraphile استفاده می کنیم که گسترش طرح GraphQL را کاملاً ساده می کند. ما همچنین میتوانیم آن را به سادگی با افزودن یک اشتراک تبدیل کنیم @pgSubscription به طرح GraphQL. سپس موضوعی را تماشا میکند و هر زمان که تماس میگیریم، مقدار آن را بهروزرسانی میکند pg_notify در مورد آن موضوع به عنوان مثال:
await pgPool.query(
`select pg_notify(‘graphql:sceneState:${id}’,'{}’);`,
[],
);
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
دستکاری داده ها آزاردهنده بود اما فقط کمی صبر و شکیبایی انجام شد!
آخرین قطعه پازل در حال فراخوانی است pg_notify زمانی که ما نیاز داریم
برای این کار، میتوانیم یک شنونده به حالت (Yjs) اضافه کنیم و هر زمان که چیزی تغییر کرد، notify را فراخوانی کنیم:
state.observeDeep(async () => {
// Call pg_notify here
});
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
تنها کاری که باید انجام دهید بهبود عملکرد است. در حال حاضر، این تابع برای هر تغییر کوچک فراخوانی می شود، همچنین به قسمت جلویی به روز می شود. ما میتوانیم وضعیت بهدستآمده را محاسبه کنیم و اگر چیزی تغییر کند قبل از فشار دادن بهروزرسانی، مقایسه کنیم.
راه حل بهتر
اکنون این راه حل مطمئناً کار می کند. اما از اینکه ما به تک تک تغییرات گوش میدادیم متنفر بودم. این غیرضروری است و من مطمئن نیستم که عملکرد چگونه مقیاس خواهد شد. آیا راه حل بهتری وجود دارد؟
بنابراین یک لحظه عقب رفتم و ایده ای به ذهنم رسید: چطور به سراغ اصول اولیه برویم و از داده های Yjs استفاده کنیم؟
مشکل این بود که هر افزونه ممکن است از روش های مختلفی برای نشان دادن وضعیت پخش استفاده کند. بنابراین ما به راهی نیاز داشتیم تا بدانیم چگونه حالت حاصل را خودمان محاسبه کنیم. اما به جای اینکه به کاربر اجازه عبور یک تابع را بدهید، چرا ملکی را رزرو نمی کنید که بتوانند از آن برای نشان دادن این موضوع استفاده کنند؟
به جای ارسال یک تابع برای محاسبه وضعیت، هر افزونه می تواند وضعیت رزرو شده را مستقیماً در کنار داده های موجود خود با ویژگی هایی مانند تنظیم کند. __audioIsPlaying . آنها میتوانند مستقیماً از این مقدار استفاده کنند، یا میتوانند آن را با ویژگیهای موجود خود هماهنگ نگه دارند، مانند:
const onRendererDataLoaded = (
rendererData,
) => {
watchYjs(
// Watch the isPlaying property
(x) => x.isPlaying,
() => {
// And if it changes, sync the __audioIsPlaying property
rendererData.set(“__audioIsPlaying”, rendererData.get(“isPlaying”));
},
);
};
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
حذف کدهای قدیمی
روش جدید فوق العاده است. بدون شنونده اضافی، بدون API اضافی، فقط یک ویژگی رزرو شده ساده.
هزینه؟ خب من قبلا 95% اجرای اول رو نوشتم🫣
**” وقتی این همه مدت روی آن کار کرده ام، خیلی شرم آور است که این را حذف کنم. هر چیز دیگری غیر از این یک چیز عالی است!»* – ذهن من *
این اولین بار نیست. نه دوم و نه سوم این بار فقط چند ساعت کار بود. هر چه زمان بیشتری برای پیاده سازی طول بکشد، رها کردن آن سخت تر است. اما اگر نباید به سرورها متصل شویم، نباید به کدی که می نویسیم نیز متصل شویم.
واضح است که اجرای دوم بهتر است. این سریعتر، قطعات متحرک کمتر، سطح API کمتر و کد کمتری برای نگهداری است. اجرای اول 289 خط جدید اضافه کرد در حالی که اجرای دوم فقط 32 خط جدید اضافه کرد.
آن وقت چه درسی باید یاد گرفت؟
خب، شاید ابتدا ساده ترین راه حل را پیدا کنید. اما گاهی اوقات فقط با فکر کردن به بهترین راه حل نمی رسیم. اگر اینطور است، کد خود را دوست نداشته باشید و از دور انداختن آن نترسید. و شاید یک پست وبلاگ بنویسید تا چیزی از آن به دست آورید!
اگر تا اینجا خوانده اید، ممکن است بخواهید TheOpenPresenter را امتحان کنید! این یک سیستم ارائه منبع باز است که به شما امکان می دهد هر یک از صفحه نمایش های خود را از راه دور کنترل کنید.
نمایش اسلایدها، پخش ویدیوها، استفاده به عنوان داشبورد و بسیاری موارد دیگر. همانطور که از این پست می توانید متوجه شوید این نرم افزار هنوز در مراحل اولیه توسعه قرار دارد، اما به اندازه کافی پایدار است تا به طور منظم از آن استفاده کنید. من شخصاً هر هفته از آن برای جلساتم استفاده می کنم.
هر سوالی دارید بپرسید یا با خیال راحت مشکلات موجود در مخزن Github را گزارش کنید.
من فقط صدها خط کدی را که دیروز نوشتم حذف کردم و 32 خط کد جدید را جایگزین آنها کردم. این برای ویژگی TheOpenPresenter بود که برای نشان دادن اینکه آیا صدا در حال پخش است یا خیر.
هر چند وقت یکبار، من روی عملکردی کار می کنم که اجرای آن کاملاً ساده به نظر می رسد. در این مورد، من فقط باید این نماد را هنگام پخش صدا نشان دهم.
به اندازه کافی ساده هر یک از اینها یک صحنه حاوی چندین پلاگین است. هر افزونه دارای ویژگی های خاص خود است isPlaying
. ما می توانیم مقادیر را بین افزونه ها ادغام کنیم و اگر پرچم درست باشد، می توانیم نماد را نشان دهیم.
معماری یک راه حل
مسئله اصلی نحوه دسترسی به این داده ها است. ببینید، ما میتوانیم مستقیماً به دادهها دسترسی داشته باشیم. اما هر افزونه می تواند شمای خاص خود را داشته باشد. در حالی که برخی از افزونه ها ممکن است ساده باشند در حال پخش است اموال، برخی دیگر ممکن است برای نشان دادن وضعیت بازی خود به چیز پیچیده تری نیاز داشته باشند.
ساده است.
این همان الگویی است که TheOpenPresenter برای بسیاری از افزونه های خود استفاده می کند. و در حالی که ما در آن هستیم، می توانیم آن را به یک انتزاع کنیم وضعیت صحنه شی بنابراین اگر زمانی به حالت دیگری نیاز داشتیم، میتوانیم آن را در اینجا اضافه کنیم. در اینجا ممکن است برای این افزونه به نظر برسد:
// The pattern we use for plugins
serverPluginApi.onPluginDataCreated(pluginName, onPluginDataCreated);
serverPluginApi.onPluginDataLoaded(pluginName, onPluginDataLoaded);
serverPluginApi.registerRemoteViewWebComponent(
pluginName,
remoteWebComponentTag,
);
// Example of how the new API might look like
serverPluginApi.registerSceneState(
pluginName,
(_, rendererData) => {
return {
audioIsPlaying: !!rendererData.find((x) => x.isPlaying),
}
},
);
مدیریت سرور
توجه داشته باشید که کد بالا در سرور مدیریت می شود. این به این دلیل است که TheOpenPresenter از 3 مؤلفه جداگانه تشکیل شده است:
- کنترل از راه دور – جایی که این نشانه صوتی نشان داده می شود
- رندر – صدا را پخش می کند
- سرور – این دو را به هم متصل می کند
در حالت ایدهآل، ما باید این را در قسمت جلویی (ریموت) مدیریت کنیم تا بار اضافی به سرور اضافه نکنیم. با این حال، ثبت این عملکرد ممکن است کثیف باشد. فرانت اند ما از یک معماری میکرو پیشانی بارگذاری شده با اجزای وب استفاده می کند.
ناحیه قرمز رنگ زیر پوسته React است. منطقه سبز از طریق اجزای وب بارگذاری می شود و توسط هر افزونه مدیریت می شود.
توجه داشته باشید که نماد صدا در سمت چپ پوسته قرار دارد. چگونه عملکرد مورد نیاز خود را به پوسته ارائه کنیم؟ ما میتوانیم یک تابع JS را در بستهبندی کامپوننتهای وب قرار دهیم، اما در درازمدت به نظر میرسد درهم و برهم باشد.
به نظر می رسد انجام این کار در سرور راه مناسبی برای انجام این کار باشد.
لوله کشی داده ها از طریق
با این تصمیم، زمان اجرا فرا رسیده است. چند کار برای انجام دادن وجود دارد:
- API افزونه را ایجاد کنید
- این داده ها را در قسمت جلو ارائه دهید
- UI را مصرف و به روز کنید
در حال اجرا
من شما را با جزئیات خسته نمی کنم، بنابراین در اینجا یک مرور کلی وجود دارد. API کاملاً ساده نبود زیرا داده های ما می تواند کاملاً گیج کننده باشد. به طور خلاصه: یک صحنه می تواند چندین پلاگین داشته باشد. و ممکن است چندین رندر وجود داشته باشد که هر کدام یک صحنه را به روشی متفاوت مشاهده می کنند. بنابراین یک افزونه می تواند چندین رندر داشته باشد که آن را به روش های مختلف نشان می دهد. اما با کمی دستکاری داده ها، مشکل حل شد.
مصرف و به روز رسانی UI
مصرف ارزش ساده بود. من در نظر داشتم از پروتکل آگاهی Yjs برای ارائه داده استفاده کنم زیرا زمان واقعی است و چارچوب از قبل در محل موجود است. وضعیت به این ترتیب ذخیره می شود. با این حال، گنجاندن این داده ها از سرور مشکل خودش است. بنابراین تصمیم گرفتم به جای آن از GraphQL استفاده کنم – پروتکلی که ما برای هر چیز دیگری در پلتفرم استفاده می کنیم.
بنابراین تنها کاری که باید انجام دهیم این است که نقطه پایانی را فراخوانی کنیم، با استفاده از اشتراک GraphQL به آن گوش دهیم و در صورت نیاز نماد را نشان دهیم. انجام شد.
ارائه این داده ها به فرانت اند
خوشبختانه، ما از Postgraphile استفاده می کنیم که گسترش طرح GraphQL را کاملاً ساده می کند. ما همچنین میتوانیم آن را به سادگی با افزودن یک اشتراک تبدیل کنیم @pgSubscription
به طرح GraphQL. سپس موضوعی را تماشا میکند و هر زمان که تماس میگیریم، مقدار آن را بهروزرسانی میکند pg_notify
در مورد آن موضوع به عنوان مثال:
await pgPool.query(
`select pg_notify('graphql:sceneState:${id}','{}');`,
[],
);
دستکاری داده ها آزاردهنده بود اما فقط کمی صبر و شکیبایی انجام شد!
آخرین قطعه پازل در حال فراخوانی است pg_notify
زمانی که ما نیاز داریم
برای این کار، میتوانیم یک شنونده به حالت (Yjs) اضافه کنیم و هر زمان که چیزی تغییر کرد، notify را فراخوانی کنیم:
state.observeDeep(async () => {
// Call pg_notify here
});
تنها کاری که باید انجام دهید بهبود عملکرد است. در حال حاضر، این تابع برای هر تغییر کوچک فراخوانی می شود، همچنین به قسمت جلویی به روز می شود. ما میتوانیم وضعیت بهدستآمده را محاسبه کنیم و اگر چیزی تغییر کند قبل از فشار دادن بهروزرسانی، مقایسه کنیم.
راه حل بهتر
اکنون این راه حل مطمئناً کار می کند. اما از اینکه ما به تک تک تغییرات گوش میدادیم متنفر بودم. این غیرضروری است و من مطمئن نیستم که عملکرد چگونه مقیاس خواهد شد. آیا راه حل بهتری وجود دارد؟
بنابراین یک لحظه عقب رفتم و ایده ای به ذهنم رسید: چطور به سراغ اصول اولیه برویم و از داده های Yjs استفاده کنیم؟
مشکل این بود که هر افزونه ممکن است از روش های مختلفی برای نشان دادن وضعیت پخش استفاده کند. بنابراین ما به راهی نیاز داشتیم تا بدانیم چگونه حالت حاصل را خودمان محاسبه کنیم. اما به جای اینکه به کاربر اجازه عبور یک تابع را بدهید، چرا ملکی را رزرو نمی کنید که بتوانند از آن برای نشان دادن این موضوع استفاده کنند؟
به جای ارسال یک تابع برای محاسبه وضعیت، هر افزونه می تواند وضعیت رزرو شده را مستقیماً در کنار داده های موجود خود با ویژگی هایی مانند تنظیم کند. __audioIsPlaying
. آنها میتوانند مستقیماً از این مقدار استفاده کنند، یا میتوانند آن را با ویژگیهای موجود خود هماهنگ نگه دارند، مانند:
const onRendererDataLoaded = (
rendererData,
) => {
watchYjs(
// Watch the isPlaying property
(x) => x.isPlaying,
() => {
// And if it changes, sync the __audioIsPlaying property
rendererData.set("__audioIsPlaying", rendererData.get("isPlaying"));
},
);
};
حذف کدهای قدیمی
روش جدید فوق العاده است. بدون شنونده اضافی، بدون API اضافی، فقط یک ویژگی رزرو شده ساده.
هزینه؟ خب من قبلا 95% اجرای اول رو نوشتم🫣
**” وقتی این همه مدت روی آن کار کرده ام، خیلی شرم آور است که این را حذف کنم. هر چیز دیگری غیر از این یک چیز عالی است!»* – ذهن من *
این اولین بار نیست. نه دوم و نه سوم این بار فقط چند ساعت کار بود. هر چه زمان بیشتری برای پیاده سازی طول بکشد، رها کردن آن سخت تر است. اما اگر نباید به سرورها متصل شویم، نباید به کدی که می نویسیم نیز متصل شویم.
واضح است که اجرای دوم بهتر است. این سریعتر، قطعات متحرک کمتر، سطح API کمتر و کد کمتری برای نگهداری است. اجرای اول 289 خط جدید اضافه کرد در حالی که اجرای دوم فقط 32 خط جدید اضافه کرد.
آن وقت چه درسی باید یاد گرفت؟
خب، شاید ابتدا ساده ترین راه حل را پیدا کنید. اما گاهی اوقات فقط با فکر کردن به بهترین راه حل نمی رسیم. اگر اینطور است، کد خود را دوست نداشته باشید و از دور انداختن آن نترسید. و شاید یک پست وبلاگ بنویسید تا چیزی از آن به دست آورید!
اگر تا اینجا خوانده اید، ممکن است بخواهید TheOpenPresenter را امتحان کنید! این یک سیستم ارائه منبع باز است که به شما امکان می دهد هر یک از صفحه نمایش های خود را از راه دور کنترل کنید.
نمایش اسلایدها، پخش ویدیوها، استفاده به عنوان داشبورد و بسیاری موارد دیگر. همانطور که از این پست می توانید متوجه شوید این نرم افزار هنوز در مراحل اولیه توسعه قرار دارد، اما به اندازه کافی پایدار است تا به طور منظم از آن استفاده کنید. من شخصاً هر هفته از آن برای جلساتم استفاده می کنم.
هر سوالی دارید بپرسید یا با خیال راحت مشکلات موجود در مخزن Github را گزارش کنید.