بلاکچین – چطور کار میکنه؟

بلاکچین یک پایگاه داده توزیع شده است. هر چند اکسل دیتابیس نیست ولی یه چیزی شبیه به همون و تفاوت اصلیش اینه که داده ها چطور توش ذخیره و چطور قابل دسترسی هستند.

بلاکچین یک سری برنامه داره که بهش میگن script که این script ها کارهایی که تا حالا شما توی پایگاه داده های معمولی انجام میدادید رو به صورت اتوماتیک انجام میدن. مثل ذخیره سازی داده ها و دسترسی به اونها.

بلاکچین توزیع شده است یعنی هر بلاک که نوشته میشه، چند تا کپی میشه و توی چند کامپیوتر دیگه ذخیره میشه. اگر بخایم ببینیم یه بلاک سالم هست یا نه (تقلبی نیست) بلاکچین با چند تا کپی موجود مقایسه میکنه و صحت سنجی میکنه.

بیتکوین هم بستر بلاکچین مخصوص به خودش رو داره. که تراکنش ها توی بلاکهایی با حجم 4 مگابایت ذخیره میکنه (توی بلاکچین های دیگه این مقدار فرق میکنه). وقتی که یک بلاک پر میشه با یک الگوریتم رمزنگاری، رمز میشه و از اون یک عدد (مبنای 16) به دست میاد. به این عدد میگن block header hash یا مقدار هش هدر مربوطه به بلاک. این مقدار توی هدر بلاک بعدی قرار میگیره و باز هم با مقدارهای دیگه که توی این هدر جدید موجود هست رمزنگاری میشه و به این شکل یک رشته یا شبکه ایجا میشه. بخاطر همین بهش میگن بلاکچین.

بلاکچین – چی هست؟

بلاکچین یک دیتابیس توزیع شده است. دیتابیسی که به جای اینکه توی یک سرور نصب بشه، توی هزاران کامپیوتر تقسیم شده (توزیع شده). دیتابیسی که توی یه سرور نصب بشه ممکنه با خاموش شدن سرور از بین بره، ممکنه افراد سودجود ازش بهره برداری کنن، دولت ها میتونن دسترسی بهش رو محدود کنند و ممکنه توش اطلاعات یا داده ها خراب بشه و یه جاهایی اطلاعات از بین بره.

ولی توی بلاکچین این داده ها بین هزاران کامپیوتر تقسیم شده. پس کسی نمیتونه اون اطلاعات رو از بین ببره. بلاکچین میاد داده ها رو بین کامپیوترهای مختلف توی بلاک های مختلف ذخیره میکنه و وقتی داده جدیدی به این اضافه میشه یه بلاک اضافه میشه و مدام در حال بزرگ شدنه. هر بلاک طی یه عملیات ریاضی که توسط کامپیوترها یا ماینرها (معدنچی ها) ساخته میشه و توسط سه ماینر دیگه صحت سنجی میشه پس اگر در یکی از بلاک ها داده خراب بشه توسط اون سه نفر دیگه درست میشه. از توضیحات دیگه توی این پست میگذرم چون اینجا فقط تعریف میکنیم.

پس بلاکچین یک پایگاه داده توزیع شده روی رایانه های مختلف هست. جوری دیگه هم میشه تعریف کرد. بلاکچین مثل دفتر کل حسابدارهاست ledger. دفتر کل دفتری هست که تمامی تراکنش های مالی یه سازمان توش نوشته شده و چیزی توش از قلم نمی افته. بلاکچین هم همینه. هر تراکنشی انجام بشه توی بلاک ها ذخیره میشه.

از اونجایی که نمیشه یه بلاک قلابی ساخت پس صحت اطلاعات توی بلاکچین تضمین شده است. دیگه نیاز نیست یه سازمان ثالث بیاد حسابرسی کنه که صحت این دفترکل رو تایید کنه.

روی این بستر بلاکچین امکاناتی ساخته شده. مثل رمزارزها (مثلا بیتکوین یا اتریوم)، اپلیکیشن های توزیع شده مالی DeFi یا Decenteralized Finance، توکن های غیرقابل جعل NFT یا non-Fungible token و smart contract ها که به فارسی میشه قراردادهای هوشمند.

این قابلیتها از این بستر و قابلیت ها اون استفاده میکنن. مثلا گفتیم که داده های داخل بلاکچین قابل جعل نیست پس برای ساخت قراردادهای هوشمندی که نشه جعلش کرد عالیه. یا مثلا بخاطر اینکه تراکنشها از ببین نمیره و قابل اتکاست برای سیستم های مالی عالیه و …

یک نمونه AJAX

در یک پروژه پرتکرار از AJAX استفاده کردیم و یه نمونه پیچیده شو اینجا میزارم.

در کد بالا route زیر که مربوط به یک view توی جنگو هست صدا زده شده

این یک route مربوطه به جنگو هست که یک پارامتر به اسم dep_id هم میگیره. قسمت جالب این کد اینه که همین کد جاوااسکریپت با django template engine داره render میشه و بعد توسط .replcace اصلاح میشه

نمونه route و view رو هم در ادامه میبینید.

Liskov substitution principal یا قاعده جانشانی لیسکوف

LSP یک اصل از SOLID هست که میگه:

اگر S یک زیرنوع(Subtype) از T باشد، آنگاه در یک برنامه باید بتوان یک شیء از نوع T را با یک شیء از نوع S جایگزین کرد بدون اینکه این برنامه هیچ تغییری نیاز داشته باشد. به بیان ساده تر آبجکت کلاسهایی که والد و فرزند هستن باید بدون هیچ مشکلی در یک برنامه جای هم استفاده شوند.

مثال معروف بالا یک نمونه LSP رو نشون میده یه برنامه حسابداری هست که قیمت License رو حساب میکنه. حالا این محصول ما دو نوع license داره شخصی و شرکتی PersonalLicense و Business License. نکته اینجاست اگر به برنامه Billing ها یک شیء از هرکدوم این کلاسها رو پاس بدیم هیچ تغییری در رفتار Billing وجود نداره و نیازی هم به تغییر کد نیست بنابراین یک LSP هست.

مثال بعدی اینه که میدونیم مربع یک نوع مستطیل هست که اضلاعش با هم برابره. اما نمیتونیم بگیم توی یک برنامه شیء مربع قابل جایگزین با مستطیل نیست. چراکه مستطیل دو تابع داره setWeight و setHeight که طول و عرضش رو ست میکنه. حالا اگه توی یک مربع هر کدوم از این دوتا رو فراخوانی کنیم اونیکی هم تغیییر میکنه چون طول و عرض باید برابر باشن. بنابراین اگر به یک برنامه که یک شیء از مربع رو به جای مستطیل پاس بدیم نیاز هست که کد این برنامه رو هم تغییر بدیم که (مثلا با یک if که چک کنه مربعه یا مستطیل). بنابراین این مثال یک LSP نیست.

OCP در SOLID

OCP یا Open Closed Principal یکی از اصول SOLID هست. که میگه یک نرم افزار باید قابل توسعه و گسترش باشه و نسبت به تغییر بسته باشه.

A software artifact should be open for extention and closed for change.

یعنی توسعه پذیر باشه. به این معنی که اگر نیازمندی جدید بیاد با همین معماری بتونیم اون قابلیت رو اضافه کنیم ولی نه با تغییر اصول قبلی.

توی کتاب Clean Architecture یه مثال اومده که خیلی توضیحات داره و پیچیده است و جالب اینه که توی یکی از پست های همین بلاگ من یه مثال دارم که مثال خوبی برای OCP هست.

توی مثال ها گفته شده شما باید معماری رو جوری بچینید که اون بخش هایی که بنظرتون نباید تغییر کنن محافظت بشن. توی مثال این کتاب گفته: اگر کامپوننت A قراره از تغییر توی کامپوننت B محافظت بشه، کامپوننت B به وابستگی به کامپوننت A داشته باشه. مثل رابطه مدل ها توی دیتابیس.

توی این پست ما با یه چالش روبه رو بودیم.

چالش این بود که یه مدل Company داشتیم و میخواستیم یه فیلد عکس logo بهش اضافه کنیم و فکر کردم چون از این مدل در جاهای مختلف استفاده شده احتمالا این تغییر در جاهای مختلف Impact داره و باید بریم اونجاها رو هم تغییر بدیم. از طرفی نخواستم این مدل رو تغییر بدم و مجبور شم این مدل رو با migration توی دیتابیس تغییر بدم بنا براین به این نتیجه رسیدم که برای لوگو یک مدل جدید بسازم و یک رابطه یک-به-یک داشته باشن.

با این کار در واقع از مدل Company محافظت کردم. از این به بعد اگر بخوایم از یک مدل یا کلاس یا به صورت کلی یک کامپوننت محافظت کنیم باید بقیه به اون وابستگی داشته باشن و اون به کامپوننتی وابسته نباشه.

پس OCP یک اصل در معماری نرم افزاره که هدفش اینه که سیستم رو توسعه پذیرتر کنه و نیاز به تغییر در کامپوننت های قبلی در توسعه ها رو به حداقل برسونه. این هدف با پارتیشن بندی بخش های نرم افزار محقق میشه. با رده بندی کامپوننت ها با استفاده از وابستگی اونها به صورتی که یه سلسله مراتب ایجاد شه که از کامپوننتهای سطح بالا محافظت بشه که توی کامپوننت های سطح-پایینتر تغییر نکنن.

SRP یا Single Responsibility Principal

این اصل SOLID به این معنی نیست که هر ماژول از کد باید یک وظیفه داشته باشه (در نگاه اول اینطور به نظر میرسه).

این اصل میگه که:

A module should have one and only one reason to change

هر ماژول فقط یک دلیل برای تغییر باید داشته باشه. این یعنی چی؟ در واقع هر برنامه برای این ساخته شده که کار یک مشتری یا یک stakeholder رو راه بندازه. در واقع مشتری دلیل تغییر کد میتونه باشه. بنابراین میتونیم این جمله رو اینجوری بنویسیم

“هر ماژول فقط باید مسئول یک مشتری یا کاربر باشه”

مشتری منظور شخص نیست، چرا که توی یک تیم 20 نفر ممکنه یک نقش داشته باشن پس بهتره به جای کاربر یا مشتری بنویسیم Actor.

A module should be responsible to one and only one actor

هر ماژول فقط باید به یک Actor مرتبط باشه.

با یک مثال میتونیم بهتر بفهمیم:

فرض کنید یه ماژول داریم به اسم Employee که سه تا قسمت داره: CalculatePay و ReportHours و Save

CalculatePay برای محاسبه پرداختی استفاده میشه و مورد استفاده مدیر مالی. ReportHours برای محاسبه ساعات کارکرد نیازه برای استفاده مدیر منابع انسانی و Save با الگوریتمی بهینه داده ها رو توی دیتابیس ذخیره میکنه و مورد استفاده مدیر IT.

همینطور که میبینید این ماژول سه تا actor داره. فرض کنید که CalculatePay و ReportHours هر دو از یک الگوریتم استفاده میکنن (چون توی یک ماژول هستن برای جلوگیری از duplication برنامه نویس فکر کرده که هردو باید از یک الگوریتم استفاده کنن) فرض کنید مدیر مالی تصمیم میگیره که الگوریم محاسبه پرداختی تیمش رو تغییر بده و بعد از یک ماه مدیر منابع انسانی متوجه میشه محاسبه پرداختی تیمش تغییر کرده بدون اینکه خبر داشته باشه.

بنابراین:

seperate the code that different actors depend on

بهتره هر ماژول فقط یک actor داشته باشه.

مثال دوم اینه که:

اگر به حالتی برخوردید که یک ماژول توسط برنامه نویسان دو واحد همزمان توسعه داده میشه و توی Merge کردن کد به conflict میخورید یعنی این ماژول برای دو actor توسعه داده شده و بهتره اصلاح شه.

راه حل:

بهترین راه حل اینه که دیتا و توابع رو از هم جدا کنیم ینی یه کلاس داشته باشیم به اسم EmployeeData که سه تا کلاس PayCalculator و HourReporter و EmployeeSaver از اون به ارث میبرن و از همدیگه هییچ اطلاعی ندارن. این جوری هر کدوم رو تغییر بدیم فقط یه actor تحت تاثیر قرار میگیره.

مشکلش اینه که الان برنامه نویسا 3 تا کلاس دارن که توسعه بدن که برای حل این مشکل میشه از Facade Pattern استفاده کرد و یک EmployeeFacade ساخت که از سه تا کلاس به ارث می بره.

EmployeeFacade کد خیلی کمی داره. وظیفه اش صرفا ساختن نمونه و مقدار دهی اولیه هر کلاس و دادن اجرای برنامه به اون کلاسه نه چیزی بیشتر instantiating and delegating

بعضی برنامه نویسها هم ترجیح میدن که قسمتهای خیلی مهم کد رو نزدیک کلاس Data بزارن.

پس اصل SRP به توابع و کلاسها (در واقع component level) کار داره. اما تاثیرش رو توی معماری میزاره

اصول SOLID یا SOLID Principals

در زمینه توسعه محصول در هر بخش اصولی وجود داره که برای توسعه نرم افزاری استاندارد باید رعایت بشه. یک سری اصول در لایه های پایینی و جزئی نرم افزار وجود دارن. مثلا کد داخل توابع رو چطور بنویسیم، چطور به دیتابیس query بزنیم و اصلا چطور متغیرها رو تعریف کنیم و … اینها برای خودشون اصولی دارن ولی SOLID به این بخش مرتبط نیست.

توی لایه های بالاتر میگیم حالا این توابع و متغیرها و داده ها وقتی دسته بندی میشن با چه اصولی کنار هم قرار بگیرن. اگر بخایم زبان های OOP رو در نظر بگیریم در واقع مرتبط به داخل کلاس class میشه. اصول SOLID مربوط به این دسته بندی هاست یعنی توی لایه میانی mid-level.

لایه بالاتر میشه معماری که SOLID به اینجا هم مربوط نیست.

SOLID میگه این لایه میانی باید جوری نوشته بشه که:

  1. قابل تغییر باشه
  2. قابل فهم باشه
  3. ساختن بخش هایی از نرم افزار که خودشون بخش هایی از ماژولهای بزرگتر خواهند بود

اگر بخایم یه مثال قابل فهم بزنیم. فرض کنیم میخایم یه ساختمون تولید کنیم. بخشی از افراد دارن آجر درست میکنن. طبیعتا اگر آجرها مقاوم نباشن دیگه اتاقها و پارکینگ خوبی هم نمیشه ساخت. اما فرض کنیم که آجرها و مواد اولیه خوب ساخته شده حالا بازم اگر از اصولی پیروی کنیم ممکنه پارکینگ یا اتاق خوبی نسازیم پس از یک اصولی استفاده میکنیم تا بخش های ساختمون درست ساخته بشه SOILD با ساختن آجر کاری نداره با ساختن پارکینگ و لایه میانی کار داره.

اصول SOLID شامل موارد زیره:

SRP یا Single Responsility Principal

OCP یا Open Closed Principal

LSP یا Liscov Substitution Principal

ISP یا Interface Segregation Principal

DIP یا Dependency Inversion Principal

ارور دسترسی روی gitlab

gitlab رو توی داکر بالا آوردم ولی بعضی از کاربران برای لاگین ارور 422 میگرفتن. بعد از بررسی متوجه شدم که باید از مسیر زیر کانفیگ رو تیک بزنیم که resource های خارجی هم بتونن دسترسی داشته باشن. چون gitlab رو روی داکر بالا میارید این وسط لودبالانسر قرار میگیره

Admin → Settings → Network → Outbound Requests 

Structured vs Functional vs Object Oriented

هر کدوم از این پارادایم های برنامه نویسی شرایط خاصی دارن.

OOP یا برنامه نویسی شیء گرا. وقتی میگیرم یه برنامه OOP هست که سه پیلار زیر در کل برنامه حاکم باشه. بنابراین به ما میگه که برنامه شامل قسمت هایی هست که ما کنترل رو به صورت غیرمستقیم به کامپوننتهای مختلف داده میشه و بنابراین میشه بخش های مختلف برنامه جداگانه قابل توسعه باشه.

  1. Encapsulation
  2. Inheritance
  3. Polymorphism

وقتی میگیم یک برنامه Structured هست که از توابع قابل تست استفاده شده باشه. عملا الان هر کسی داره کد میزنه structured کد میزنه. این مفهوم زمانی شکل گرفت که با زبانهایی مثل Assembly برنامه نوشته میشد. برنامه نویسی Functional روی انتقال کنترل برنامه به صورت مستقیم تاکید داره.

Functional Programming وقتی میتونیم ادعا کنیم که برنامه مون کاملا Functional هست که تمامی متغیرها غیرقابل تغییر باشن Immutable و بنابراین مجبور میشیم از یک زبان Functional هم استفاده کنیم که ابزارهای کار با این متغیرها رو به ما میده. Functional Programming بر روی انتصاب به متغیرها محدودیت میزاره.

یعنی عملا هر کدام از این پارادایم ها یک محدودیت خاص بر روی برنامه های ما میزاره و هیچ کدوم چیزی اضافه نمیکنه.

Structured Programming

کسایی که قبلا Assembly کد زدن میدونن برنامه ها چطور بود. شما یک سری دستور پشت هم میچیدید و هر جایی لازم بود از GOTO و JUMP استفاده میکردید که برنامه بره به جای جدید و اون تیکه رو اجرا کنه. مثلا از خط 20 میگفتیم برگرد به خط 10. با این تکنیک عملا حلقه هم پیاده سازی میشد. ولی بعدا این روش منسوخ شد و توی برنامه توابع تعریف شدن. مفاهیم حلقه با کلید های جدید شکل گرفتن. به این روش جدید میگن structured programming.

Structured programming یعنی برنامه رو به بخش های مختلف و توابع مختلف تقسیم کنیم و بتونیم هر کدوم از اون توابع یا بخش ها رو تست کنیم. تست کنیم که در چه شرایطی غلط کار میکنن و بنابراین اطمینانی از برنامه داشته باشیم.