<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>پست‌های انتشارات انتشارات روبیک</title>
        <link>https://virgool.io/RubikGroup/feed</link>
        <description>انتشارات روبیک زیر شاخه گروه روبیک می باشد</description>
        <language>fa</language>
        <pubDate>2026-04-15 10:18:39</pubDate>
        <image>
            <url>https://files.virgool.io/upload/publication/wh3qzkcatt17/zv9i3v.png</url>
            <title>انتشارات روبیک</title>
            <link>https://virgool.io/RubikGroup</link>
        </image>

                    <item>
                <title>پیاده سازی Promises در Golang</title>
                <link>https://virgool.io/RubikGroup/%D9%BE%DB%8C%D8%A7%D8%AF%D9%87-%D8%B3%D8%A7%D8%B2%DB%8C-promises-%D8%AF%D8%B1-golang-sevzfaom1o7i</link>
                <description>زبان Go با معماری CSP به ما قدرت خیلی زیادی میده که سیستم concurrent مورد نظرمون رو طراحی کنیم. اما حداقل برای من موقع شروع کار یکم گیج کننده بودن، چنل ها و گوروتین ها و اینکه چطور با ترکیبشون میتونم از تمام قدرت CPU مون برای یک برنامه استفاده کنیم.یک مثال ساده، درخواست batchفرض کنید یک سرویس دارید که چند هزار ریکوئست برثانیه میخواد پاسخ بده. این سرویس میخواد یک دیتایی رو از کش ردیس بخونه و به ما بده. حالا اگر برای هردرخواست ریکوئست بزنیم به ردیس i/o ما اذیت میشه، درحالی که میدونیم ردیس قابلیت درخواست های batch رو داره که میدونیم خیلی خیلی سریع تر پاسخشون میده. سوالی که مطرح میشه چطور از این قابلیت ردیس توی Go استفاده کنیم؟حالت معمولی اینطوره که برای هر درخواست HTTP یک تابع صدا میزنیم که دیتا رو از ردیس بگیره. پس به ازای هر درخواست HTTP یک درخواست به redis داریم. اما کاری که میخوایم انجام بدیم اینه هر ۵۰ میلی‌ثانیه یک بار تمام درخواست های redis رو با هم بفرستیم. یعنی یک درخواست HTTP وقتی اون تابع رو صدا زده میشه باید صبر کنه که پنجره ۵۰میلی‌ثانیه ایی تموم شه که سرویس ما تمام درخواست ها رو با هم بفرسته.چرا این موضوع میتونه پرفورمنس سیستم رو بهتر کنه؟همون طوری که توی این پست صحبت کردیم، اگر از pipeline ردیس استفاده کنیم هم i/o ما فشار کمتری بهش میاد هم اینکه خود ردیس syscall های کمتری میزنه و به شکل چشم‌گیری پرفورمنس ما هم بهتر میشه.اگر سیستم رو به حال خودش رها کنیم و ۲ هزار ریکوئست برثانیه داشته باشیم ۲ هزار ریکوئست برثانیه به ردیس میزنیم. اما اگر به صورت batch هر ۵۰ میلی‌ثانیه درخواست بزنیم همیشه ۲۰ درخواست در ثانیه به ردیس میزنیم.البته به یک موضوعی باید توجه کرد. با این کار میانگین ریسپانس تایم سیستم رو در حال معمولی ۵۰ میلی‌ثانیه بیشتر میکنیم که عدد زیادیه. اما توی درخواست های این سیستم خودش رو نشون میده.متوجه شدیم که میخوایم چیکار کنیم. اما چطور توی Go پیادش کنیم؟ با کمک channel های go ما میتونیم promises رو پیاده سازی کنیم. اینطوری به قضیه نگاه کنید. ما وقتی تابع رو صدا میزنیم، تابع به ما یک متغیر میده که میدونیم در لحظه هنوز توش مقداری ریخته نشده. اون متغیر میره توی thread های مختلف و ما اصلا نگران race condition نیستیم، ما فقط منتظریم تا توی اون متغیر مقداری ریخته بشه. درخواست HTTP ما قفل میشه تا وقتی مقداری توی اون متغیر ریخته بشه.مثال Promises در Golangنمونه کد زیر رو در نظر بگیرید:func PromiseMe() chan bool {
   c := make(chan bool)
   go func() {
      time.Sleep(2 * time.Second)
      c &lt;- true
   }()
   return c
}توی این تابع Go ما میایم اول یک چنل میسازیم، در ادامه یک تابع رو با استفاده از go توی یک گوروتین‌ (thread خیلی سبک) اجرا میکنیم. گوروتین ما خیلی سادست، ۲ ثانیه صبر میکنه و بعدش مقداری رو توی چنل میریزه. اما میدونیم این تابع توی ترد دیگه ایی اجرا میشه. ما همون موقع داریم چنل رو برمیگردونیم.func main() {
   promise := PromiseMe()
   response := &lt;-promise
   if response {
      // we got true!
   }
}حالا توی این نمونه کد ما چنل رو از تابع گرفتیم. میدونیم در لحظه مقداری توی چنل ریخته نشده، توی خط بعد ما با استفاده از &lt;- داریم میگیم آخرین مقدار توی چنل رو به ما بده (چنل ها مثل صف میمونن و میتونن تعداد مقادیر مدنظرمون عضو نگه دارن). نکته ایی که هست چون چنل ما مقداری توش نیست اون خط کد قفل میشه (همچنین تردش) تا وقتی مقداری توی اون چنل ریخته بهشه.پیاده سازی batch با استفاده از channelsمثالی که اول مقاله گفتم یکم پیچیده هست (قبلا توی این مقاله نمونه کدش رو زده بودیم، میتونید اینجا یه نیم نگاهی بندازید) بیاید یک مثال ساده بزنیم. فرض کنید یک تابع داریم که بهش یک متن میدی و اون رو نمایش میده. حالا میخوایم جای اینکه هربار تابع رو صدا زدیم متن رو نشون بده، جمع کنه هر ۵ ثانیه همه رو با هم نشون بده.type Printer struct {
   channel chan string
}
func (p *Printer) Print(s string) {
   p.channel &lt;- s
}
func (p *Printer) work() {
   for {
      time.Sleep(5 * time.Second)
      // reading
      batch := &amp;quot&amp;quot
      lenChannel := len(p.channel)
      if lenChannel == 0 {
         continue
      }
      for i := 0; i &lt; lenChannel; i++ {
         batch += &lt;-p.channel + &amp;quot\n&amp;quot
      }
      fmt.Println(&amp;quot\n&gt; batch print on &amp;quot, time.Now())
      fmt.Println(batch)
   }
}
func NewPrinter() *Printer {
   p := &amp;Printer{
      channel: make(chan string, 100),
   }
   go p.work()
   return p
}همونطوری که میبینید یک تایپ جدید به اسم Printer نوشتیم که دو تا متد داره. اولی Print هست که خیلی ساده هرمقداری که میگیره رو توی چنلی که قبلا برای Printer تعریف کردیم میریزه. همچنین متد work که جلوتر میبینیم قراره توی یک گوروتین جدا اجرا بشه. این تابع ۵ ثانیه صبرمیکنه، چک میکنه چقدر توی چنلمون ریخته شده، تک تکشون رو میخونه و درنهایت با هم نمایش میده.نکته ایی که هست تابع NewPrinter هست که یک چنل با ظرفیت ۱۰۰ میسازه، متد work رو به صورت گوروتین اجرا میکنه و در نهایت Printer ایی که ساخته رو برمیگردونه.func main() {
   printer := NewPrinter()
   for {
      printer.Print(&amp;quotHello -&amp;quot + time.Now().String())
      time.Sleep(1 * time.Second)
   }
}در نهایت توی تابع main یک پرینتر میسازیم، و هر ثانیه یک متن جدید رو باهاش پرینت میکنیم. خروجی چطور میشه؟&gt; batch print on  2021-04-11 22:39:48.922123619 +0430 +0430 m=+10.000904303
Hello -2021-04-11 22:39:43.922688513 +0430 +0430 m=+5.001469122
Hello -2021-04-11 22:39:44.923071867 +0430 +0430 m=+6.001852526
Hello -2021-04-11 22:39:45.92339546 +0430 +0430 m=+7.002176162
Hello -2021-04-11 22:39:46.92362527 +0430 +0430 m=+8.002405921
Hello -2021-04-11 22:39:47.924194516 +0430 +0430 m=+9.002975169&gt; batch print on  2021-04-11 22:39:53.92252801 +0430 +0430 m=+15.001308662
Hello -2021-04-11 22:39:48.924275894 +0430 +0430 m=+10.003056544
Hello -2021-04-11 22:39:49.92445176 +0430 +0430 m=+11.003232412
Hello -2021-04-11 22:39:50.924880096 +0430 +0430 m=+12.003660754
Hello -2021-04-11 22:39:51.925031043 +0430 +0430 m=+13.003811747
Hello -2021-04-11 22:39:52.925309521 +0430 +0430 m=+14.004090169اگر میخواید یک کد یکم پیچیده‌تر ولی با همین منطق رو ببینید حتما این مقاله رو مطالعه کنید. از ۸۰۰ ریکوئست برثانیه میرسیم به ۱۴ هزار تا :)چند تا مثال دیگهunc PromiseMe() chan bool {
   c := make(chan bool)
   go func() {
      time.Sleep(2 * time.Second)
      c &lt;- true
   }()
   return c
}

func main() {
   // Simple promise
   a1 := PromiseMe()
   &lt;-a1
   // Wait for all
   a2 := PromiseMe()
   b2 := PromiseMe()
   c, d := &lt;-a2, &lt;-b2
   // Wait for the first one
   a3 := PromiseMe()
   b3 := PromiseMe()
   var c3 bool
   select {
   case c3 = &lt;-a3:
   case c3 = &lt;-b3:
   case &lt;-time.After(time.Second * 2): // 2 seconds timeout
      c3 = false
      // handling timeout
   }
   // all with timeout
   a4 := PromiseMe()
   b4 := PromiseMe()
   ctx, _ := context.WithTimeout(context.Background(), time.Second*1)
   select {
   case &lt;-a4:
   case &lt;-ctx.Done():
   }
   select {
   case &lt;-b4:
   case &lt;-ctx.Done():
   }
}</description>
                <category>انتشارات روبیک</category>
                <author>محمد حسینی راد</author>
                <pubDate>Sun, 11 Apr 2021 23:02:25 +0430</pubDate>
            </item>
                    <item>
                <title>کاربرد Interface ها در PHP و Laravel</title>
                <link>https://virgool.io/RubikGroup/%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%D8%AF-interface-%D9%87%D8%A7-%D8%AF%D8%B1-php-%D9%88-laravel-p0yp4a30i7mi</link>
                <description>واژه Interface به معنی رابط (کاربری) است. رابط کاربری در برنامه نویسی، رفتار (متد) های یک کلاس (ماژول) می‌باشد که دیگر ماژول ها از طریق آنها می‌توانند با آن کلاس (ماژول) ارتباط برقرار کنند.برای مثال، کلاس زیر (Gmail) مسئولیت فرستادن ایمیل را بر عهده دارد.class Gmail {
    public function send(string $to, string $content) {
         // Preparing Gmail API requirements
        $this-&gt;call([$to, $content, $username, $password, $server]);
    }
    private function call(array $parameters) {
        // Send email using the Gmail API
    }
}در کلاس بالا، متد send بصورت public (عمومی) تعریف شده و دیگر ماژول ها برای ارسال ایمیل آن را فراخوانی می‌کنند. این متد، رابط کاربری کلاس محسوب می‌شود. در طرف دیگر، متد call یک متد private (خصوصی) است و تنها مصرف داخلی دارد (متد send از آن استفاده می‌کند) و جزو رابط کاربری کلاس محسوب نمی‌شود.اکنون با استفاده از یک Interface، رابطه کاربری کلاس های ارسال ایمیل را تعریف کنیم.interface Email {
    function send(string $to, string $content);
}در کلاس Gmail نیز مشخص می‌کنیم که این کلاس از رابط کاربری Email پیروی می‌کند.class Gmail implements Email { ... }البته هنوز سوال اصلی که Interface چه کمکی به ما می‌کنند پابرجاست. این سوال را با معرفی اصول SOLID پاسخ می‌دهیم.کاربرد Interface ها در PHP و Laravelاصول SOLIDاصول SOLID، مجموعه پنج اصل مهم در برنامه نویسی شی گرا (Object-oriented programming) است. این اصول عبارت‌اند از:اصل Single-responsibility (تک مسئولیتی)اصل Open-closed (باز-بسته)اصل Liskov substitution (جایگزینی لیسکوف)اصل Interface segregation (تفکیک رابطه کاربری)اصل Dependency inversion (وارونگی وابستگی)اصل Dependency inversion در SOLIDاصل Dependency inversion (وارونگی وابستگی) در برنامه نویسی شی گرا و اصول SOLID، بر وابستگی به تعاریف انتزاعی (Abstraction) به جای وابستگی به پیاده سازی (Concrete یا Implementation) تاکید می‌کند.به بیان ساده ساده تر، ماژول های پروژه باید به Interface ها (مانند Email) وابستگی داشته باشند، نه پیاده سازی ها (مانند Gmail). پیاده سازی ها ممکن است در طول زمان تغییر کنند و فقط Interface ها هستند که ثابت می‌مانند.برای مثال، در زیر یک Controller به نام UsersContronller را می‌بینید. در متد create که Action مربوط به API ساخت کاربر جدید است، پس از ذخیره اطلاعات کاربر در دیتابیس، یک ایمیل خوشامد گویی برای او ارسال می‌کند.class UsersContronller extends Controller {
    public function create(Request $request) {
        // Save user information into database
        $email = new Gmail();
        $email-&gt;send($user-&gt;email, &#039;Welcome dear user...&#039;);
    }
}مشکل Controller بالا تا وقتی که ما تنها از Gmail برای ارسال ایمیل استفاده می‌کنیم ممکن است مشخص نشود. وقتی تصمیم بگیریم از سرویس ایمیل دیگری همچون Mailgun استفاده کنیم، باید این کلاس و دیگر کلاس هایی که از Gmail استفاده می‌کنند را پیدا کرده و کد های آنها را تغییر دهیم.مشکل Controller بالا وابستگی به پیاده سازی (به جای وابستگی به تعاریف انتزاعی) است و اصل Dependency inversion از اصول SOLID را نقض کرده است. برای رفع این مشکل، این Controller را بصورت زیر بازنویسی می‌کنیم.class UsersContronller extends Controller {
    public function create(Request $request, Email $email) {
        // Save user information into database
        $email-&gt;send($user-&gt;email, &#039;Welcome dear user...&#039;);
    }
}دیگر بخش های پروژه را نیز در کد زیر می‌بینید.interface Email {
    function send(string $to, string $content);
}
class Gmail implements Email { ... }
class Mailgun implements Email { ... }از Interface ها نمی‌توان Object (شی) ساخت، اما از کلاس هایی که Interface ها پیاده سازی می‌کنند می‌شود Object ساخت. نوع پارامتر email در متد create کنترلر بالا، اینترفیس Email است. در نتیجه این پارامتر می‌تواند یک Object از کلاسی مانند Gmail یا Mailgun باشد که اینترفیس Email را پیاده سازی می‌کند. هر کلاسی که از رابط کاربری اینترفیس Email پیروی کند مجبور می‌شود متد send را پیاده سازی کند. در نتیجه هر Object که از نوع اینترفیس Email باشد حتما دارای متد پیاده سازی شده‌ی send است.کلاس UsersContronller اکنون وابسته به اینترفیس Email (یک تعریف انتزاعی) است و وابستگی به پیاده سازی هایی همچون Gmail یا Mailgun ندارد. برای استفاده از این کلاس می‌توانید هر پیاده سازی که از رابط کاربری Email پیروی کند را به متد create آن تزریق کنیم. تزریق این وابستگی می‌تواند توسط ابزاری به نام IoCC انجام شود که در بخش بعد شرح داده می‌شود.ابزار IoCCابزار IoCC یا Inversion of Control Container طراحی شده‌اند‌ تا با استفاده از آن اصل Dependency inversion در پروژه رعایت شود. این ابزار در ابتدای اجرای پروژه لیست Abstraction ها و پیاده سازی های آنها را دریافت می‌کنند و در ادامه هنگامی که یک ماژول به یک Abstraction نیاز داشت، پیاده سازی مناسب را در اختیار آن ماژول قرار می‌دهند.در پروژه های PHP می‌توانید از miladrahimi/phpcontainer بعنوان IoCC پروژه استفاده کنید. در پروژه های Laravel می‌توانید از IoCC خود لاراول استفاده کنید.فریم ورک Laravel مجهز به یک IoCC قوی و انعطاف پذیر است. بسیاری از متد ها در پروژه توسط این ابزار فراخوانی می‌شود تا وابستگی های مورد نیاز را تزریق کند. برخی از متد هایی که توسط IoCC لاراول فراخوانی می‌شوند را در زیر می‌بینید.متد های Constructor در Controller هامتد های Controller که نقش Action برای یک Route ایفا می‌کنند (مانند create در مثال بالا)متد های handle مربوط به Middleware هامتد های handle مربوط به Job هامتد های handle مربوط به Command هادر متد register از کلاس App/Providers/AppServiceProvider می‌توانید تعیین کنید که به هنگام نیاز ماژول های پروژه به یک Abstraction، کدام پیاده سازی برای آنها فراهم شود. این فرایند، Bind کردن نام دارد و اصطلاحا Interface یا Abstraction ها را به پیاده سازی های آنها Bind می‌کنیم.برای مثال در یک پروژه، کد زیر در متد register، اینترفیس Email را به پیاده سازی آن که Gmail می‌باشد، Bind می‌کند.class AppServiceProvider extends ServiceProvider {
    public function register() {
        $this-&gt;app-&gt;bind(Email::class, Gmail::class);
    }
    // ...
}اکنون، UsersController را در این پروژه نظر بگیرید.class UsersContronller extends Controller {
    public function create(Request $request, Email $email) {
        // Save user information into database
        $this-&gt;email-&gt;send($user-&gt;email, &#039;Welcome dear user...&#039;);
    }
}می‌دانیم که متد create بعنوان یک Action توسط IoCC لاراول فراخوانی می‌شود تا وابستگی های مورد نیاز آن تزریق شود. با توجه به Binding تعریف شده، IoCC لاراول پیاده سازی Gmail بعنوان پارامتر این متد تزریق می‌کند.علاوه بر متد های معرفی شده برای تزریق وابستگی، مستقیم از خود IoCC نیز می‌توانیم پیاده سازی مورد نیاز را درخواست کنیم. برای مثال کد زیر پیاده سازی مربوط به اینترفیس Email را از IoCC درخواست می‌کند.$email = app(Email::class);
// $email will be an object of Gmailاگر به این روش علاقه‌مند هستید، می‌توانید UsersController را به شکل زیر هم نوشت.class UsersContronller extends Controller {
    public function create(Request $request) {
        // Save user information into database
        app(Email::class)-&gt;send($user-&gt;email, &#039;Welcome dear user...&#039;);
    }
}حال اگر تصمیم بگیریم که در پروژه بجای Gmail از سرویس ایمیل Mailgun استفاده کنیم تنها کافیست متد register در کلاس App/Providers/AppServiceProvider را بصورت زیر تغییر دهیم.$this-&gt;app-&gt;bind(Email::class, Mailgun::class);اصل Open-closed در SOLIDاصل Open-closed (باز-بسته) در در برنامه نویسی شی گرا و اصول SOLID، بر باز بودن ماژول ها برای گسترش یافتن و بسته بودن آنها برای اصلاح تاکید دارد. به بیان ساده تر، ماژول های برنامه نویسی باید طوری طراحی شوند که گسترش آنها راحت باشد تا گسترش به اصلاح ترجیح داده شود.برای مثال، کلاس زیر مسئول ساخت کد ورود کاربران، ذخیره و ارسال آن به شماره همراه کاربر است.class Otp {
    public function make(User $user) {
        $code = andom_int(1000, 9999);

        $userOtp = new UserOtp();
        $userOtp-&gt;user_id = $user-&gt;id;
        $userOtp-&gt;code = $code;
        $userOtp-&gt;save();

        app(Sms::class)-&gt;send($user-&gt;cellphone, $code);
    }
}مشکل کلاس بالا وقتی مشخص می‌شود که مثلا به دلیلی مانند افزایش سرعت سایت، تصمیم بگیریم به جای ذخیره کد های OTP در دیتابیس (MySQL)، آنها را در Redis ذخیره کنیم. آنگاه به ناچار باید کلاس بالا را اصلاح کنیم و اصل Open-closed از اصول SOLID نقض می‌شود.حال کلاس بالا را بازنویسی می‌کنیم و کلاس و Interface های جدیدی معرفی می‌کنیم تا ماژول نهایی از اصل Open-closed از اصول SOLID پیروی کرده باشد.interface OtpStorage {
    function save(string $cellphone, int $code);
}
class MySQL implements OtpStorage {
    function save(string $cellphone, int $code) {
         $userOtp = new UserOtp();
         $userOtp-&gt;user_id = $user-&gt;id;
         $userOtp-&gt;code = $code;
         $userOtp-&gt;save();
    }
}
class Redis implements OtpStorage {
    function save(string $cellphone, int $code) {
        Redis::put($cellphone, $code);
    }
}
class Otp {
    public function make(User $user) {
        $code = random_int(1000, 9999);
        app(OtpStorage::class)-&gt;save($user-&gt;id, $code);
        app(Sms::class)-&gt;send($user-&gt;cellphone, $code);
    }
}حال برای تغییر روش ذخیره سازی کد های ورود کاربران از MySQL به Redis، تنها کافیست که Binding آن در متد register از کلاس App/Providers/AppServiceProvider از$this-&gt;app-&gt;bind(OtpStorage::class, MySQL::class);به صورت زیر تغییر کند:$this-&gt;app-&gt;bind(OtpStorage::class, Redis::class);و دیگر هیچ تغییری در کلاس Otp نخواهیم داشت. اکنون کلاس Otp قابلیت گسترش یافتن (افزودن روش های ذخیره سازی جدید) را دارد اما نیازی به اصلاح شدن ندارد.اصول ISP ،SRP و LSP در SOLIDاصل SRP یا Single-responsibility principle (تک مسئولیتی) در برنامه نویسی شی گرا و اصول SOLID، بر تک کاربرد (مسئولیت) بودن ماژول ها، کلاس ها و Interface ها تاکید دارد.اصل ISP یا Interface segregation principle (تفکیک رابطه کاربری) در برنامه نویسی شی گرا و اصول SOLID، بر تعدد Interface ها و طراحی آنها بر اساس نیاز کاربر به جای طراحی یک Interface جامع تاکید می‌کند.اصل LSP یا Liskov substitution principle (جایگزینی لیسکوف) در برنامه نویسی شی گرا و اصول SOLID، بر قابلیت جایگزین شدن Type با Subtype های آن Type تاکید دارد. بعنوان مثال مربع یک Subtype از مستطیل است، پس اگر این اصل در پروژه رعایت شده باشد، ماژولی که مستطیل را بعنوان ورودی قبول می‌کند باید بتواند مربع را هم به عنوان ورودی بپذیرد.سه اصل ذکر شده را با یک مثال و در رابطه با استفاده صحیح از Interface ها شرح می‌دهیم.برای مثال، Interface زیر را در نظر بگیرید:interface Notification {
    function sendSms(string $to, string $content);
    fucntion sendEmail(string $to, string $contnet);
}واضح ترین اصلی که در طراحی Interface بالا رعایت نشده، اصل Single-responsibility است. این Interface  می‌تواند به دو Interface (یکی Email و دیگری Sms) تقسیم شود. برای رعایت این اصل باید Interface را تا جایی که امکان دارد خرد کنیم تا به Interface هایی برسیم که تنها یک مسئولیت دارند.طبق اصل Interface segregation که مختص به طراحی Interface هاست نیز بر طراحی طبق نیاز کاربر تاکید دارد. برای مثال UsersController که در بخش های قبلی معرفی شد تنها به ارسال Email نیاز دارد اما این Interface قابلیت ارسال SMS هم در خود جای داده که بیشتر از نیاز کاربر (UsersController) است و در نتیجه این اصل هم از اصول SOLID نقض شده است.مشکل بزرگتری که این Interface دارد به هنگام پیاده سازی آن مشخص می‌شود. واضح است که این Interface تنها پیاده سازی هایی را می‌تواند قبول کند که هم خدمات Email و هم خدمات SMS ارائه می‌دهد. برای مثال اگر بخواهیم پیاده ‌سازی مانند Gmail داشته باشیم که تنها متد sendEmail را می‌تواند پوشش دهد و متد sendSms را خالی رها کنیم آنگاه باید دقت کنیم که ماژولی که Gmail را به آن تزریق می‌کنیم تلاش نکند با استفاده از آن SMS ارسال کند. به بیانی، به همه ماژول هایی که به اینترفیس Notification نیاز دارند نمی‌توانیم Gmail را تزریق کنیم چرا که ممکن است به sendSms نیاز داشته باشد و اگر Notification را Type و Gmail را Subtype آن در نظر بگیریم، اصل Liskov substitution از اصول SOLID را نقض کرده ایم.سخن پایانیدر این مقاله سعی کردیم کاربرد ها و نحوه استفاده صحیح از Interface ها را در PHP و Laravel شرح دهیم. برای شرح این موارد به اصول SOLID تکیه کردیم. هم Interface و هم اصول SOLID کاربرد های فراتری دارند که قطعا در یک مقاله کوتاه نمی‌توان جا داد. با این وجود امیدوارم این مقاله توانسته باشد شما را با این دو مهم در برنامه نویسی آشنا کرده باشد.</description>
                <category>انتشارات روبیک</category>
                <author>میلاد رحیمی</author>
                <pubDate>Sun, 11 Apr 2021 15:45:43 +0430</pubDate>
            </item>
                    <item>
                <title>آموزش ساخت progress bar در پایتون</title>
                <link>https://virgool.io/RubikGroup/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D8%B3%D8%A7%D8%AE%D8%AA-progress-bar-%D8%AF%D8%B1-%D9%BE%D8%A7%DB%8C%D8%AA%D9%88%D9%86-xyctq779p50p</link>
                <description>سلام با آموزش ساخت progress bar با پایتون در خدمت شما هستیمبریم سر آموزش اول از همه کتابخونهtqdmرو با پیپ نصب می کنیمpip install tqdmبعد از نصب کتابخونه از tqdm که کتابخونه ای که نصب کردیم هست tqdm رو ایمپورت می کنیم from tqdm import tqdmبعد از ایمپورت کردن یک حلقه for می نویسیمfor i in tqdm(range(10000)):    passبعد از اجرای این کد progress bar تا 10000 می رهکد کامل ما اینه :موفق باشید لایک و کامنت فراموش نشه</description>
                <category>انتشارات روبیک</category>
                <author>M0_1S</author>
                <pubDate>Sat, 10 Apr 2021 15:46:33 +0430</pubDate>
            </item>
            </channel>
</rss>