CodeCrafters
765 subscribers
91 photos
51 videos
42 files
170 links
Download Telegram
CodeCrafters
با توجه به جدول City : سوال :فهرست نام‌های CITY که با حروف صدادار (یعنی a، e، i، o یا u) شروع می‌شوند را از STATION جستجو کنید. نتیجه شما نمی تواند حاوی موارد تکراری باشد. سطح : آسان راهنمایی : جز استفاده از WHERE که برای ایجاد شرط در SQL است باید از تابع…
پاسخ : چند تا از جواب های ممکن :

SELECT DISTINCT CITY FROM STATION WHERE LEFT(CITY,1) IN ('A','E','I','O','U');

SELECT DISTINCT CITY FROM STATION WHERE UPPER(CITY) RLIKE '^[AEIOU]';

SELECT DISTINCT CITY FROM STATION WHERE CITY LIKE "A%" OR CITY LIKE "E%" OR CITY LIKE "I%" OR CITY LIKE "O%" OR CITY LIKE "U%";

SELECT DISTINCT CITY FROM STATION WHERE UPPER(SUBSTR(CITY, 1, 1)) IN ('A', 'E', 'I', 'O', 'U');
2👏1
اگه به این سوال ها علاقه دارید (علاقه موج میزنه ☹️)
میتوانید از سایت هکر رنگ استفاده کنید
سوال ها از ساده تا پیشرفته طبقه بندی و جز SQL چند تا زبان برنامه نویسی دیگه هم پشتیبانی میکنه
اگر جواب سوالی نتوانستید پاسخ بدهید میتوانید از بخش بحث(Discussions) جواب را پیدا کنید اگر توانستید حل کنید هم باز سری به این بخش بزنید و جواب های دیگران ببینید دید خوبی از SQL به دست می آورید .

https://www.hackerrank.com/
👍6💩1
تراکنش در دنیا پایگاه داده ها: قهرمان‌های گمنامِ پشت صحنه 💪

در دنیای پایگاه داده، تراکنش (Transaction) مثل یه گروه سربازه که یا با هم تا تهِ خط می‌رن، یا همه با هم برمی‌گردن. وقتی حرف از تراکنش ها می‌شه، خیلی‌ها یاد تراکنش حساب‌های بانکی میفتن و با خودشون می‌گن: «وا، من که به این پیچیدگی‌ها نیاز ندارم!» اما حقیقت اینه که تراکنش ها فقط مال پایگاه‌های داده‌ی بانک‌ها نیستن. خیلی وقت‌ها مردم گیر یه سری مثال‌های بانکی می‌افتن و فراموش می‌کنن که تو دنیای واقعی، تراکنش ها چقدر کاربرد دارن.

با استفاده از تراکنشها برنامه‌نویس‌ها نه تنها وقتِ خودشون رو ذخیره می‌کنن، بلکه کد مورد نیازشون برای برنامه‌هایی که به پایگاه داده وابسته هستن رو هم کم می‌کنن. اگه پایگاه داده خودش وضعیت تراکنش رو مدیریت نمی‌کرد، باید خود برنامه‌نویس این کار رو انجام می‌داد. به نظر ساده میاد، ولی وقتی با داده‌های مرتبط به هم سروکار داشته باشیم، خیلی زود پیچیده می‌شه.

مثلاً به مراحل ثبت‌نام ساده‌ی یه کاربر فکر کنین. این مراحل باید یه رکورد کاربر و یه رکورد حساب بسازن و بعد اون‌ها رو به هم وصل کنن. بدون تراکنش باید تک تک مراحل رو تو برنامه بنویسیم:

کاربر رو بساز
اگه موفق نبود، خارج شو و پیام خطا بفرست
حساب رو بساز
اگه موفق نبود، کاربر رو حذف کن، خارج شو و پیام خطا بفرست
کاربر رو به حساب وصل کن
اگه موفق نبود، کاربر، حساب رو حذف کن، خارج شو و پیام خطا بفرست

اما با تراکنش، می‌تونیم راحت‌تر و تمیزتر عمل کنیم:

تراکنش رو شروع کن
حساب رو بساز
کاربر رو بساز
کاربر رو به حساب وصل کن
تراکنش موفقیت‌آمیز بود؟
اگه آره، پیام موفقیت رو برگردون
اگه نه، پیام خطا رو برگردون

حالا دیگه نگران این نیستیم که بخاطر یه دستوری که موفق نشده، بقیه رو پاک کنیم. یا همه با هم درست انجام می‌شن، یا همه با هم شکست می‌خورن. به همین سادگی!

خب، حالا می‌بینیم که تراکنش ها نه تنها پیچیده نیستن، بلکه تو خیلی از کارها می‌تونن دست چپ و راست برنامه‌نویس‌ها باشن. دیگه این قهرمان‌های گمنام دنیای پایگاه داده رو دست‌کم نگیرین!

#postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1👏1
تراکنش های ابتدایی

ساده‌ترین تراکنش در زیر آمده است. با استفاده از BEGIN تراکنش را شروع کرده و با COMMIT آن را پایان می‌دهد.
sql 

BEGIN;
INSERT INTO employees (first_name, last_name, start_date, salary, job_title, manager_id, department_id) VALUES ('Elizabeth', 'Christensen', current_date, 1, 'Master of the Highwire', 2, 2) RETURNING employee_id;
COMMIT;


مثل آب خوردن کار کرد، درسته؟ شبیه اینه که یه دستور معمولی رو اجرا کنیم ( داریم از دستور RETURNING استفاده می‌کنیم تا بعداً چیزی رو ثابت کنیم). برای اینکه مطمئن بشید داده‌ها ثبت شدن، حالا این دستور رو بزنید:


SELECT    * FROM employees  WHERE    first_name = 'Elizabeth' AND    last_name = 'Christensen';


اما اگر تصمیم بگیرید به جای COMMIT، تراکنش را ROLLBACK کنید، نتیجه‌ای متفاوت خواهید داشت:

BEGIN;

INSERT INTO employees (first_name, last_name, start_date, salary, job_title, manager_id, department_id) VALUES ('Chris', 'Winslett', current_date, 1, 'Jr Director of the Highwire', 2, 2) RETURNING employee_id;

ROLLBACK;


وقتی از دستور ROLLBACK استفاده می‌کنی، مثل این میمونه که داری به پایگاه داده میگی: «بیخیال این تراکنش شو، انگار نه انگار اتفاقی افتاده.» با این کار، هر تغییری که توی تراکنش انجام شده بود، پاک میشه و توی تاریخچه پایگاه داده ذخیره نمیشه. اما یه نکته جالب اینجاست: با اینکه تراکنش ثبت نمیشه، اما پایگاه داده باز هم یه شناسه برای اون تراکنش در نظر می‌گیره. ولی اگه بعدا بخوای اون رکورد رو با دستور select پیدا کنی، هیچی پیدا نمیشه، چون از اول ثبت نشده بوده!!
SELECT * FROM employees WHERE first_name = 'Chris' AND last_name = 'Winslett';

می‌دونی چرا وقتی یک تراکنش رو شروع می‌کنی، حتی قبل از اینکه اون رو نهایی کنی، یک مقدار شناسه (ID) بهت برمی‌گردونه؟

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

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

برای جلوگیری از این مشکل، دنباله‌ها حتی قبل از اینکه تراکنش نهایی بشه، مقدار شناسه بعدی رو تولید می‌کنن. این کار باعث می‌شه که هر دو تراکنش مقدار شناسه متفاوتی رو دریافت کنن.

حالا، اگه تراکنش رو نهایی نکنی، مقدار شناسه‌ای که بهت برمی‌گردونه، فقط یک مقدار موقتی هست. این مقدار تا زمانی که تراکنش نهایی بشه، در پایگاه داده ذخیره نمی‌شه.

اگه تراکنش رو با دستور ROLLBACK لغو کنی، مقدار شناسه‌ای که بهت برمی‌گردونده، از بین می‌ره.

برای اینکه مطمئن بشی که مقدار شناسه‌ای که دریافت می‌کنی، در پایگاه داده ذخیره شده، باید تراکنش رو با دستور COMMIT نهایی کنی.

اگه در حین انجام تراکنش، خطا رخ بده، نمی‌تونی اون رو نهایی کنی. در این صورت، مقدار شناسه‌ای که دریافت می‌کنی، در پایگاه داده ذخیره نمی‌شه.

BEGIN;
INSERT INTO employees (first_name, last_name) VALUES ('Tom', 'Jones') RETURNING employee_id;
COMMIT;

بعد از اجرای دستور بالا، یک دستور ROLLBACK نشان داده خواهد شد. بنابراین، دستور COMMIT ناموفق بوده است زیرا آخرین وضعیت تراکنش یک خطا است.

#postgresql
@Code_Crafters
👍2
رازهای مخفی تراکنش‌های پایگاه داده: هرچی توی تراکنش هست، همونجا میمونه! (Transaction Scope)

تصور کن یه صندوق داری داری که توش کلی کارای عجیب غریب میشه، ولی هیچکس اجازه نداره سرک بکشه تا وقتی کار تموم نشده! همینه داستان تراکنش‌های پایگاه داده.

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

مثل همون صندوقه، اطلاعات تغییرات مخفیه تا کار تموم نشده، بعدش همه می‌بینن چی به چیه. اینجوری مطمئن می‌شیم که همه اطلاعات با هم هماهنگه و هیچ قاطی‌بازی‌ای نمیشه.

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

#postgresql
@Code_Crafters
2👍1
تراکنش ها در دنیای واقعی

تراکنش‌ها در دنیای واقعی خیلی پیچیده‌تر از مثال‌های ساده‌ای هستند که دیدیم. مثلاً، فرض کن می‌خوایم یه کارمند جدید در شرکتمون اضافه کنیم. این دستورات ساده هستند و به راحتی اجرا می‌شن. ولی اگه در اجرای یکی از این دستورات خطا رخ بده، تمام تغییراتی که انجام شده‌اند، از بین می‌رن:
BEGIN; 
INSERT INTO employees (first_name, last_name, start_date, salary, job_title, manager_id, department_id) VALUES ('Chris', 'Winslett', current_date, 1, 'Jr Director of the Highwire', 2, 2);
INSERT INTO dependents (first_name, last_name, employee_id) VALUES ('oldest', 'kid', (SELECT employee_id FROM employees WHERE first_name = 'Chris' AND last_name = 'Winslett'));
INSERT INTO dependents (first_name, last_name, employee_id) VALUES ('youngest', 'kid', (SELECT employee_id FROM employees WHERE first_name = 'Chris' AND last_name = 'Winslett'));
COMMIT;




اگه دوباره همون کد بالا رو اجرا کنید، بازم با خطا مواجه می‌شید. دلیلش اینه که دوتا مقدار برای employee_id برمی‌گرده. همچنین، کارمند تکراری هم ایجاد نمی‌شه.

وای! چقدر تراکنش‌ها عالین!

حالا بیایید یه کاری کنیم که ببینیم چطوری تراکنش‌ها با خطا مواجه می‌شن.

اول، سعی می‌کنیم مقدار null رو برای فیلد first_name در دستور دوم قرار بدیم. این فیلد توی جدول اجباریه، پس تراکنش با شکست مواجه می‌شه.

بعد، حقوق (salary) رو حذف می‌کنیم. این کار باعث لغو تراکنش قبل از تاییدش می‌شه.

BEGIN;   
INSERT INTO employees (first_name, last_name, start_date, salary, job_title, manager_id, department_id) VALUES ('Bob', 'Young', current_date, 1, 'Jr Director of the Highwire', 2, 2);
INSERT INTO dependents (first_name, last_name, employee_id) VALUES ('oldest', 'kid', (SELECT employee_id FROM employees WHERE first_name = 'Bob' AND last_name = 'Young'));
INSERT INTO dependents (first_name, last_name, employee_id) VALUES (null, 'kid', (SELECT employee_id FROM employees WHERE first_name = 'Bob' AND last_name = 'Young'));
COMMIT;


حواست باشه! اجرای کدی که دیدی، با خطا مواجه شده و به عقب برگشته. یعنی تغییراتی که قرار بود اعمال بشه، ذخیره نشده. نگران نباش، اینجوری اطلاعاتت سالم می‌مونه. برای اطمینان بیشتر، می‌تونی یه سرچ بزنی و ببینی که اسم "Bob Young" توی لیست کارمندا نیست. خیالت راحت!
SELECT *  FROM employees  WHERE  first_name = 'Bob' AND last_name = 'Young';




دلیل این امر این است که تراکنش به طور کامل انجام نشد. این یک حالت "همه یا هیچ" است.

#postgresql
@Code_Crafters
2
تغییرات ساختار در تراکنش ها

شاید تعجب کنید، اما PostgreSQL اونقدر باحال هست که هیچ تغییری توی ساختار پایگاه داده رو ثبت نمی‌کنه تا زمانی که کل تراکنش با موفقیت انجام بشه! این ویژگی توی دنیای پایگاه‌های داده خیلی خاصه و خیالمون رو راحت می‌کنه.

بذارید با یه مثال براتون توضیح بدم. فرض کنید می‌خوایم یه ستون جدید به اسم "middle_name" به جدول "employees" اضافه کنیم. برای این کار، از دستورات زیر استفاده می‌کنیم:
BEGIN;
ALTER TABLE employees ADD COLUMN middle_name VARCHAR(50) DEFAULT NULL;
COMMIT;


دستور "BEGIN" شروع تراکنش رو مشخص می‌کنه و دستور "COMMIT" هم پایان تراکنش رو نشون می‌ده. هر تغییری که بین این دو دستور انجام بشه، تا زمانی که دستور "COMMIT" اجرا نشه، ثبت نمی‌شه.

حالا اگه از دستور \d employees استفاده کنیم، می‌بینیم که ستون "middle_name" به جدول اضافه شده.

اما اگه یه تغییر پیچیده‌تر بخوایم انجام بدیم و یه اشتباه کوچولو توش داشته باشیم، چی می‌شه؟ مثلاً فرض کنید می‌خوایم چند تا ستون جدید برای آدرس به جدول اضافه کنیم، اما یادمون بره که برای ستون "postal_code" یه مقدار پیش‌فرض تعیین کنیم. دستورات زیر رو ببینید:
BEGIN;
ALTER TABLE employees ADD COLUMN address_line_1 VARCHAR(50) DEFAULT NULL;
ALTER TABLE employees ADD COLUMN address_line_2 VARCHAR(50) DEFAULT NULL;
ALTER TABLE employees ADD COLUMN city VARCHAR(50) DEFAULT NULL;
ALTER TABLE employees ADD COLUMN province VARCHAR(50) DEFAULT NULL;
ALTER TABLE employees ADD COLUMN postal_code VARCHAR(50) NOT NULL;
COMMIT;


به خاطر اینکه کل این تغییرات داخل یه تراکنش قرار گرفتن، و چون برای ستون "postal_code" مقدار پیش‌فرض تعیین نکردیم، هیچ کدوم از تغییرات ثبت نمی‌شن! یعنی اگه دوباره از دستور \d employees استفاده کنیم، می‌بینیم که ستون‌های آدرس اضافه نشدن.

به این ویژگی فوق‌العاده می‌گن "Transactional DDL". توی پایگاه‌های داده دیگه که این ویژگی رو ندارن، ممکنه تغییرات نصفه و نیمه انجام بشن و همه چیز بهم بریزه. اما توی PostgreSQL، یا همه تغییرات با موفقیت انجام می‌شن، یا هیچ تغییری ثبت نمی‌شه.

#postgresql
@Code_Crafters
2
تراکنش‌های پیشرفته: نقطه‌ی نجات (SAVEPOINT)

یه ویژگی توپ دیگه از Postgres می‌خوام بهتون معرفی کنم که کار با تراکنش‌ها رو توی شرایط پیچیده خیلی راحت‌تر می‌کنه. اسمش "نقطه‌ی نجات" یا SAVEPOINT هست.

تصور کنید یه تراکنش دارید و چند تا دستور داخلش انجام می‌دید. شاید بخواهید یه جایی وسط کار، یه نقطه‌ی امن داشته باشید که اگه هر اتفاقی افتاد، بتونید به اونجا برگردید و همه چی رو از اول انجام بدید. SAVEPOINT دقیقا همینه!

بذار یه مثال بزنم. فرض کنید می‌خوایم یه کارمند جدید به اسم Bob Young اضافه کنیم، بهش چندتا وابسته اضافه کنیم و بعد تراکنش رو تموم کنیم. ولی ممکنه یه جا تو کار اشتباهی پیش بیاد. برای همین از SAVEPOINT استفاده می‌کنیم:
BEGIN;

INSERT INTO employees (first_name, last_name, start_date, salary, job_title, manager_id, department_id) VALUES ('Bob', 'Young', current_date, 1, 'Jr Director of the Highwire', 2, 2);

SAVEPOINT saved_employee; // این نقطه‌ی نجاته!

INSERT INTO dependents (first_name, last_name, employee_id) VALUES ('oldest', 'kid', (SELECT employee_id FROM employees WHERE first_name = 'Bob' AND last_name = 'Young'));

INSERT INTO dependents (first_name, last_name, employee_id) VALUES (null, 'kid', (SELECT employee_id FROM employees WHERE first_name = 'Bob' AND last_name = 'Young'));

ROLLBACK TO SAVEPOINT saved_employee; // اگه یه مشکلی پیش بیاد، به نقطه‌ی نجات برمی‌گردیم!

COMMIT;


حالا اگه اسم Bob Young رو توی کارمندها Search کنیم، پیداش می‌کنیم، ولی وابسته‌هایش رو نمی‌بینیم. چرا؟ چون وقتی توی اضافه کردن وابسته‌ها یه خطایی پیش اومده، تراکنش رو به نقطه‌ی نجات برگردوندیم و فقط اضافه‌کردن Bob Young انجام شده.

می‌دونم این مثال یه کم مصنوعیه، ولی SAVEPOINT توی شرایط پیچیده‌تری که معمولاً برنامه‌نویس هم باهاش درگیره، خیلی کارآمد میشه. فعلاً شاید لازم نباشه ازش استفاده کنی، ولی خوبه بدونی همچین ویژگی‌ای وجود داره!

#postgresql
@Code_Crafters
3👍1
محاصره در تراکنش ها

یه چیزی هست که شاید خیلی‌هاتون متوجهش نشده باشید. اونم اینه که توی PostgreSQL، حتی ساده‌ترین دستورات هم توی یه تراکنش انجام می‌شن! عجیبه نه؟

شاید بگید "خب چطور می‌شه فهمید؟ ما که تراکنشی شروع نکردیم!". ولی یه خورده صبر کنید... می‌تونیم یه دستوری اجرا کنیم که برامون نشون بده الان داخل کدوم تراکنشیم. بفرما:

SELECT txid_current();


حالا چی شد؟ یه عددی بهتون نشون داد، درسته؟ ولی ما که چیزی شروع نکردیم! چون اون عددی که دیدید، شناسه‌ی تراکنشیه که همین الان توش هستید.

حالا بازم همون دستور رو اجرا کنید. چی می‌بینید؟ اون عدد، یه واحد زیادتر شده! آره، این یعنی حتی همین یه دستور کوچیک، یه تراکنش جدید برا خودش باز کرده.

شاید بپرسید چرا انقدر ریزه‌کاری؟ خب، اینجوری PostgreSQL، خیالش راحته که هر تغییری که انجام می‌شه، یا کاملاً انجام می‌شه، یا اصلاً انجام نمی‌شه. اگه توی یه دستور مشکلی پیش بیاد، کل تراکنش باطل می‌شه و هیچ تغییری اعمال نمی‌شه.

پس یادتون باشه، توی PostgreSQL، همیشه تو یه تراکنش هستید، چه بخواهید، چه نخواهید! این یه جور مراقبت اضافه‌ست که داده‌هاتون رو سالم نگه می‌داره.

#postgresql
@Code_Crafters
👍52
چرا جنگو‌ فریمورک محبوبی هست؟؟؟

بیاید یکم راجبش حرف بزنیم

جنگو‌ خیلی از موارد برنامه نویسی مدرن رو براتون فراهم میکنه بدون اینکه خودتون راجبش حتی دانش کافی داشته باشید و بدونید، که میتونیم به design patterns و clean architecture اشاره کرد

بارها به بچه‌ها گوشزد کردم که business logic رو فراموش نکنید و جدی بگیرید ،کار سختی نیست یک فایل با نام services.py بسازید و موارد مربوط به orm رو داخلش بنویسید (یک دایرکتوری با نام services بسازید و ماژول‌های پایتونی خودتون رو داخلش بزارید) حالا کافیه با dependency inversion principle رو بدونید و داخل کدهاتون رعایت کنید

خب چه اتفاقی افتاد؟؟؟
الان شما اومدین و app رو به سه لایه تقسیم کردید لایه application ، لایه service ، لایه infrastructure , خب این چه مزیتی داره برامون

بیایم ببینیم هر لایه شامل چه چیزی میشه؟؟؟
Application: urls, views
درخواست‌های مشتری در این قسمت مورد پردازش قرار میگیره که داده‌های مورد نیاز رو از لایه service میگیره و اون رو تبدیل میکنه به مقداری که قابل خوندن واسه مشتری هست که میتونه http, drf, grpc و ... باشه


Service:
این لایه همون مبحث business logic رو ارائه میده و تمام موارد مورد نیاز رو در خودش هندل میکنه(وظیفه ذخیره و بازیابی موجودیت‌هارو برامون هندل میکنه) اینجا orm django کار میکنه لایه انتزاع از دیتابیس رو میسازه و بواسطه شی گرایی مارو از پیچیدگی کار رها میکنه

Infrastructure: migrations , models
تو این قسمت شما موجودیت‌ها و مجموعه‌ها رو در یک سیستم ذخیره ساز، ذخیره میکنید ،اینکار با استفاده از مدل‌های جنگو و queries صورت میگیره ، بخش مایگریشن‌ها هم اینجا صورت میگیره
من این همه سردرد رو واسه چی دارم تحمل میکنم خدایی؟؟؟

شما دارید ذره ذره به سمت bounded context ها میرید

خب اینکه گفتیم به چه معناست اصلا؟؟
نکته: ما همیشه میگیم تسک بزرگ رو به چند تسک کوچیکتر بشکنید (بصورت منطقی البته) یک کلاس بزرگ ننویسید یک تابع طولانی نسازید

ما اینهارو‌ رعایت کردیم به کجا داریم میرسیم؟؟؟
جالبه بدونید که داریم به سبک معماری DDD نزدیک میشیم

بیایید ادامه بدیم
خب اصل SoC میاد وسط(پروژه میتونه به بخش‌های کوچکتر و قابل مدیریت تر تقسیم بشه، اجزا میتونه میکروسرویس یا ماژولهای مستقل در یک مونولیت باشند)
همین ترکیب بالا رو بزاریم داخل microservice ، پروژه خودمون رو به چند سرویس منطقی و درست تقسیم کنیم، مدلهای هر سرویس رو داخل یک دیتابیس جدا بزاریم ، FKهای مدل رو به Bigint تبدیل کنیم ارتباط‌ بین سرویس‌ها رو مدیریت و هندل کنیم (اینجا rabbitmq سلام میرسونه) الزامات سرویس‌های بیس رو انجام بدیم (این شد bounded context)

چه اتفاقی داره میافته ؟؟؟
هر بخش داره بصورت مستقل توسعه داده میشه 

نگرانی حاصل از پیچیدگی داره رفع میشه

بهبود توسعه کد و پایداری داره بخوبی اتفاق میافته

پایگاه داده از شکستن داره خارج میشه
به معماری DDD خوش آمدید
این معماری برای پروژه‌های بزرگ مناسبه و اگر یک پروژه قدیمی با حداقل 20 app دارید لازم نیست تعطیلش کنید فقط کافیه با DDD تبدیلش کنید
یک معماری میکروسرویس پیاده سازی کنید

که شامل چند سرویس میشه

هر سرویس در دل خودش چندتا app داره

هر app طبق DDD به سه لایه application , services , infrastructure تقسیم میشه و دیتابیس خودش رو داره

خود جنگو براتون clean architecture رو تا سطح بالایی براتون اتخاذ میکنه

در کدهاتون dependency inversion principle رو رعایت کنید





@code_crafters
4👍2
Media is too big
VIEW IN TELEGRAM
ما از دنیا حذف شده ایم!
#appex #2024 #filternet
👍7
پارتیشن‌بندی | Partitioning

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

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

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

پس پارتیشن‌بندی یه راه بی‌نظیره برای اینکه هم انبار اطلاعاتی منظمی داشته باشی، هم هزینه نگهداری رو مدیریت کنی. دیگه لازم نیست نگران انبار شلوغ و هزینه‌های اضافی باشی!

👩‍💻 #postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
2
سرعتِ جت با پارتیشن‌بندی: وقتی انبارت مرتب باشه، پیدا کردن وسایل هم سریع‌تره! 🚀

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

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

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

👩‍💻 #postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
2
انبار داده‌هات رو جورچین کن: با پارتیشن‌بندی‌های مختلف!

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

چیدمان بر اساس بازه (Range): این محبوب‌ترین مدل برای دسته‌های زمانی یا داده‌های عددی مثل سال، ماه، روزه. مثلا می‌تونی اطلاعات فروش سال ۲۰۲۳ رو تو یه قفسه، سال ۲۰۲۴ رو تو یه قفسه دیگه بذاری. پیدا کردن اطلاعات یه سال خاص سریع و آسون می‌شه.

چیدمان بر اساس لیست (List): اگه داده‌هات یه دسته‌بندی مشخص دارن، مثل موقعیت جغرافیایی یا دسته‌های محصول، می‌تونی از این مدل استفاده کنی. مثلا اطلاعات مشتریای تهران رو تو یه قفسه، مشتریای مشهد رو تو یه قفسه دیگه بذاری. جستجو بر اساس دسته‌های خاص به راحتی انجام می‌شه.

چیدمان بر اساس هش (Hash): وقتی دسته‌بندی مشخصی برای داده‌هات نداری، می‌تونی از این مدل استفاده کنی. یه کد هش به هر تیکه اطلاعات اختصاص داده می‌شه و اونو تو قفسه مربوطه می‌ذاره. شبیه یه انبار با برچسب‌های مخفیه!

چیدمان ترکیبی (Composite): اگه دلت می‌خواد از ترکیب مدل‌های مختلف استفاده کنی، این گزینه ایده‌آله. مثلا می‌تونی داده‌های فروش رو هم بر اساس سال (بازه) و هم بر اساس نوع محصول (لیست) دسته بندی کنی. یه انبار مرتب و تفکیک‌شده‌ی دوبل!

این فقط یه نگاه کلی به مدل‌های مختلف پارتیشن‌بندی بود. حالا می‌تونی انتخاب کنی که کدوم مدل برای انبار داده‌هایت بهتره و یه دیتابیس منظم و دسترسی‌پذیر بسازی!

👩‍💻 #postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍1
بیا یه انبار داده‌های باحال بسازیم: مثال پارتیشن‌بندی با PostgreSQL

فکر کن یه عالمه داده درباره ترموستات‌های هوشمند داریم. دما، تاریخ، وضعیت روشن/خاموش و یه عالمه اطلاعات دیگه. خب، چطوری قراره این انبوه اطلاعات رو منظم و مرتب نگه داریم؟ اینجا با پارتیشن‌بندی تو PostgreSQL آشنا می‌شیم که حکم قفسه‌چین‌های حرفه‌ای رو دارن!

اول یه نگاهی به انبارمون بندازیم:
SELECT * FROM thermostat LIMIT 10;


این دستور ۱۰ تا ردیف اول از جداول thermostat رو نشون میده. هر ردیف شامل تاریخ، شناسه‌ی ترموستات، دمای فعلی و وضعیتش هست. حالا می‌تونیم این انبار رو با پارتیشن‌بندی مرتب‌تر و کارآمدتر کنیم. تو قسمت بعدی قراره ببینیم چطور میشه این کار رو انجام داد!

آماده‌ای بریم سراغ جادوی پارتیشن‌بندی با PostgreSQL؟ ⚡️

👩‍💻 #postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1
ساخت قفسه‌های دیجیتالی: ایجاد جدول پارتیشن‌بندی‌شده

خب، حالا وقتشه دست به کار شیم و قفسه‌های دیجیتالیمون رو بسازیم! برای این کار، یه جدول جدید درست می‌کنیم که از همون اول پارتیشن‌بندی‌شده باشه. مثل اینکه قبل از چیدن وسایل تو انبار، قفسه‌ها رو آماده کنیم.

دستور زیر رو بزن تا جدول جدید iot_thermostat ساخته بشه:
CREATE TABLE iot_thermostat (
thetime timestamptz,
sensor_id int,
current_temperature numeric (3,1),
thermostat_status text
) PARTITION BY RANGE (thetime);


اینجا به PostgreSQL می‌گیم که جدول iot_thermostat رو با پارتیشن‌بندی بر اساس بازه‌های زمانی (RANGE (thetime)) درست کنه. یعنی قراره اطلاعات ترموستات‌ها رو بر اساس تاریخشون توی قفسه‌های جداگانه بچینیم.

یادت باشه که واسه پیدا کردن سریع‌تر وسایل توی انبار، لازمه برچسب‌های راهنما داشته باشیم. برای این کار از ایندکس‌ها استفاده می‌کنیم. دستور زیر یه ایندکس روی فیلد thetime می‌سازه:

CREATE INDEX ON iot_thermostat(thetime);


اینجوری PostgreSQL می‌تونه خیلی سریع‌تر اطلاعات رو بر اساس تاریخ پیدا کنه. دیگه لازم نیست کل انبار رو زیر و رو کنه!

حالا قفسه‌های دیجیتالیمون آماده‌ست که اطلاعات ترموستات‌ها رو توش بچینیم. تو قسمت بعدی می‌بینیم چطوری این کار رو انجام میدیم!

👩‍💻 #postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍2
برچسب‌های روی قفسه‌ها: ایجاد پارتیشن‌های جداگانه

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

دستور زیر قفسه‌هایی برای تاریخ‌های ۲۳ جولای تا ۴ آگوست می‌سازه:

SQL 
CREATE TABLE iot_thermostat07232022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-23 00:00:000') TO ('2022-07-24 00:00:000');
CREATE TABLE iot_thermostat07242022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-24 00:00:000') TO ('2022-07-25 00:00:000');
CREATE TABLE iot_thermostat07252022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-25 00:00:000') TO ('2022-07-26 00:00:000');
CREATE TABLE iot_thermostat07262022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-26 00:00:000') TO ('2022-07-27 00:00:000');
CREATE TABLE iot_thermostat07272022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-27 00:00:000') TO ('2022-07-28 00:00:000');
CREATE TABLE iot_thermostat07282022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-28 00:00:000') TO ('2022-07-29 00:00:000');
CREATE TABLE iot_thermostat07292022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-29 00:00:000') TO ('2022-07-30 00:00:000');
CREATE TABLE iot_thermostat07302022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-30 00:00:000') TO ('2022-07-31 00:00:000');
CREATE TABLE iot_thermosta07312022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-07-31 00:00:000') TO ('2022-08-01 00:00:000');
CREATE TABLE iot_thermostat08012022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-08-01 00:00:000') TO ('2022-08-02 00:00:000');
CREATE TABLE iot_thermostat08022022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-08-02 00:00:000') TO ('2022-08-03 00:00:000');
CREATE TABLE iot_thermostat08032022 PARTITION OF iot_thermostat FOR VALUES FROM ('2022-08-03 00:00:000') TO ('2022-08-04 00:00:000');


یعنی از این به بعد، هر اطلاعاتی که مربوط به تاریخ ۲۳ جولای باشه، مستقیم میره توی قفسه iot_thermostat07232022 و با اطلاعات روزهای دیگه قاطی نمیشه. اینجوری هم انبارت مرتب میمونه، هم پیدا کردن وسایل راحت‌تر میشه.

حالا اگه بخوای اطلاعات یه روز خاص رو ببینی، فقط کافیه به قفسه مربوط به اون روز سر بزنی؛ نیازی نیست کل انبار رو بگردی. این یعنی سرعتِ جت در جستجو و دسترسی به داده‌ها!

👩‍💻 #postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1
چیدن وسایل توی قفسه‌ها: وارد کردن اطلاعات به پارتیشن‌ها

خب، قفسه‌ها آماده‌ان، برچسب‌ها خوردن، حالا وقتشه وسایل رو توشون بچینیم! اینجا با یه دستور ساده، اطلاعات رو از جدول اصلی thermostat به جدول پارتیشن‌بندی‌شده iot_thermostat منتقل می‌کنیم:
INSERT INTO iot_thermostat SELECT * FROM thermostat;

نگران نباش، لازم نیست به PostgreSQL بگی کدوم اطلاعات باید کجا بره. خودش حواسش هست و هر تیکه اطلاعات رو بر اساس تاریخش، توی قفسه مناسبش میذاره. مثل یه ربات قفسه‌چین حرفه‌ای!🤖

برای اینکه مطمئن بشی همه چی درست انجام شده، می‌تونی یه نگاهی به یکی از قفسه‌ها بندازی:
SELECT * FROM iot_thermostat07242022 LIMIT 10;

این دستور ۱۰ تا ردیف اول از قفسه‌ی ۲۴ جولای رو نشون میده. اگه همه چی مرتب باشه، فقط اطلاعات مربوط به همون روز رو باید ببینی.

حالا انبار داده‌هات حسابی مرتب و منظم شده! هم پیدا کردن اطلاعات راحت‌تره، هم مدیریتش آسون‌تره. تبریک میگم، تو یه قفسه‌چین حرفه‌ای شدی!

👩‍💻 #postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍2
انبار مرتب، انبار بی‌دردسر: چرخش پارتیشن‌ها

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

با دستور زیر، قفسه مربوط به ۲۳ جولای (iot_thermostat07232022) رو از انبار اصلی جدا می‌کنیم:
ALTER TABLE iot_thermostat DETACH PARTITION iot_thermostat07232022;

حالا اون یه قفسه مستقل شده و دیگه تو انبار اصلی نیست. می‌تونی اونو به یه انبار آرشیو منتقل کنی تا فقط اطلاعات مهم و اخیر تو انبار اصلی باقی بمونن.

البته قرار نیست انبار خالی بمونه! باید یه قفسه جدید هم برای اطلاعات جدید بسازیم. دستور زیر یه قفسه با برچسب iot_thermostat0842022 ایجاد می‌کنه که اطلاعات ۴ و ۵ آگوست رو توش جا می‌ده:
CREATE TABLE iot_thermostat0842022 PARTITION OF iot_thermostat
FOR VALUES FROM ('2022-08-04 00:00:000') TO ('2022-08-05 00:00:000');


حالا با یه چرخش مرتب، قفسه‌های قدیمی رو آرشیو می‌کنیم و قفسه‌های جدید برای اطلاعات جدید اضافه می‌کنیم. اینجوری انبارت همیشه مرتب و منظم می‌مونه و فقط داده‌های مهم و قابل استفاده توش نگه می‌داری.

اگه قراره این چرخش رو هر روز انجام بدی، می‌تونی از یه ابزار به اسم cron job استفاده کنی تا همه چی به صورت خودکار و بدون زحمت انجام بشه. دیگه لازم نیست خودت قفسه‌ها رو جابه‌جا کنی!

یادت باشه، پارتیشن‌بندی یه ابزار جادوییه که بهت کمک می‌کنه انبار داده‌هات رو هم تمیز و مرتب نگه داری، هم مدیریت و دسترسی به اطلاعات رو آسون‌تر کنه. با چرخش پارتیشن هم میتونی اطلاعات قدیمی رو حفظ کنی، بدون اینکه انبار اصلیت شلوغ و بی‌نظم بشه. خب، حالا قفسه‌دار حرفه‌ای و مرتبی شدی!

👩‍💻 #postgresql
@Code_Crafters
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍1