<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های حمزه معاضدی</title>
        <link>https://virgool.io/feed/@m_51949767</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-04-15 10:19:27</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/3251593/avatar/Bkk0qf.jpg?height=120&amp;width=120</url>
            <title>حمزه معاضدی</title>
            <link>https://virgool.io/@m_51949767</link>
        </image>

                    <item>
                <title>یه دیس Redis</title>
                <link>https://virgool.io/codenevis/%DB%8C%D9%87-%D8%AF%DB%8C%D8%B3-redis-jx9tihsazelk</link>
                <description> چیزی که از redis میشه به عنوان یه معرفی مختصر گفت اینه که یه تکنولوژی (دیتابیس) برای ذخیره سازی دیتا توی مموری هست. با توجه به in memory بودنش و هسته قدرتمند و انواع دیتایی که برای خوندن و نوشتن در اختیارمون قرار میده، گزینه ی مناسب ( و تقریبا همه گیری ) برای cache کردن دیتاست. اگر به مبحث cache علاقمند هستین، شما رو ارجاع میدم که بعد از خوندن این مقاله (اگه خوندین البته D:) ، مقاله ی دیگه ی منو در همین رابطه مطالعه بفرمایین :‌  https://vrgl.ir/MRHTe ارائه دیتا تایپ های مختلف برای خوندن و نوشتن دیتا، مساله ی حائز اهمیتیه. از این جهت که اگر ساختار دیتای خاصی، غیر از دیتا تایپ های بیسیک رو برای ذخیره کردن مد نظر داشته باشیم، چنانچه دیتا تایپ معادلش توی دیتابیسمون وجود نداشته باشه، ما به ناچار دوبار عمل cast دیتا یا encoding و decoding (یا شایدم marshal/unmarshal خدا عالمه ) خواهیم داشت. قاعدتا یه با ر وقتی دیتا رو مینویسیم و یه بارهم وقتی میخوایم بخونیم و استفاده کنیم. این ممکنه در نظر اول هزینه پردازش و زمانی چشمگیری نداشته باشه، اما امان از وقتی که تعدادش بالا بره... . حالا اینو بزاریم کنار امکان خیلی کوچیک بروز خطا در پروسه تبدیل. خلاصه اینکه وجود این دیتا تایپ ها، دستمونو باز تر و سرمونو ( و سر سرور مونو) خلوت تر میکنه. به علاوه این دیتا تایپ ها هر کدوم در کیس های خاصی از کاربرد، خودشون میتونن با تکیه بر توانایی redis ، قسمتی از راه حل مساله باشن. مثل وقتی که به یه صف یا stream نیاز داریم تا رشته ای  یا مجموعه ای . از دیتا ها رو مدیریت کنیم.و اما دیتا تایپ های ردیس:‌۱- دیتای رشته ای یا همون string  برای redis توی ذخیره سازی string یه حالت جفت key/value وجود داره. کلید ها (key) به صورت باینری نگهداشته میشن و خیلی مهمه که بدونیم یونیک هستن یعنی میشه به عنوان یه مپ هم بهش نگاه کرد (میشه که چه عرض کنم... مپه دیگه).  از طرف دیگه value ها مقادیری با ظرفیت حداکثری 512 مگابایتی هستن که میتونن تکست، آرایه های باینری یا مستقیما object ها (در ادبیات دیگه struct ) رو در خودشون نگه دارن(این تعریف از value ها یه خورده کلیه و خیلی ارتباطی به قضیه string نداره). تو خود کامند لاینش، خوندن و نوشتن string ها به این صورته:SET my_key = my value
GET my_key 
Output : my value ۲- دیتای hash مفهوم hash توی redis رو باید از تعریف خودش ببینیم که درواقع شامل یه لیست از key/value ها میشه. همین خاصیت از redis هست که به ما اجازه میده مستقیما structure های دیتا رو توش بنویسیم و بخونیم. جایی خوندم که هر hash از redis میتونه تا 4 میلیارد key/value تو خودش نگهداره! رسما تو بعضی از work scale ها میشه کل یه دیتابیس رو تو یکی از hash هاش نوشت ( به درست و غلطی و کاربرد این کار فکر نکردم البته).برای ذخیره hash ها توی redis ، دستوراتی با پیشوند H به نمایندگی از hash وجود دارن. فرض کنین من ساختار کاربری به این شکل دارم:‌{
name: hamzah,
family : moazedy
}برای وارد کردن این ساختار به redis به این شکل عمل میکنم:‌HSET user:1 name hamzah family moazedyحالا برای خوندنش به صورت یکجا میتونم از HGETALL استفاده کنم، یا اینکه برای خوندن یکی از فیلداش با استفاده از اسم اون فیلد، دیتا رو بخونم:‌HGETALL user:1
output : 
1) name
2) hamzah
3) family
4) moazedy

HGET user:1 name
output:
hamzahو یه سری فیچر دیگه که پیشنهاد میکنم یه سرچی راجع بهشون بکنین.۳- دیتاهای list این نوع دیتا توی redis رو میشه یه سری linked list از string ها درنظر گرفت که باهشون میشه ساختار stack یا صف ها (queue) رو پیاده سازی کرد. هر لیست یه کلید داره و دیتاهایی بهش وارد میشن، به همون ترتیبی که وارد شدن قرار خواهند گرفت. به این ترتیب با کامندهایی که redis در اختیارمون میزاره (LPUSH / RPUSH ) میتونیم تصمیم بگیریم که این ترتیب چطوری باشه، first in last out یا first in first out . مجموعه این ویژگی ها بهمون این امکان رو میده که با redis نه تنها بتونیم stack و queue پیاده کنیم، بلکه تو بعضی موارد میشه ازش به عنوان message broker هم استفاده کرد.مثال زیر یه نمونه از صف first in last out از من و برادرامه :) 127.0.0.1:6379&gt; LPUSH users hamzah
(integer) 1
127.0.0.1:6379&gt; LPUSH users khaled
(integer) 2
127.0.0.1:6379&gt; LPUSH users saeed
(integer) 3
127.0.0.1:6379&gt; LPOP users
saeed
127.0.0.1:6379&gt; LPOP users
khaled
127.0.0.1:6379&gt; LPOP users
hamzahیه سری دستورات دیگه هم رو redis برای queue هستن که پیشنهاد میکنم یه سرچی راجع بهشون بکنین. نکته ی آخر درمورد صفهای redis اینه که تا 4,294,967,295 عدد میتونن ظرفیت داشته باشن، پس با خیال راحت توش دیتا بریزین.۴- مجموعه ها در redisمجموعه ها (set) در redis شامل دسته ای از دیتاهای یونیک هستن که ترتیب خاصی هم ندارن. به این صورت که اعضای مجموعه نمیتونن تکراری باشن و عملیات روی مجموعه ها (اجتماع، اشتراک و ... ) روی اونها هم اجرا میشه. نوشتن یه عضو تکراری توی یه مجموعه، تاثیر و تغییری روی مجموعه نمیده. با امکاناتی که مجموعه ها میدن، میشه اعضا رو اضافه یا حذف کرد ویا عضویت یکیشون رو تو مجموعه بررسی کرد127.0.0.1:6379&gt; SADD brothers khaled hamzah saeed
(integer) 3
127.0.0.1:6379&gt; SMEMBERS brothers
1) khaled
2) hamzah
3) saeed
127.0.0.1:6379&gt; SISMEMBER users hamzah
(integer) 1۵- مجموعه های منظم در redis این نوع از دیتا رو میشه ترکیب مجموعه ها و hash توی redis درنظر گرفت (البته نه به صورت کامل). توی مجموعه های منظم شما میتونین جفت هایی از دیتا ذخیره کنین که شامل یه امتیاز و یه عنوان برای اون امتیاز هست. مثل مجموعه ها ، اینجا هم نمیشه عینا عضو مجموعه منظم یعنی جفت امتیاز و عنوان تکراری باشن، اما میشه با امتیاز های یکسان، عناوین مختلفی ذخیره کرد. مثالش میتونه ذخیره کردن نمرات دانش آموزای یه کلاس توی یه در به خصوص باشه. منطقا یه دانش آموز نمیتونه توی اون درس دوتا نمره داشته باشه ولی دوتا دانش آموز میتونن نمره ی یکسانی داشته باشن. 127.0.0.1:6379&gt; zadd class_score  20 khaled 19 hamzah 18 saeed
(integer) 3
127.0.0.1:6379&gt; zrange class_score 0 -1
1) saeed
2) hamzah
3) khaled
127.0.0.1:6379&gt; zrange class_score 0 -1 withscores
1) saeed
2) 18
3) hamzah
4) 19
5) khaled
6) 20
127.0.0.1:6379&gt; zadd class_score  20 gholy
(integer) 1
127.0.0.1:6379&gt; zrange class_score 0 -1 withscores
1) saeed
2) 18
 3) hamzah
4) 19
5) gholy
6) 20
 9) khaled
10) 20۶- دیتای stream در redis دیتای stream در redis یک دیتا استراکچر جدیده که redis باتوجه به نیاز فراوان امروز برای هندل کردن دیتای استریم ایجاد کرده. باید بدونیم که استریم هم در اصل به صورت key/value ذخیره میشه که همین امر باعث میشه بتونیم کامندهای این دسته دیتا رو روی استریم ها هم داشته باشیم (مثل DEL و EXPIRE ). استریم ها در واقع یک فلو مداوم از دیتاست که ترتیبشون ثابته و قابل تغییر نیست و شبیه یه صفه که دیتای جدید مدام به آخرش اضافه میشه. هر عضو از یه استریم یه جفت از key/value  هست که با دیتای مرتبط با قطعه های دیگه ای از دیتاست. دیتایی که به بخشهای کوچکتر شکسته شده و هر بخشش کلید منحصر به فرد خودش رو داره. هر عضو از این استریم با یه id منحصر به فرد شناخته میشه که باتوجه به اهمیت ترتیب دیتا در استریم، این id ها با یه timestamp همراه هستن.برای پردازش دیتای استریم، redis دوتا حالت رو اجازه میده، یکی اینکه دیتای استریم شده، هر عضوش تنها توسط یه مصرف کننده دیتا دیده و پردازش بشه، یا اینکه مصرف کننده های مختلفی بتونن همزمان یه دیتا رو ببینین و پردازش کنن. ایم امر توسط consumer group ها هندل میشه. consumer group کمک میکنه که کار بین مصرف کننده ها توزیع بشه و لود بین اونها تقسیم بشه. به این ترتیب هر replica از یه برنامه یکسان، تکه ی جدایی از دیتا رو هندل خواهد کرد.برای اضافه کردن دیتای جدید به استریم، نقش پابلیشر در سیستم از دستور XADD استفاده میکنه. با این کار یه key/value جدید به یه استریم خاص اضافه میکنه. در این حالت اگه استریم خواسته شده وجود نداشته باشه،redis اونو ایجاد میکنه و دیتا رو توش میریزه. در هنگام اضافه شدن دیتا به استریم، این دستور یه id برای دیتا جنریت میکنه که همونطور که عرض کردم یه timestamp تو خودش داره و شماره ایکه نشون دهنده ی جایگاه دیتا توی توالی اون استریم هست.127.0.0.1:6379&gt; XADD brothers_stream * name khaled score 100
1719220675816-0
127.0.0.1:6379&gt; XADD brothers_stream * name hamzah score 98
1719220697600-0حالا اگر دقت کنین مقدار بازگشتی رو که ترکیب timestamp با sequence number هست برای id میبینین. اما چرا sequence number برای هردو دیتا یکیه (صفره درواقع) ؟ ببینین اساس کار id یونیک بودنه و زمانی که insert های شما در timestamp های متفاوتی انجام بشه، چون مقدار timestamp مختص همون لحظه ی نوشتن دیتاست، در نتیجه id یونیک میشه. اما اگه وارد کردن دیتا به استریم در یه میلی ثانیه مشترک انجام بشه، اون موقع است که redis میاد و با افزایش sequence number یونیک بودن id رو تظمین میکنه. مقدار * هم جانشین id هست و به redis میگه که خودش بر اساس ترکیبی که ازش صحبت کردیم، برای دیتا id جنریت کنه.سمت دیگه اما مصرف کننده ی دیتاست. برای خوندن دیتا از یه استریم، از یه دستوری شبیه دستور پایین استفاده میکنیم 127.0.0.1:6379&gt; XREAD COUNT 2 BLOCK 1000 STREAMS brothers_stream 0-0
1) 1) brothers_stream
   2) 1) 1) 1719220675816-0
         2) 1) name
           2) khaled
            3) score
            4) 100
      2) 1) 1719220697600-0
         2) 1) name
            2) hamzah
            3) score
            4) 98خب بریم سراغ شکستن دستور. XREAD که کلمه کلیدی برای خوندن از استریمه. بعدش COUNT (اختیاری) و مقداری که بهش پاس میدیم، به redis میگه که چه تعداد رکورد از داده رو میخوایم. BLOCK و مقدارش (اختیاری)  مقدار زمانی رو در واحد میلی ثانیه نشن میدن که ما برای صبر کردن تعیین کردیم و اگه بیش از اون خوندن دیتا طول بکشه، تایم اوت خواهیم شد. بعد STREAMS و مقدارش که بهمون میگه از رو کدوم استریم داریم میخونیم و پارامتر آخر که اریم میگیم از کدوم دیتا به بعد که این حالت به خصوص داره میگه همه رو بخون (این فرمت یعنی timestamp و  sequence number هردو صفر باشن که قاعدتا میشه از اول).اما اگه ما بخوایم فقط دیتاهای جدید رو بخونیم چی؟ برای این کار از فرمت زیر استفاده میکنیم: XREAD COUNT 2 BLOCK 1000 STREAMS brothers_stream $فقط نکته ای که باید توجه کرد اینه که این کامند فقط زمانی دیتا برمیگردونه که دیتا موقع بلاک بودن این دستور وارد بشه.حالابریم سراغ مبحث consumer group . هدف از ایجاد این گروه ها برای زمانی هست که لود بالا باشه و ما بخوایم چندتا مصرف کننده همزمان روی یه استریم کار کنن اما نه روی دیتای تکراری. برای ایجاد یه consumer group از این کامند استفاده میکنیم 127.0.0.1:6379&gt; XGROUP CREATE brothers_stream consumer_group1 0
OKخب با این کار ما برای استریم brothers_stream یه گروه مصرف کننده ایجاد کردیم به نام consumer_group1 و پارامتر آخر یعنی 0 داره میگه که این گروه دیتای روی استریم رو از ابتدا میتونه بخونه. چنانچه میخواستیم که گروه به دیتاهای استریم فقط بعد از ایجاد گروه دسترسی داشته باشه، باید به جای پارامتر 0 از $ استفاده کنیم. حالا وقتی که گروه ایجاد شد، کاری که باید بکنیم، اینه که یه consumer داشته باشیم که تو این گروه دیتا رو بخونه 127.0.0.1:6379&gt; XREADGROUP GROUP consumer_group1 consumer1 COUNT 2 BLOCK 1000 STREAMS brothers_stream &gt;
1) 1) brothers_stream
   2) 1) 1) 1719220675816-0
         2) 1) name
            2) khaled
            3) score
            4) 100
      2) 1) 1719220697600-0
         2) 1) name
            2) hamzah
            3) score
            4) 98کلمه کلیدی برای اینکار XREADGROUP هستش که یه GROUP میگیره و یه consumer . پارامتر های بعدی رو هم که تو کامندهای قبلی دیدیم. فقط میمونه پارامتر آخر ( &lt; ) . این پارامتر همون id رو میگیره که قبلا باهاش مواجه شدیم یعنی میتونیم به جای این مقدار یه id پاس بدیم، اما این نماد به این معنیه که به من دیتایی رو برگردون که هنوز هیچ consumer دیگه ای توی گروه دریافتش نکرده و اصطلاحا تا حالا به کسی deliver نشده.حالا با این توضیحات دوتا تعریفی هست که باید بهش توجه کنیم. یه لیستی وجود داره به نام PEL یا Pending Entry List . این لیست شامل پیامها یا دیتاهاییه که به یه consumer تحویل شدن ولی consumer هنوز acknowledge ی مبنی بر پروسس کردنشون به استریم برنگردونده. پس با این اوصاف consumer هاهم باید بعد از پروسس کردن دیتا، یه سیگنال به استریم برگردونن ، به این معنی که کار پروسس اون دیتای دریافتی تموم شده. تو این لیست میشه حتی گزارش گیری هم انجام داد ( XPENDING ) که باهاش میشه وضعیت پیامهای معلق و زمان تعلیقشون رو دید تا در صورت نیاز درموردشون تصمیم گرفت.اما برای اینکه consumer اعلام کنه که کار پردازش دیتا و پیام دریافتیش تموم شده، به این شکل acknowledge میده127.0.0.1:6379&gt; XACK brothers_stream consumer_group1 1719220675816-0
(integer) 1با این دستور به استریم گفته میشه که مسیج 1719220675816-0 پردازش شد.اگر یه consumer نتونه پیامی که بهش تحویل شده رو در یه بازه زمانی خاص پردازش کنه، اینطور در نظر گرفته میشه که این پروسه fail شده. همونطور که عرض کردم لیست پام های معلق رو به اینصورت دریافت میکنیم 127.0.0.1:6379&gt; XPENDING brothers_stream consumer_group1 IDLE 20000 - + 2 consumer1
1) 1) 1719220697600-0
   2) consumer1
   3) (integer) 1680065
   4) (integer) 1
2) 1) 1719223217132-0
   2) consumer1
   3) (integer) 137401
   4) (integer) 1با درنظر گرفتن یه محدودیت زمانی برای انجام پردازش پیامها، میتونیم توی برنامه مون ست کنیم که اگه این زمان سپی شده برای پردازش دیتا از حدی گذشت، مصرف کننده ( consumer ) دیگه ای وظیفه ی پردازش این پیام خاص رو بر عهده بگیره و این کار با دستور XCLAIM انجام میشه. به این صورت که consumer درخواست میده تا پردازش یه پیام خاص به اون سپرده بشه  XCLAIM brohters_stream consumer_group1 consumer2 300001719223217132-0توی این دستور consumer2 داره میگه میگه من به عنوان یه مصرف کننده از consumer_group1 درخواست میکنم که اگر دیتا با id برابر  1719223217132-0 بیش از 30 ثانیه معلق بود، پیام (دیتا ) رو به من بدین که پردازشش رو برعهده بگیرم.</description>
                <category>حمزه معاضدی</category>
                <author>حمزه معاضدی</author>
                <pubDate>Mon, 24 Jun 2024 17:53:46 +0330</pubDate>
            </item>
                    <item>
                <title>محکم مثل SOLID</title>
                <link>https://virgool.io/@m_51949767/%D9%85%D8%AD%DA%A9%D9%85-%D9%85%D8%AB%D9%84-solid-gro1itngogbi</link>
                <description>چیکار کنیم که کدی که مینویسیم، خوانا باشه، یا اینکه بشه دوباره ازش استفاده کرد، یا اینکه اگه به مشکلی یا خطایی توش برخورد کردیم، راحت بشه دیباگش کرد یا حتی توسعه و گسترشش داد؟اینا سوالایی هستن که هر برنامه نویس آینده نگری که دسخطش براش مهم باشه، کمابیش از ذهنش گذشتن .(صد البته اگر آینده نگر نباشه یا براش مهم نباشه که چیکار داره میکنه، کلا داستان متفاوتی داره). وقتی صحبت از اصول و نقشه راه میشه، نامی که میدرخشه قطعا عمو باب هستش که با معماری تمیزش، خیلی جزئی، تو لایه های پیاده سازی، نکاتی رو ذکر ،ابداع و گرداوری کرده که اگه همچون منی پیاده نظام، فقط سعی کنم به سمتشون برم، برای خودم میتونم اندک آبرویی دست و پا کنم! دیگه ببین کی بوده خودش!!از مجموعه اصولی که ایشون معرفی کرده، میشه گفت شاید معروف ترینش اصول SOLID باشن که در اصل برای الگوهای شیئ محور یا به قول معروف شیئ گرا (OOP) ارائه شدن. پنج اصلی که واقعا نشون دادن که اگه هر برنامه نویسی ازشون بهره ببره، نکاتی رو که در ابتدای نوشته بهشون اشاره کردم رو به دست میاره. پس با اجازه از رو دست بزرگای مجلس کپی میکنم و این اصول رو یکی یکی تشریح میکنم.۱-اصل Single responsibility نمیدونم دقیقا اگه بخوام معنی فارسی این اصطلاح رو ترجمه کنم، چی باید بگم؟ اما بیاین در این اسکوپ بهش بگیم &quot; تک مسئولیتی &quot; بودن. قطعا چیزی که مهمتر از عنوانه، معنی این اصله و این اصل به این معنیه که وقتی شما یه کلاس تعریف میکنین، این کلاس باید صرفا و تنها یک وظیفه داشته باشه. شنیدین که میگن &quot; من یه قناری دارم روپایی میزنه &quot; ... ؟ این دقیقا برعکس اون قضیه ست. در این اصل، قناری فقط باید آواز بخونه و نه کار دیگه. وقتی کار های متفاوتی به یه کلاس  سپرده میشن، این کلاس  جاهای مختلفی برای کار های مختلفی به کار گرفته میشه که خب عملا پیچیدگی ایجاد میکنه.یه مجموعه تولیدی رو در نظر بگیرین، تکنیسینی که پشت دستگاه هست نباید در گیر زنجیره تامین، نظافت یا کارهای دیگه بشه. اینطوری میشه از این کارگاه، نظم و کیفیت تولید بالا رو انتظار داشت.۲-  اصل Open/Closed  در یک جمله کوتاه : بسته برای تغییر، باز برای توسعه.حالا این یعنی چی؟ عرض میکنم. در این اصل گفته میشه اجزای یک برنامه، از کلاس و متد الی آخر، باید طوری تعریف و پرداخته بشن که در صورت نیاز، بشه توسعه شون داد و برای این توسعه، نیازی به تغییرشون نباشه. همون کارگاه رو درنظر بگیرین، ما یه وسیله داریم به اسم بلبرینگ. یه بلبرینگ با ساختارش و کاربردش بلبرینگه (در غیر اینصورت شاید اسم دیگه ای میگرفت، خدا عالمه!). ما میتونیم وسایل متعددی با استفاده از بلبرینگ و خاصیتش ایجاد کنیم. میتونیم اونو تو چرخ ماشین جا بدیم و یه ماشین رو باهاش تکمیل کنیم، میتونیم تو ساخت روتور یه ژنراتور ازش استفاده کنیم و اینطوری میشه یه قطعه از اون ژنراتور. ببینین، بلبرینگ همون بلبرینگه، نه ماهیتش و نه خاصیتش تغییر نکرده ولی یه جا میشه یه قطعه از اتومبیل و جای دیگه قطعه ی ژنراتور. پس بسته برای تغییر و باز برای توسعه :)۳- اصل  Liscov&#x27;s substitution یا جایگزینی لیسوفزیباست که بدونین (و من تا همین اواخر نمیدونستم) که لیسکوف در واقع یه سیبیل کلفت جامعه گریز نبوده و در اصل یه بانوی ملیح با پیرهن گل گلی به نام خانم باربارا لیسکوف هستن که اتفاقا به نظر خیلی هم مهربون میان. اینه که از رو اسم قضاوت نکنین. باری...این اصل بیان میکنه که هر کلاس که از توسعه کلاس دیگری ایجاد شده، یعنی رابطه فرزند و والدی با کلاس دیگری داره، باید بتونه بدون مشکل به جای کلاس والدش به کار برده بشه. یه ماشین رو در نظر بگیرین. این ماشین قصه ما یه وسیله ی ایاب و ذهاب برای  یه خانواده ست. پر خوش ذوق خانواده (که از قرار شبیه منه) میره و میل سوپاپ ماشین رو تعویض میکنه، هدرز میبنده و یه کیت مکش میزاره رو ماشین (قطعا ریمپش هم میکنه) . این ماشین الان قطعا یه ماشین مسابقه ست. یعنی کلاسی که از کلاس والد به اسم ماشین سدان خانوادگی ارث بری کرده. اما دلیلی نمیشه که نشه با همین ماشین کماکان ایاب و ذهاب های خانوادگی رو انجام داد. متوجه شدین دیگه ؟! اوکیه؟۴- اصل Interface segregation این اصل رو میشه گفت همون اصل اوله ولی برای اینترفیس ها. خلاصه ش میشه اینکه دوست عزیز! اینترفیسی تعریف نکن که اگر اطلاعات کاربر رو میخوای ازش میخونی،، اطلاعات هواشناسی ازش میخونی،، توش خاطرات مینویسی و نون سنگک هم میگیره. قشنگ و مرتب، بر اساس کاربرد جداشون کن. پیشاپیش ممنون.۵ - اصل Dependency inversion این اصل یه خورده مفهومیه، پس یادداشت کنین که حتما ازش تو امتحان سوال میاد.خود اصل میگه که ماژول های سطح بالا نباید به ماژول های سطح پایین وابسته باشن، بلکه هردو باید به ابسترکشن یا انتزاع وابسته باشن و همینطور در رابطه با وابستگی انتزاع به جزئیات هم همین طوره. انتزاع نباید به جزئیات وابسته باشه. این رابطه باید عکسش باشه و جزئیات بر اساس انتزاع شکل بگیرن.خب بیاین این جملات قصار رو آدم فهم تر کنیم. ماژولهای سطح بالا تو برنامه، ماژولهایی هستن که منطق ها و لاجیک های پیچیده رو پیاده سازی میکنن. از طرف دیگه ماژول های سطح پایین، در واقع utility های سیستم رو پیاده سازی میکنن ( ابزار دیگه.. همون کارای خورده ریزه). حالا انتزاع چیه؟ انتزاع میشه رفتار. اصل رو اینطوری توضیح میدم:‌ رفتار بیزینسی که توی سیستم مدل میشه، میشه همون انتزاع یا ابسترکشن ما. مثلا ما یه سیستم داریم که یه مرسوله پستی رو برامون رهگیری میکنه. اینترفیسی که یه متد توش داره و اون متد خیلی راحت اسمش هست TrackMyPackage(packageCode) میشه انتزاع من از رهگیری. این یه رفتار و انتزاع انسانیه (محموله منو رهگیری کن).الان این رفتار نه کاری به الگوریتم های پیچیده ی مسیریابی GPS داره (ماژول سطح بالا) و نه به اینکه تبدیلات لوکیشن با چه ابزاری انجام میشه(سطح پایین). اگر روزی روزگاری هم زیر پست پیاده سازیش کلا زیرو رو بشه و تغییر کنه، رفتار همینه، چون بیزینس من همینه. پس اگر رفتار رو مستقل از ماژولها و تکنولوژی ها مدل کنیم، در واقع این اصل رو رعایت کردیم. به همین خوشمزگی.</description>
                <category>حمزه معاضدی</category>
                <author>حمزه معاضدی</author>
                <pubDate>Mon, 13 May 2024 18:50:20 +0330</pubDate>
            </item>
                    <item>
                <title>سرد و گرم روزگار یا hot cache و cold cache</title>
                <link>https://virgool.io/@m_51949767/%D8%B3%D8%B1%D8%AF-%D9%88-%DA%AF%D8%B1%D9%85-%D8%B1%D9%88%D8%B2%DA%AF%D8%A7%D8%B1-%DB%8C%D8%A7-hot-cache-%D9%88-cold-cache-ysnjzf5q9zbw</link>
                <description>ساختار cacheاینکه کش کنیم یا نکنیم، اینکه چیو کش کنیم و کجا بخونیم کاااملا به بیزینسمون، روند کارمون و نیازمندیهامون  بستگی داره. در نتیجه ممکنه مسائلی که من اینجا مطرح میکنم به نظر شما اصلا کاربردی نیاد... شایدم بیاد خدا میدونه. از طرفی خوندن از دیتا و پالسی های دسترسی و پرمیشنهایی که هر پروژه و بیزینس داره، به خودش مربوطه و از موضوع بحث ما خارجه :)تاجایی که من میدونم، کش کردن، فرایند نگهداری یه دسته از اطلاعاته به صورت دم دستی که گردآوریش به روش فرمال و کلاسیک یه مقدار از لحاظ منابع، هزینه بردار باشه(معمولا زمان!). در این حالت ما دیتایی که ریفرنس بهش زیاده رو یه جایی همین اطراف نگه میداریم که بتونیم به سرعت بهش دسترسی داشته باشیم. این نکته رو باید عرض کنم که هر دیتایی  ارزش و امکان کش کردن نداره. دیتایی که عموما درخواست خوندنش بالاست و معمولا سخت گردآوری میشه رو معمولا کش میکنیم. لازم به ذکره که دیتایی که نرخ بروزرسانیش هم بالاست رو خیلی نمیشه،،،، نمیشه که نه، به صرفه نیست که کش کنیم. مگر اینکه ترید آف (مصالحه)ی که بین دسترسی و آپدیت کردنش توی سیستم ما هست، کفه ی ترازو رو به سمت کش کردن سنگین تر کنه. و در نهایت همونطور که قبل تر عرض کردم، کل این فرایند به ما، بیزینس ما، نیاز مندی های ما و نوع پیاده سازیمون برمیگرده.برای درک بهتر نیاز به کشینگ، من یه مثال میزنم. فرض کنین ما توی یه سامانه ای هستیم که اطلاعات یه کاربر  رو که جنبه های مختلفی داره، توی دیتابیس های مختلفی نگه میداره ( خواهشا به کانسپت و اینکه دلیل این کار چیه گیر ندین، مثاله آقا). فرضا توی میکروسرویس های مختلف که هرکدوم دیتابیس مستقل خودشون رو دارن.در این حالت، هربار که کلاینت بخواد دیتای کاربر رو جمع کنه، باید به همه ی این سرویس ها درخواست بده تا بتونه این دیتا رو جمع آوری کنه. حالا این موضوع رو بزارین کنار اینکه اگر کاربر دیتایی داشته باشه که نیاز باشه براسا پارامترهای مختلف، توسط سیستم محاسبه  بشه. پس هربار درخواستهای متعدد و محاسبات متعدد. دیگه بیاین به این فکر نکنیم که ممکنه توی شبکه ارتباطی بین این میکرو سرویس ها، هزار و یک اتفاق بیوفته و ... .در این حالت چقدر کاربردیه که ما بیایم یه فرمت دیتا برای این اطلاعات کاربری بسازیم و اونو کش کنیم. اینطوری روی هربار درخواست فقط از یه منبع با سرعت خیلی بالاتر میتونیم دیتارو بخونیم.این نکاتیه که درمورد کش عمومیه و چیزی که من میخواستم بهش بپردازم بحث hot cache و  cold cache هستش. در این ساختار hot cache در واقع اون منبعیه که ما دیتارو داغ داغ توش سرو میکنیم (مثلا یه دیتابیس redis ) و البته خیلی از بزرگان معتقد هستن که کش یه امکان cross cutting platform هستش. یعنی جدا از لایه بندی پروژه و این داستانا، هرجا که احتیاجش داشتیم، میتونینم ازش استفاده کنیم. البته در این مورد و مثال، ما تو همون لایه ی بالایی که به presentation ، controller و ... معروفه میخوایم ازش بخونیم.در طرف دیگه ماجرا cold cache وجود داره که درواقه یه دیتابیس با خاصیت stability بالاتره (مثل postgres یا couch base ) که دیتارو باهمون فرمت تو خودش نگه میداره و پشتوانه hot cache مون هست. این فرمت دیتا میتونه تو لایه های بالایی ساخته بشه و روی هر آپدیتی که رو ی دیتا صورت میگیره، اونم متعاقبا بروزرسانی بشه که همیشه دیتای صحیح رو تو خودش نگهداره( اگر دیتابیس های جدایی ندارین، اکیدا پیشنهاد میکنم که برای cold cache از materialized view استفاده کنین... خیلی جوابه).حالا فرایند رو عرض میکنم. وقتی که درخواستی میاد که اطلاعات کاربر رو بخونه، ابتدا تو hot cache رو چک میکنیم، اگه دیتا رو پیدا نکردیم(که خب قاعدتا تو درخواست اول به این صورته) میریم دیتا رو از  cold cache میخونیم و هم به درخواست دهنده میدیم و هم تو hot cache ذخیره میکنیم. تبریک میگم، اولین کشمون رو انجام دادیم!حالا سوال شاید پیش بیاد که cold cache دیتا رو از کجا آورده؟ خب همونطور که عرض کردم، یک سری رفتار توی لایه های بالایی (یا شایدم تو دیتابیس) باید پیاده کنیم، که روی اکشن هایی که دیتا رو ایجاد میکنن یا تغییر میدن، اصطلاحا trigger بشن و دیتای مورد نیاز رو توی  cold cache برامون ثبت کنن. به این صورت روی ایجاد کاربر یا آپدیتش، این دیتا ایجاد یا بروز رسانی میشه.یه نکته رو نباید فراموش کنیم. مکانیزمی که هر از چندگاهی ورزن دیتای hot cache رو با cold  cache تطبیق بده و دیتای hot cache رو بروزرسانی کنه. پس باید توجه داشت که این پترن، روی دیتایی بیشتر کاربردیه که availability ش مهم تر از consistency ش باشه.#programming</description>
                <category>حمزه معاضدی</category>
                <author>حمزه معاضدی</author>
                <pubDate>Sat, 11 May 2024 11:41:01 +0330</pubDate>
            </item>
                    <item>
                <title>دیزاین پترن ها یا الگو هایی از بزرگان!</title>
                <link>https://virgool.io/codenevis/%D8%AF%DB%8C%D8%B2%D8%A7%DB%8C%D9%86-%D9%BE%D8%AA%D8%B1%D9%86-%D9%87%D8%A7-%DB%8C%D8%A7-%D8%A7%D9%84%DA%AF%D9%88-%D9%87%D8%A7%DB%8C%DB%8C-%D8%A7%D8%B2-%D8%A8%D8%B2%D8%B1%DA%AF%D8%A7%D9%86-z24481y3xthg</link>
                <description> دیزاین پترن ها یکی از موضوعات کاربردی در برنامه نویسی و حوزه دیزاین هستن. هم بابت کاربردشون توی کد و فرایند توسعه، و هم بابت سوالاتی که توی مصاحبه ها معمولا ازشون پرسیده میشه.حالا بماند اگر بعدا ازشون هم استفاده میشه یا نه :) دلیل اینکه عنوان این مقاله رو گذاشتم الگوهایی  از بزرگان،  اینه که واقعا دیزاین پترنها الگوهایی از مسائل هستن که مکررا توی پروژه ها پیش اومدن و یه جورایی میشه گفت نیاز هایی بودن که تکرار میشدن. به همین خاطر ، افراد درگیر با این مسائل ، کاری رو کردن که هر برنامه نویس درست و حسابی دیگه ای هم بود همون کارو میکرد، یعنی کشف الگو ایجاد راه حل عمومی برای اون الگو. بزارین مثالش رو اینطوری بگم: من هرروز از خونه باید برم سرکار، و یه بعد فاصله ای هست این وسط (البته این مثاله و من دورکارم). داداشم باید هرروز بچه شو ببره مدرسه (داداشمم بچه نداره آخه) و مدرسه ش دوره. و یه نفر دیگه هم خلاصه از یه جایی میخواد به جای دیگه بره. این وسط یه الگویی هست و اون ترنسپورته.یک نفر به هر دلیل از جایی به جای دیگر میخواد منتقل . بشه. اینجا یه راه حل که با این الگو بخونه وسیله ی نقلیه ست و اینکه بسته به تعداد نفرات. مثلا دو نفر.برای این کار یه موتو ر جوابگوه. من با موتور میرم سر کار. داداشم بچه شو میبره مدرسه و اون دوستمون از نقطه آ میره به ب . قطعا روزی روزگاری اگه کس دیگه ای بخواد ترنسپورت یک یا دو نفره داشته باشه، نمیاد یه وسیله ی جدید اختراع کنه، میره موتور میگیره(شایدم بکنه.. نمیدونم). این اتفاق سمت برنامه نویسی هم میوفته.  فرض کنیم من یه منبع دارم که دیتا توش نوشته و ازش خونده میشه (دیتابیس دیگه)  من نمیخوام همه ی اکتورها هر وقت و هر طور که دوست دارن به این منبع دسترسی داشته باشن. . من میخوام فقط یه راه ارتباطی برای این منبع وجود داشته باشه و فقط یه راه.هر کس از هرجای برنامه میخواد دیتایی بخونه یا بنویسه باید از این مسیر اقدام کنه و نمیتونه برای خودش کانکشن جدایی بسازه.در این صورت فرایندگرفتن کانکشن به دیتابیس به این صورت خواهد بود که وقتی درخواست دریافت کانکشن رو کسی صدا میزنه، چنانچه از قبل کانکشن بازی با دیتابیس وجود داشته باشه، اون کانکشن باز به درخواست دهنده برگردونده میشه و کانکشن جدید فقط در صورتی ساخته میشه که کانکشن بازی وجود نداشته باشه. این مثالیه که ممکنه برای موارد دیگه ای هم اتفاق بیوفته. یعنی الگویی به این صورت که  ما بخوایم از یه موجودیت توی سیستم، فقط یه نمونه داشته باشیم. اینجاست که راه حل مثل قضیه موتور، یه راهکار مشترکه که اونو به عنوان دیزاین پترن سینگلتون میشناسیم. بقیه دیزاین پترن ها هم طی همچین فرایندی به وجود اومدن، یعنی پاسخ دهنده ی یه نیاز مشترک در مساله های مشترک هستن که طی پروژه های مختلف تکرار شدن. این دیزاین پترن ها عموما به سه دسته تقسیم میشن که هر کدوم رو با مثال توضیح میدم: اول creational  الگوهایی هستن که فرایند ساخت یک نمونه از یک چیز رو انتزاعی میکنن. یعنی چی، یعنی اینکه به سیستمی که داره ازشون استفاده میکنه کمک میکنن، مستقل از اینکه یه آبجکت (نمونه) چطور ساخته و پرداخته و سر هم میشه، بتونه . یه نمونه از اونو دریافت بکنه. که مثالش میشه همین سینگلتونی که قبلا معرفی شد. اواع دیگه ای هم داره مثل فکتوری، ابسترکت فکتوری، بیلدر و پروتو تایپ پترن که هر کدوم توضیح و کاربرد خودشون رو دارن که هرکدومو سرچ کنین، قطعا توضیحات خوبی راجع بهش میتونین پیدا کنین.  دوم structural الگو هایی هستن که با ترکیب اجزای کوچکتر(میتونن کلاس آبجکت یا اینترفیس باشن) اجزای بزرگتری رو میسازن و برای این کار از مفاهیم ارث بری بهره میگیرن. البته توی مواردی، شامل الگوهایی هم میشن که یه اینترفیس رو به یه اینترفیس دیگه تبدیل و ترجمه میکنن.(آداپتر ها از این دسته هستن) بریج، کامپوزیت کردن و دکوریتور ها از انواع این الگو ها هستن.  سوم behavioral این الگو ها هم بر ساختار و هم بر رفتار اشیا و حتی بر ارتباط بینشون هم تاثیر میذارن. نمونه ش رو تو الگو هایی میشه دید که ساختاری ایجاد میکنن که بشه مجموعه ای از روابط بین دیتا رو ترک کرد در حالی که این فرایند ترک کردن د رحالت ران تایم و اجرا عملا نزدیک به غیر ممکنه. مثل دیزاین ممنتو که اجازه میده آبجکت رو به حالت قبلش برگردونیم، یا الگوی آبزرور که رابطه ای مثل رابطه ی بین انتیتی های مستقل و انتیتی های وابسته ش ایجاد میکنه، به صورتی که تغییر توی انتیتی مستقل، انتیتی های وابسته رو هم تحت تاثیر قرار بده یا دیزاین استیت و …  در اصل تسلط بر دیزاین پترن ها میطلبه که دولوپری که  ما و شما باشیم در عمل و در کیسهایی که بهشون نیاز داریم ازشون استفاده کنیم و این امکان پذیر نیست الا اینکه  نوعهای مختلفشو ن رو مطالعه کنیم و برای کیس های مشابهشون آماده باشیم.#design_patterns</description>
                <category>حمزه معاضدی</category>
                <author>حمزه معاضدی</author>
                <pubDate>Sat, 11 May 2024 09:08:52 +0330</pubDate>
            </item>
            </channel>
</rss>