Design Patterns niyə lazımdır?
Design patterns daimi baş verən problemlərə tapılmış və uzun müddətdir istifadə olunan həll yollarının toplusudur. Təsəvvür edin ki, paltaryuyan almısınız və kitabçasında paltarın materialına görə hansı modda yumalı olduğunuz yazılıb. Design Patterns, proqramlaşdırmanın həmin kitabçasıdır.
Bu məqalədə Design Patternləri öyrətmə məqsədi yoxdur. Factory method adlanan Design Patterndən istifadə edərək real praktikada olan prosesi, problemi və həllini izah etmək istəyirəm.
Yeni bir layihəyə başlamısız və ilk proyekt fərqli fayl tiplərini oxuyan bir proqram yazmaqdır. Ilkin olaraq .csv, .xlsx, .json
tipində faylları oxumaq lazımdır.
class Reader {
type: string;
constructor(type: string) {
this.type = type;
}
public read(file: string): void {
if (this.type === 'csv') {
console.log(`Reading CSV file ${file}`);
} else if (this.type === 'excel') {
console.log(`Reading Excel file ${file}`);
} else if (this.type === 'json') {
console.log(`Reading JSON file ${file}`);
} else {
throw new Error(`Unsupported file type: ${this.type}`);
}
}
}
const csvReader = new Reader('csv');
csvReader.read('...csv file');
const excelReader = new Reader('excel');
excelReader.read('...excel file');
const jsonReader = new Reader('json');
jsonReader.read('... json file');
Bu kodun qısa məntiqi necədir? Reader adlı bir sinifiniz var, hər bir fayl tipinə uyğun bu sinifdən yeni bir obyekt yaradırsınız və .read()
metodunu çağırırsız. Səliqəli, rahat, anlaşılan.
Bu kodu yazdınız, merge request yaratdınız və xoş sözlər və MR birləşdirildi bildirişini gözləyirsiniz. Əvəzində isə Senior Developer sizin MR-i bəyənmədi və sizə link göndərdi. Linki açdıqda qarşınıza Gang of Four — Design Patterns kitabının satın alınma səhifəsi çıxdı. Problem nə ilə əlaqəli ola bilər?
- Əla kod yazmısınız və Senior sizi qısqanır.
- Senior Developer sizdən daha təcrübəlidir və bu kodun gələcəkdə yaradacağı problemləri bilir.
Ümid edək ki, ikinci ehtimalla getdiniz və kitabı satın aldınız. Oxuyub heç nə başa düşmürsüz və Factory Method hissəsinə gəldiniz. Qaçdığınz ChatGPT-yə, ondan Factory Method istifadə edərək bu proqramın strukturunu sizin üçün qurmasını istədiniz. Nəticədə belə birşey var.
interface Reader {
read(file: string): void;
}
class CSVReader implements Reader {
public read(file: string): void {
console.log(`Reading CSV file ${file}`);
}
}
class ExcelReader implements Reader {
public read(file: string): void {
console.log(`Reading Excel file ${file}`);
}
}
class JSONReader implements Reader {
public read(file: string): void {
console.log(`Reading JSON file ${file}`);
}
}
class ReaderFactory {
public static createReader(fileType: string): Reader {
if (fileType === 'csv') {
return new CSVReader();
} else if (fileType === 'excel') {
return new ExcelReader();
} else if (fileType === 'json') {
return new JSONReader();
} else {
throw new Error(`Unsupported file type: ${fileType}`);
}
}
}
const fileType = 'csv';
const reader = ReaderFactory.createReader(fileType);
reader.read(fileType);
Bu kod nədir belə?
- Ümumi bir interfeys var və burada bütün oxuyucuların ortaq metodlarını göstərirsiniz.
- Hər bir fayl tipinə uyğun yeni sinif yaradıb eyni adlı metodu yazırsınız.
- ReaderFactory adlanan yeni bir sinif yaradıb xüsusi metod əlavə edirsiniz. Bu metodun işi parametr olaraq qəbul edilən fayl tipinə uyğun yeni bir oxuyucu obyekti yaradıb sizə qaytarmaqdır.
Bu qarışıqlığa nə ehtiyac var? Nəysə.
Bu kodla yenidən MR yaratdınız və eyni reaksiyanı alacağınızı düşünərək ümidsiz formada gözləyirsiniz. Nəticə? Senior Developer işinizi bəyəndi, Docstrings tövsiyyələrinə əməl etdikdən sonra kodu merge edəcəyini bildirdi. Binqo.
Yenə də ağıllarda sual var. İki kod arasında fərq nə idi? Siz hansı görünməz problemi həll etdiniz?
- Siz cari kodda heç bir problemi həll etmədiniz. İki kod da texniki olaraq eyni işi görür, hətta birinci kod daha az sətr tutur.
- Siz gələcəkdə yarana biləcək problemləri Design Patterns istifadə edərək kortəbii formada qabaqladınız.
İstər junior istər senior developerlərin öncədən görə bilmədiyi problemlər ola bilər. Bəzən bu problemlər daha sonra ciddi infrastruktur problemlərinə səbəb olur. Bu tip bəd hadisələrin qarşısını almaq üçün, sınaqdan keçmiş və daimi istifadə olunan kod nümunələri Design Patterns adı altında birləşir.
Məsələn, ilk yazdığınız kod hansı problemlərə səbəb ola bilər?
İlk yazılan kod, Open / Closed prinsipini pozur (Solid prinsipləri)
Problem: read()
metodunuz var və bunun daxilində şərtdən aslı olaraq müxtəlif fayl tiplərini oxuyursunuz. Gələcəkdə .yaml
tipli faylları oxumaq lazım olsa nə olacaq? Bu metoda düzəliş etmək məcburiyyətində qalacaqsınız. 5 il sonra 50 fayl tipi olduqda bu kod həm oxunaqlığını itirəcək, həm idarəsi çətinləşəcək həm də bir müddət sonra bu kodu oxusanız özünüz də başa düşməyəcəksiniz (inanın ki, başınıza gələ bilər).
Həll: İkinci kod blokunu istifadə etməklə obyekt yaratma mərhələsini hər bir sinifdən kənarda saxlayırsınız. Fərqli fayl tiplərinin öz sinifi var, bir-birlərinə qarışmırlar. Gələcəkdə yeni fayl formatı əlavə etmək lazım olarsa onun sinifini yaradacaqsınız (Reader sinifi hansı təməl metodları əlavə etməli olduğunuzda sizə kömək edəcək) və "fabrik" sinifinə həmin tipi əlavə edəcəksiniz.
Yeni başlayan biri olaraq, yaranacaq problemləri əvvəlcədən görməniz mümkün deyil. Nəzərə almaq lazımdır ki, bəzən Senior Developerlər belə çox ciddi xətalara yol verə bilir. Yeni başlayan developerlər olaraq etməli olduğunuz.
- İlkin prinsipləri düzgün öyrənmək. (Solid, DRY, KISS, YAGNI, etc.)
- Design Patternsi oxumaq, çoxlu kod nümunələrinə baxmaq. (Təsəvvür edin ki, hamburger yaradırsız kimi yox, real kod nümunələri tapın)
- Prinsiplərə əməl edərək Design Patternsi gündəlik işinizdə istifadə etmək.
Unutmayın ki, bir Design Patterni bütün koda tətbiq ediləcək kimi birşey mümkün deyil. Hər bir biznes məntiqinin öz tələbləri var və həmin tələblərə əsasən optimal kod yazılır. Bu bəzən ən uyğun Design Patterni tapmaqla, bəzən isə bir neçə Design Patterni birlikdə tətbiq etməklə alınır.