Advanced Topics
14 subscribers
5 files
3 links
Bu kanalda dasturlashga oid o'zim o'rganayotgan va o'rgangan bilimlarimni ulashib boraman.
Download Telegram
Channel created
#mundarija

# lar uchun Mundarija

#sources Ma'lumotlar qayerdan olingani haqida.
Advanced Topics pinned ยซ#mundarija # lar uchun Mundarija #sources Ma'lumotlar qayerdan olingani haqida.ยป
#introduction

Design Patternlar - biz ishlab chiqayotan dasturlarni loyihalashda ko'p uchraydigan muammolarni hal qilish uchun berilgan umumiy yechim hisoblanadi.

Biz patternlardan shunchaki nusxa olishimiz va dasturimizga qo'shish orqali muammoni hal qila olmaymiz. Aksincha Design Patternlar muammoga berilgan umumiy tushuncha bo'lganligi sababli biz ularni o'z dasturimizga moslashtirgan holda ish olib boramiz.

Nega ulardan foydalanishimiz kerak?

Design Patternlar - sinalgan va testlardan o'tgan yechimlar hisoblanadi. Ularni bilish orqali har qanday muammoga "Design principle" va "Object Oriented Design"lar orqali yech topa olishingiz mumkin.

Design Patternlar - siz va jamoadoshlaringiz birga ilshashlari uchun umumiy tilni belgilab beradi. Ya'ni sizga team-lead tomonidan "Singleton Design Pattern" ni ishlatish haqida topshiriq keldi va siz ushbu pattenni bilganligingiz sababli ortiqcha tushintirishlarsiz ishni davom etasi.
#type_of_patterns

Creational Design Patternlar

Obyektning yaratilish jarayonida kodni qayta ishlatilinishi va yuqori darajadagi moslashuvchanlikni taminlab beradi.

Factory
#factory

Factory Design Pattern

Ota klasslardagi (Superclass) obyektlarni yaratish uchun interface taminlaydi, ammo Bola klasslarda (Subclass) yaratilayotgan obyektlarning turini o'zgartirish imkonini beradi.

Tassavur qiling bizda quyidagi muammo mavjud:

Yuk tashuvchi Logistika kompaniyasi dasturining birinchi versiyasida faqatgina Quruqlik orqali yuk tashish hizmati mavjud. Demak bizda asosiy logika Track klasida amalga oshadi.

Vaqt o'tishi bilan kompaniya kengayadi va suv transportiga talablar ortishi natijasida ular dasturga suv transporti uchun ishlaydigan funksiya qo'shishlariga to'g'ri keladi.
Bizda deyarli hamma jarayonlar quruqlik transporti bilan bir hil. Agarda suv transport uchun ham shu logikani qayta yozib chiqsak bu juda ham ko'p vaqt oladi, aksiga olib biz logikani Track klasiga bog'lab ketganmiz.

Ya'ni muammo har gal yangi turdagi transport turi qo'shilganda boshidan bir hil logika qayta va qayta yozishga to'g'ri keladi.



Yechim

Biz Factory Design Pattern orqali muammoga yechim beramiz.

Logistics nomli parentclass boladi va uning quyidagi methodlari mavjud.

delivery() : transport turining logikasi yoziladi.
support() : ushbu klass qaysi turdagi transportlarga hizmat ko'rsatishini aniqlab beradi.

RoadLogistics va SeaLogistics klasslari Logistics dan vorislik oladi.

Product classiga esa type nomli field qo'shamiz.

Bizga kirib kelgan product typega asoslanib roadlogistics yoki sealogistics klasslaridan obyekt qaytaramiz. Va qaytagn obyektning delivery() funksiyasiga murojat qilamiz.


Agarda bizga havo transporti ham qo'shiladigan bo'lsa, biz
AirLogistics nomli klassga Logistics classdan vorislik olishimiz va Product ga AIR type qo'shishimiz orqali strukturani osongina AirLogistics klasga ko'chirib olamiz.


delivery() bu funksiyada esa har bir klassning o'zini logikasini yozamiz.
#singleton

Singleton Design Pattern - Creational Design Patterga mansub bo'lib biz yaratayotgan klassda faqatgina bitta obyekt bo'lishini taminlab beradi. Ya'ni necha marotaba klassdan obyekt olinishidan qatiy nazar klassda bitta obyekt bo'ladi va klass ichidagi resurslar faqatgina bitta obyekt tomonidan o'zgartib boriladi.

class SingletonMeta(type):
_instances = {}

def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)

return cls._instances[cls]

Singleton klass uchun meta klass yaratib olamiz.

_instances = {} klassdagi obyektlarni saqlash uchun ishlatilinadi.

agar klassdan obyekt olingan bo'lsa usha klass obyekti qaytarib yuboriladi aks holda esa _instances = {} klas set qilinadi.



class Singleton(metaclass=SingletonMeta):

def __init__(self):
self.dict_ = {}

def set_value(self, key, value):
self.dict_[key] = value

def get_value(self):
return self.dict_


Singleton klassda dict_ field mavjud bo'lib classdan necha marotaba obyekt olinishidan barcha obyektlar shu dict_ ustida ish olib boradi.


if __name__ == '__main__':
singleton = Singleton()
singleton.set_value('key', 'value')

singleton2 = Singleton()
singleton2.set_value('key', 'value2')
print(singleton2.get_value())
print(singleton.get_value())


Natija ikkala klassda ham bir hil chiqadi.
#shared_state

Singleton Design Patternning o'ziga yarasha bir nechta kamchiliklari mavjud.
1) OOP da barcha obyektlar bitta global varieable ni o'zgartirishi Best Practise emas.
2) Unit Test qilishda muammolar yuzaga kelishi, ya'ni test qilish jarayonida boshqa obyektlar tomonidan istalgan vaqtda field qiymatini o'zgartirilishi uning aniq qiymatini belgilashni qiyinlashtiradi (assertga aniq bir qiymat berish orqali tekshirish jarayonini).


Umumiy olganda iloji boricha Singleton patternni ishlatishdan qochishimiz kerak. Agar shunday bo'lsa uning o'rniga nima ishlatishimiz mumkin?

Ayni shu paytda Shared State sahnaga chiqadi. Shared stateni Singleton patternga alternativ sifatida ishlatish mumkin. Ya'ni Shared Stateda global o'zgaruvchi (field) bo'ladi lekin bir nechta instancelar yaratilishi mumkin. Singletonda esa faqatgina bitta instance bo'ladi va har safar obyektlar invoke (chaqirilganda, instance olish jarayonida) osha yagona bo'lgan instance qaytariladi.


Shared Singletonga qaraganda kam hatoliklarga moyil, test qilish oson va oldingi klasslarni yaratish imkoni mavjud.
#builder

Builder Design Pattern - murakkab obyektlarni osonlik bilan yaratish imkonini beradi. Ya'ni bizning ma'lum bir klasimizda ko'plab fieldlar bo'ladigan bo'lsa ularni hammasini bitta konstruktorga berib yuborish o'rniga navbatma-navbat kerakli fieldlarni qo'shish imkonini beradi.

Builder Design Patternni istalga dasturlash tiliga moslashtirib ishlatib ketish mumkin.

Javada build in @Builder anotatsiyasini klass ustiga qo'yish orqali bunga erishish mumkin.
#borg

Borg (Monostate) pattern Singleton va Shared Patternlarga alternativ sifatida qabul qilinilishi mumkin. Ya'ni:
 Singletonda bitta klas bitta instance orqali ma'lumotlarini ulashadi.

Shared Stateda bir nechta instancelar orqali bu ish amalga oshiriladi.

Borg Pattern da ham maqsad datani barcha instancelar o'rtasida ulashish hisoblanadi, faqat boshqacha logika bilan. Borg patternda har bir yaratilgan instance uchun klass attributelari (field) dan nusxa (replica) olib beriladi. Bunda ayrim muammolar kelib chiqishi mumkin, lekin shu holdayam Singletondan ancha foydali taraflari mavjud.
#adapter

Adapter Design Pattern - Inheritence va Compositiondan foydalangan holda turli hil, bir biriga mos kelmaydigan interfacelarni bir biriga bog'lash uchun ishlatiladi.

Misol uchun kundalik hayotda ishlatiladigan universal adapterlar (komputer zaryadlagichlari)ni ko'rish mumkin. U o'zida barcha kompyuterlar uchun mos kela oladigan umumiy shakilni hosil qiladi.

Dasturlash jihatidan misol keltiradigan bo'lsak. A nomli dastruda X va Y interfacelar bo'lib X JSON, Y esa XML formatlaridan foydalanadi. Ikki service o'zaro to'gridan to'g'ri ma'lumotlar almashina olmaydi, ayni shu paytda biz Z nomli interfaceni ularni bo'glovchilik funksiyasini bajaradigan Adapter sifatida qo'shamiz.

Sodda qilib aytadigan bo'lsak Adapter bir biriga mos kelmaydigan interfacelarni o'rtasidagi vositachi bo'ladi. Adapter Single Responseibility va Open-Closed principlelarga mos keladi.
๐Ÿ‘1
#load_balancing

Load Balancing - Foydalanuvchilar tomonidan berilayotgan so'rovlarni(requestlarni) o'zaro serverlar o'rtasida taqsimlab berish jarayoni hisonlanadi. Bu esa serverlarga so'rovlarni turli yo'llar bilan taqsimlash imkonini beradi.

Turlari

Load Balancing Statik va Dinamik turlarga ajratiladi.

Statik

Round Robin, Sticky Round Robin, Weight Round Robin va IP hash turlarga ajratiladi.
Statik Load Balancerlar sozlash(set-up) qilish juda ham oson va qulay.


Round Robin Load balancer

Kirib kelayotgan so'rovlarni serverlarga CPU, RAMning hajmini inobatga olmagan holda ketma-ket ravishda yuboradi.


#nginx
upstream backend {

server backend:8000;
server backend3:8000;
server backend2:8000;

}

server {
listen 80;
server_name 172.20.192.1;

location /api/ {
proxy_pass http://backend; # http so'rovlarni yuqoridagi backendga yuboradi
proxy_set_header Host $http_host;

}

}


Bu esa turli hil parametrlarga ega serverlar bilan load balancing qilish jarayonida ayrim muammolar keltirishi mumkin. Bu paytda bizga Weight Round Robin yordam beradi.

Weight Round Robin

upstream backend {

server backend:8000 weight=1 ;
server backend3:8000 weight=5;
server backend2:8000 weight=4;

}

weight qo'shish orqali biz so'rovlarni serverlar o'rtasida taqsimlanishini boshqarishimiz mumkin.

IP hash Load Balancing

ip_hash; qo'shish orqali amalga oshirsa bo'ladi.


Dinamik Load Balancerlar

Statik load balancerlardan farqli ravishda Dinamik Load Balancer Algoritmlari murakkabroq hisoblanadi.

Qulayliklari:

1) Serverning holatidan kelib chiqib so'rovlarni taqsimlash. Ya'ni
A Server=10
B Server=100
C Server=1000

holatida so'rovlarni A serverga yo'naltiradi va bitta serverga bosim tushishini oldini oladi

2) Least Connection va Least Time orqali so'rovlarni yo'naltirish.

Least Connection yuqoridagi holatga to'g'ri keladi. least_conn orqali amalga oshiriladi.

upstream backend {
least_conn;
server backend:8000 weight=1 ;
server backend3:8000 weight=5;
server backend2:8000 weight=4;

}

Least Time - serverlarning requestga javob berish vaqti orqali so'rovlarni taqsimlaydi (Open Source Nginxda mavjud emas, Faqat Commercial orqali amalga oshirish mumkin)