06 β Funksiyalar, modullik va kod tuzilishi¶
β¬ οΈ Oldingi: 05 β Nomlash β eng qiyin oson ish Β· π README Β· Keyingi: 07 β Izoh va o'z-o'zini hujjatlovchi kod β‘οΈ
Bu bobda: funksiyani qanday qilib kichik, tushunarli va bir maqsadli qilish; argumentlarni kamaytirish va yon ta'sirlarni jilovlash; takrorlanishni o'chirish bilan erta abstraksiya o'rtasidagi nozik chiziq; va bog'liq kodni bir joyga yig'ib, faylu modullarni shunday tuzishki, keyinroq "buni qayerga qo'ygandim" deb azoblanmaslik. Hammasi kod darajasida β tizim darajasidagi qarorlar uchun Dasturlash arxitekturasi kitobi bor.
Halollik / Eslatma: bu yerdagi "kichik funksiya", "uchta marta qoidasi", "3 argumentdan oshmasin" kabi raqamlar β qonun emas, mo'ljal. Ular ko'pchilik holatda foydali, lekin har doim emas. Ba'zan biroz uzunroq, lekin chiziqli o'qiladigan funksiya o'nta mayda bo'lakka bo'lingandan ko'ra ravshanroq bo'ladi. Maqsad β qoidaga bo'ysunish emas, o'qishga va o'zgartirishga qulay kod. Qoida shu maqsadga xizmat qilmasa, qoidadan voz keching.
Funksiya β bitta ishni qilsin va yaxshi qilsin¶
Eng eski va eng kuchli maslahat: bir funksiya bitta narsa qilsin, uni yaxshi qilsin va faqat shuni qilsin. Bu β funksiya darajasidagi yagona mas'uliyat (single responsibility). Diqqat: bu kod darajasidagi qoida. Arxitektura kitobidagi SOLIDning "S" harfi klass/modul darajasida gapiradi β bu yerda biz aynan funksiyaning o'ziga qaraymiz.
"Bitta ish" deganda qatorlar soni emas, bitta maqsad nazarda tutiladi. Funksiyani ko'rganingizda uni bir jumla bilan, "va", "yoki", "keyin" so'zlarisiz tasvirlay olsangiz β yaxshi belgi. "Bu funksiya buyurtmani tekshiradi va to'lovni o'tkazadi va email yuboradi" β bu uchta funksiya, bittasi ichida yashiringan.
β Oldin β hammasini qiluvchi funksiya:
function buyurtmaniBajar(savat, foydalanuvchi) {
// savatni tekshirish
if (savat.mahsulotlar.length === 0) throw new Error("Savat bo'sh");
for (const m of savat.mahsulotlar) {
if (m.miqdor <= 0) throw new Error("Noto'g'ri miqdor");
}
// narxni hisoblash
let jami = 0;
for (const m of savat.mahsulotlar) jami += m.narx * m.miqdor;
if (foydalanuvchi.premium) jami *= 0.9;
// to'lovni o'tkazish
const tolov = tolovTizimi.charge(foydalanuvchi.karta, jami);
if (!tolov.ok) throw new Error("To'lov o'tmadi");
// bazaga yozish
db.query("INSERT INTO buyurtmalar (user, jami) VALUES (?, ?)",
[foydalanuvchi.id, jami]);
// email yuborish
pochta.yubor(foydalanuvchi.email, "Buyurtmangiz qabul qilindi", jami);
}
Bu funksiya beshta turli ishni qiladi: tekshiradi, hisoblaydi, to'laydi, saqlaydi, xabar beradi. Uni test qilish uchun bazani ham, to'lov tizimini ham, pochtani ham qalbaki qilishingiz kerak. To'lov mantig'ini o'zgartirsangiz, butun funksiyani qaytadan o'qiysiz.
β Keyin β har biri bir ishni qiladi, "dirijor" boshqaradi:
function buyurtmaniBajar(savat, foydalanuvchi) {
savatniTekshir(savat);
const jami = jamiNiHisobla(savat, foydalanuvchi);
toloviniOtkaz(foydalanuvchi.karta, jami);
const buyurtma = buyurtmaniSaqla(foydalanuvchi, jami);
tasdiqXatiniYubor(foydalanuvchi.email, buyurtma);
}
Yuqori darajadagi buyurtmaniBajar endi hikoya β uni o'qib, nima sodir bo'layotganini kod ichiga kirmasdan tushunasiz. Har bir qadam alohida funksiya: kerak bo'lsa ochasiz, kerak bo'lmasa nomiga ishonasiz. Bu shunchaki "chiroyli" emas β har bir kichik funksiyani alohida test qilish, qayta ishlatish va o'zgartirish mumkin.
Kichik funksiya: nega arzon, qachon haddan oshadi¶
Kichik funksiya nima beradi? O'qiluvchanlik (qisqa narsani miyaga sig'dirish oson), nom (har bo'lakka maqsadli nom = bepul hujjat β 05-bob), testlanuvchanlik va qayta ishlatish. Lekin "kichik" o'zi maqsad emas. Funksiyani shunchaki qatorni kamaytirish uchun maydalash β masalan, bir marta ishlatiladigan ikki qatorli kodni ajratish va unga sun'iy nom o'ylab topish β ba'zan o'qishni qiyinlashtiradi: ko'zingiz fayl bo'ylab sakrab, kichik bo'laklarni qayta yig'ishga majbur bo'ladi.
Trade-off: kichik funksiyalar lokal o'qishni osonlashtiradi, lekin "sakrash narxi"ni oshiradi β mantiqni tushunish uchun ko'p faylga qarashga to'g'ri keladi. Agar bo'lak bitta joyda ishlatilsa, juda mayda bo'lsa va ajratilsa nomi mazmunni qo'shmasa β uni joyida qoldirish ravshanroq. Maydalashning o'zi fazilat emas; xizmat qilgani uchun maydalang.
Bitta abstraksiya darajasi qoidasi¶
Eng amaliy kichik qoidalardan biri: bir funksiya ichidagi barcha amallar bir xil abstraksiya balandligida bo'lsin. Yuqori darajadagi mantiq ("hisobni yarat") bilan mayda detal ("satrning har bir belgisini aylanib chiq") bir funksiyada aralashsa, o'quvchining ko'zi yuqoridan pastga sakrab charchaydi.
β Aralash daraja:
def foydalanuvchini_royxatdan_otkaz(email, parol):
email_to_gri = False # past: mayda tekshiruv
if "@" in email and "." in email.split("@")[1]:
email_to_gri = True
if not email_to_gri:
raise ValueError("Email noto'g'ri")
hisob_yarat(email, parol) # yuqori: amal
db.execute("INSERT INTO logs ...") # past: bevosita SQL
Bu funksiyada "email satrini belgilab-belgilab tekshirish" (juda past daraja) "hisob yaratish" (juda yuqori daraja) bilan yonma-yon turibdi. O'qiyotgan odam bir lahzada "biz nima qilyapmiz" (registratsiya) darajasida, keyingi qatorda "satrda nuqta bormi" darajasida o'ylashga majbur.
β Izchil bitta daraja:
def foydalanuvchini_royxatdan_otkaz(email, parol):
kiritmani_tasdiqla(email, parol)
hisob = hisobni_yarat(email, parol)
hodisani_yozib_qoy("royxat", hisob.id)
Endi har bir qator bir xil balandlikda β hammasi "amal" darajasida. Mayda detal (email satrini tekshirish, SQL yozish) o'sha amallarning ichiga tushdi. Funksiya tepadan o'qilganda toza, davomiy hikoyaga aylandi.
Argumentlar: kamroq β yaxshiroq¶
Funksiyaning argumentlari soni β uni qanchalik tushunish va test qilish kerakligini ko'rsatadi. Argument qancha ko'p bo'lsa, ularning kombinatsiyalari shuncha ko'p, demak test holatlari va xato imkoniyatlari ko'p.
| Argument soni | Baho | Izoh |
|---|---|---|
| 0 (niladic) | Eng yaxshi | Tushunish oson; ko'pincha toza |
| 1 (monadic) | Yaxshi | Tabiiy: "bunga shuni qil" |
| 2 (dyadic) | Yaxshi | Koordinata (x, y) kabi tabiiy juftlik bo'lsa |
| 3 (triadic) | Ehtiyot bo'ling | Tartibni eslab qolish qiyin; hid (smell) |
| 4+ | Qayta ko'ring | Ko'pincha yashirin obyekt: parametr obyektiga yig'ing |
3+ argument β hid. chizish(x, y, kenglik, balandlik, rang, qalinlik) β qaysi raqam nima ekanini esda tutib bo'lmaydi; chizish(10, 20, 5, 0, ...) ni o'qiganda har biriga taxmin qilasiz. Yechim β parametr obyekti: bir-biriga bog'liq argumentlarni mazmunli nom ostida bitta obyektga yig'ish.
β Tarqoq argumentlar:
function tortburchakChiz(x, y, kenglik, balandlik, rang, qalinlik) { ... }
tortburchakChiz(10, 20, 100, 50, "ko'k", 2); // har bir raqam jumboq
β Parametr obyekti:
function tortburchakChiz(joylashuv, olcham, uslub) { ... }
tortburchakChiz(
{ x: 10, y: 20 },
{ kenglik: 100, balandlik: 50 },
{ rang: "ko'k", qalinlik: 2 }
);
Endi chaqiruvning o'zi nima nima ekanini aytib turibdi.
Boolean flag argumenti β deyarli har doim yomon¶
foydalanuvchiniSaqla(user, true) β bu true nima? Flag argumenti funksiya ikki xil ish qilishini ochiq tan oladi: rost bo'lsa bir yo'l, yolg'on bo'lsa boshqa. Demak u "bitta ish" qoidasini buzayapti. Ko'pincha eng toza yechim β ikkita aniq nomli funksiya.
β xabarYubor(matn, true); Β· xabarYubor(matn, false);
β
xabarniDarhalYubor(matn); Β· xabarniNavbatgaQoy(matn);
Trade-off: flag argument har doim gunoh emas. Kutubxona API'sida konfiguratsiya bayrog'i (
{ caseSensitive: true }kabi nomlangan parametr) o'rinli β bu yerda flag xulqni sozlaydi, funksiyani ikki boshqa funksiyaga bo'lib yubormaydi. Yomoni β pozitsiontrue/falsechaqiruv joyida nimani anglatishi ko'rinmasligi.
Yon ta'sir: bashorat qilinadigan funksiya¶
Yon ta'sir (side effect) β funksiyaning qaytaradigan qiymatidan tashqari, tashqi dunyoga ta'siri: global o'zgaruvchini o'zgartirish, faylga yozish, bazaga so'rov, ekranga chop etish, kiruvchi argumentni o'zgartirish. Yon ta'sirning o'zi yomon emas β dasturlar foydali bo'lishi uchun ular kerak (fayl saqlanishi, xabar yuborilishi kerak). Yomoni β kutilmagan, yashirin yon ta'sir.
Toza funksiya (pure function) β bir xil kirishga har doim bir xil chiqish beradi va hech qanday yon ta'siri yo'q. Bunday funksiyani tushunish, test qilish va qayta ishlatish eng oson: u faqat kirishga bog'liq, "kechagi holat" yoki "tarmoq" haqida o'ylash shart emas.
β Yashirin yon ta'sir β nomi yolg'on gapiradi:
def parolni_tekshir(foydalanuvchi, parol):
if hash(parol) != foydalanuvchi.parol_hash:
foydalanuvchi.urinishlar += 1 # yashirin: obyektni o'zgartirdi
log_fayl.write("xato urinish\n") # yashirin: faylga yozdi
return False
return True
Nomi "tekshir" deydi β savol beruvchidek tuyuladi. Aslida u obyektni o'zgartiradi va faylga yozadi. Buni faqat tekshirmoqchi bo'lgan odam (masalan, testda) kutilmagan oqibatlarga duch keladi.
β Toza tekshiruv + alohida ataylab amal:
def parol_togrimi(foydalanuvchi, parol): # toza: faqat hisoblaydi
return hash(parol) == foydalanuvchi.parol_hash
def xato_urinishni_qayd_et(foydalanuvchi): # ataylab: ta'sir bor, nomidan bilinadi
foydalanuvchi.urinishlar += 1
log_fayl.write("xato urinish\n")
Endi chaqiruvchi kod tartibni o'zi tanlaydi va har bir funksiya nima qilishi nomidan ko'rinadi.
Bu bizni komanda-so'rov ajratish (Command-Query Separation, CQS) tamoyiliga olib keladi: funksiya yo so'rov bo'lsin (savol beradi, qiymat qaytaradi, hech narsani o'zgartirmaydi) yo komanda (biror narsani o'zgartiradi, odatda hech narsa qaytarmaydi) β lekin ikkalasi bir vaqtda emas. "Savol beraman, lekin yon-yog'da javobni ham o'zgartiraman" β chalkashlik manbai.
| Tur | Maqsad | Qaytaradi | Yon ta'sir | Misol |
|---|---|---|---|---|
| So'rov (query) | Ma'lumot olish | Qiymat | Yo'q | narxniHisobla(), parolTogrimi() |
| Komanda (command) | Holatni o'zgartirish | Yo'q / status | Bor | buyurtmaniSaqla(), xabarYubor() |
Trade-off: CQS toza nazariya, lekin amalda ba'zan buzasiz β masalan, navbatdan element olib, ayni paytda uni o'chiruvchi
pop()ham qaytaradi, ham o'zgartiradi. Bu shunchalik keng tarqalgan idiomki, uni buzish g'alati bo'lardi. Qoidani biling, lekin har joyda jangga kirmang β yashirin, kutilmagan yon ta'sirga qarshi turing, ochiq va keng tanilganiga emas.
Takrorlanish vs erta abstraksiya¶
Sizga DRY (Don't Repeat Yourself β o'zingni takrorlama) o'rgatilgan: bir mantiqni ko'chirib-ko'chirib yozmang, bir joyga yig'ing. To'g'ri maslahat β chunki takrorlangan kodning bir nusxasini tuzatib, ikkinchisini unutib qo'yish β klassik xato manbai. Lekin bu yerda yosh dasturchilar tez-tez to'g'noydigan tuzoq bor: erta, noto'g'ri abstraksiya takrordan ham yomon.
Ikki kod bo'lagi bugun bir xil ko'rinishi mumkin, lekin turli sabablar bilan mavjud. Ularni darhol "umumiy funksiya"ga birlashtirsangiz, ertaga biri o'zgarishi kerak bo'lganda, umumiy funksiyani if'lar va flag'lar bilan to'ldirib, oxir-oqibat ikkala holatga ham yomon xizmat qiladigan chigal narsa hosil qilasiz. Tasodifiy o'xshashlik haqiqiy umumiylik bilan adashtirilgan.
Shuning uchun amaliy "uchta marta qoidasi" (Rule of Three): biror narsani ikkinchi marta yozayotganda biroz bezovta bo'ling, lekin shoshmang. Uchinchi marta paydo bo'lganda β endi naqsh aniq, abstraksiyani ishonch bilan ajrating. Ungacha biroz takror β kechirilarli soliq.
1-marta: yoz. (hali naqsh yo'q)
2-marta: sezgir bo'l, lekin shoshmay nusxa ol. (bir xil tasodifmi yoki naqshmi?)
3-marta: endi ajrat. (naqsh tasdiqlandi)
β Erta abstraksiya β bitta funksiya ikkala xo'jayinga ham yomon xizmat qiladi:
// Foydalanuvchi va admin bildirgisi "o'xshash" bo'lgani uchun birlashtirildi...
function bildirgiYubor(odam, tur, adminMi, smsHam, jurnalga) {
// ...keyin har biri uchun if-flag chigalligi o'sadi
}
β Avval ikkita ravshan funksiya, naqsh tasdiqlangach umumiy yadro:
function foydalanuvchigaBildirgi(foydalanuvchi, hodisa) { /* aniq, sodda */ }
function adminniOgohlantir(admin, hodisa) { /* aniq, sodda */ }
// Uchinchi shunga o'xshash kerak bo'lsa -> umumiy yadroni ajrating.
Trade-off: DRY ham, "uch marta qoidasi" ham β mo'ljal. Xavfsizlik yoki to'lov mantig'i kabi kritik joyda ikki marta takror ham xavfli (bir nusxasini tuzatmay qolasiz) β u yerda birinchi takrordayoq birlashtiring. Aksincha, ikki modul mustaqil rivojlanishi kerak bo'lsa, ataylab biroz takror to'g'ri β noto'g'ri ulanishdan ko'ra. Tizim darajasidagi DRY, KISS va YAGNI tushunchalari uchun Dasturlash arxitekturasi kitobiga qarang; bu yerda gap funksiya darajasidagi takror.
Fayl va modul tuzilishi: bog'liq narsa birga¶
Funksiyalardan bir pog'ona yuqori β modul (fayl yoki papka) darajasi. Bu yerdagi asosiy tushuncha β cohesion (ichki bog'liqlik): bir modul ichidagi narsalar bir-biriga qanchalik aloqador. Yuqori cohesion β modulning hamma qismi bir maqsadga xizmat qiladi. Past cohesion β bir-biriga aloqasi yo'q narsalar tasodifan bir faylga to'planib qolgan (utils.js, helpers.py, misc.go β ko'pincha shunday "axlat qutilari").
Amaliy mezon: birga o'zgaradigan narsa birga tursin. Agar to'lov narxini o'zgartirganingizda doim to'lov tasdig'i va chek mantig'iga ham qaraysiz β bularning hammasi tolov/ modulida bo'lishi kerak, uchta turli faylga tarqalmasin. "Buni qayerga qo'yaman?" degan savolga javob β "uni kim bilan birga o'zgaradi, o'sha bilan qo'y."
β Texnik turga ko'ra sochilgan (past cohesion):
controllers/ -> foydalanuvchiController, tolovController, mahsulotController
services/ -> foydalanuvchiService, tolovService, mahsulotService
repositories/ -> foydalanuvchiRepo, tolovRepo, mahsulotRepo
Bir "to'lov" xususiyatini o'zgartirish uchun uch papkani ochasiz. To'lov haqida o'ylayotganda foydalanuvchi va mahsulot ham ko'z oldingizda turadi.
β Xususiyatga (feature) ko'ra to'plangan (yuqori cohesion):
tolov/ -> tolovController, tolovService, tolovRepo, tolov.test
foydalanuvchi/-> ...Controller, ...Service, ...Repo, ...test
mahsulot/ -> ...Controller, ...Service, ...Repo, ...test
Trade-off: "xususiyatga ko'ra papka" ko'p loyihada qulay, lekin universal qonun emas. Kichik loyihada texnik bo'linish (
controllers/,models/) ham yetarli va freymvork odatlariga mos bo'lishi mumkin β freymvork qattiq tartib tutsa, unga qarshi kurashmang. Asosiysi β papka qaror bo'lsin, tasodif emas: "bu nega shu yerda?" degan savolga javobingiz bo'lsin. Modullar orasidagi bog'liqlik (coupling) va chegaralarni qanday chizish β bu allaqachon tizim darajasi; chuqurroq Dasturlash arxitekturasi kitobida.
Halollik: bular qoida emas, yo'l-yo'riq¶
Bu bobdagi hamma narsa β "kichik funksiya", "3 argumentdan oshmasin", "toza funksiya", "uch marta qoidasi", "yuqori cohesion" β bir maqsadga xizmat qiladi: kodni keyingi odam (ko'pincha 6 oydan keyingi siz) tez tushunsin va xavfsiz o'zgartira olsin. Qoidaning o'zi maqsad emas.
Real misol: ba'zan bir funksiyani o'nta mayda bo'lakka bo'lganingizdan ko'ra, 25 qatorli, lekin yuqoridan pastga chiziqli o'qiladigan funksiya tushunarli bo'ladi β chunki butun mantiq bir ekranda, sakrash yo'q. Ba'zan biroz takror noto'g'ri abstraksiyadan afzal. Ba'zan flag argument β eng sodda yechim. Qoidani bilish β uni qachon bukish kerakligini bilish uchun. Tajribasiz dasturchi qoidani ko'r-ko'rona bajaradi; tajribali dasturchi qoidaning maqsadini biladi va shu maqsadga xizmat qilganda qo'llaydi, qilmaganda chetga suradi.
Asosiy g'oyalar (bobni qisqacha)¶
- Bir funksiya bitta ish qilsin β uni "va/keyin"siz bir jumlada tasvirlay olsangiz, yaxshi belgi. Bu kod darajasidagi yagona mas'uliyat, tizim darajasidagidan farqli.
- Bitta abstraksiya darajasi: bir funksiya ichida yuqori mantiq va mayda detalni aralashtirmang β ko'z sakrab charchaydi.
- Argument kamroq β yaxshiroq: 3+ argument hid; bog'liqlarini parametr obyektiga yig'ing; pozitsion boolean flagdan qoching (ko'pincha ikki nomli funksiya toza).
- Yon ta'sirni jilovlang: toza funksiya eng oson; yashirin ta'sirdan qoching; komanda va so'rovni ajrating (savol berasizmi yoki o'zgartirasizmi β ikkalasi birga emas).
- DRY, lekin shoshmang: uch marta qoidasi β noto'g'ri erta abstraksiya takrordan yomonroq; tasodifiy o'xshashlikni haqiqiy umumiylik bilan adashtirmang.
- Cohesion: birga o'zgaradigan narsa birga tursin;
utils/misc"axlat qutisi"dan qoching; papka tasodif emas, qaror bo'lsin. - Bular yo'l-yo'riq, dogma emas: maqsad o'qiluvchanlik va xavfsiz o'zgartirish β qoida bunga xizmat qilmasa, bukib bo'ladi.
Mashqlar¶
Oson¶
1-mashq. Quyidagi funksiya bir jumlada, "va"/"keyin" so'zlarisiz tasvirlanadimi? Tasvirlay olmasangiz, u nechta "ish" qilayotganini sanang va har biriga nom bering:
function foydalanuvchiniQayta(user) {
user.email = user.email.trim().toLowerCase();
db.save(user);
pochta.yubor(user.email, "Profil yangilandi");
console.log("yangilandi: " + user.id);
}
2-mashq. Quyidagi chaqiruvdagi har bir argument nimani anglatishini kodga qaramay ayta olasizmi? Aytolmasangiz, qanday qilib o'qiluvchanroq qilasiz?
3-mashq. Ushbu funksiya "so'rov"mi yoki "komanda"mi? Nomi nima qilishini to'g'ri aytyaptimi? Muammoni bir jumlada tasvirlang:
O'rta¶
4-mashq. Quyidagi funksiyada abstraksiya darajalari aralashgan. Mayda detalni alohida funksiyalarga ajratib, asosiy funksiyani bir xil balandlikdagi qadamlar hikoyasiga aylantiring:
def hisobotni_tayyorla(buyurtmalar):
jami = 0
for b in buyurtmalar:
for m in b.mahsulotlar:
jami += m.narx * m.miqdor
f = open("hisobot.txt", "w")
f.write("Jami: " + str(jami))
f.close()
pochta.yubor("rahbar@firma.uz", "Hisobot tayyor")
5-mashq. Sizda ikkita funksiya bor: userBildirgisiYubor va adminBildirgisiYubor. Ular 80% bir xil. Hamkasbingiz darhol ularni bitta bildirgiYubor(..., adminMi) ga birlashtirishni taklif qilyapti. Qaror qabul qilish uchun qaysi 3 savolni berasiz? "Uch marta qoidasi" bu yerda nima deydi?
6-mashq. Loyihangizda (yoki tasavvur qiling) utils.js fayli bor va unda: sanaFormatla, pulFormatla, emailTekshir, paroldHashla, massivAralashtir funksiyalari yotibdi. Bu past cohesion misoli. Ularni mazmunli modullarga qanday qayta taqsimlaysiz? Kamida 3 modul nomini taklif qiling va qaysi funksiya qayerga ketishini ayting.
Qiyin¶
7-mashq. 5-bobdagi yoki o'z loyihangizdagi 40+ qatorli, bir nechta ishni qiladigan funksiyani toping. Uni "dirijor + kichik funksiyalar" naqshiga refactor qiling (oldin/keyin kodini yozing). Keyin halol baholang: refactordan keyin kod chindan ham o'qiluvchanroq bo'ldimi, yoki shunchaki ko'p faylga sakrash paydo bo'ldimi? Qaysi ajratish o'rinli, qaysi biri haddan oshgan edi?
8-mashq. Quyidagi funksiyada yashirin yon ta'sir bor. (a) Yon ta'sirni aniqlang. (b) Uni toza "so'rov" va alohida "komanda"ga ajrating. (c) Bu refactor testlashni qanday osonlashtirishini bir-ikki jumlada izohlang:
def chegirma_hisobla(savat, foydalanuvchi):
chegirma = 0
if savat.jami > 100000:
chegirma = savat.jami * 0.1
foydalanuvchi.bonus_ishlatildi = True # ???
audit_log.append(f"chegirma: {foydalanuvchi.id}") # ???
return chegirma
Yechimlar
1-mashq yechimi¶
Bir jumlada tasvirlab bo'lmaydi β funksiya to'rt ish qiladi: (1) emailni normallashtiradi, (2) bazaga saqlaydi, (3) email yuboradi, (4) log yozadi. Nom (foydalanuvchiniQayta) noaniq va yolg'on β "qayta nima?". Ajratish: emailniNormallashtir(user), foydalanuvchiniSaqla(user), yangilanishXabariniYubor(user), hodisaniYozibQoy(user). Yuqori darajadagi foydalanuvchiniYangila(user) shu to'rttasini ketma-ket chaqirsa, hikoyaga aylanadi.
2-mashq yechimi¶
true va false β pozitsion boolean flag, kodga qaramay ma'nosi yo'q. 30 ham noaniq (yosh? muddat? chegirma?). Yaxshilash: bog'liqlarni parametr obyektiga yig'ing va flag'larni aniq nomlang β
tasdiqlanganHisobYarat(...). Asosiysi: chaqiruv joyining o'zi nimani anglatishini aytib tursin.
3-mashq yechimi¶
Bu ikkalasi β ham komanda (hisoblagich qiymatini o'zgartiradi), ham so'rov (qiymat qaytaradi). Nomi keyingi_idni_ol β "ol" so'zi sof so'rovdek tuyuladi, lekin u jimgina holatni o'zgartiradi. CQS bo'yicha bu chalkashlik manbai. Halol qarash: pop/next/generate kabi idioma funksiyalarda bu kechirimli (Trade-off blokiga qarang); lekin nomi yon ta'sirni yashirsa β masalan oddiy ol/get/hisobla β bu xavfli. Eng aniq nom: keyingiIdniGeneratsiyaQil (generatsiya = yangi narsa yaratiladi degani, holat o'zgarishini ishora qiladi).
4-mashq yechimi¶
def hisobotni_tayyorla(buyurtmalar):
jami = umumiy_jamini_hisobla(buyurtmalar) # so'rov, toza
hisobotni_faylga_yoz(jami) # komanda
rahbarni_xabardor_qil() # komanda
def umumiy_jamini_hisobla(buyurtmalar):
return sum(m.narx * m.miqdor
for b in buyurtmalar for m in b.mahsulotlar)
def hisobotni_faylga_yoz(jami):
with open("hisobot.txt", "w") as f:
f.write(f"Jami: {jami}")
def rahbarni_xabardor_qil():
pochta.yubor("rahbar@firma.uz", "Hisobot tayyor")
hisobotni_tayyorla uchta bir xil balandlikdagi qadam: hisobla -> yoz -> xabar ber. Mayda detal (ichma-ich sikl, fayl ochish/yopish) o'z funksiyalarining ichida. umumiy_jamini_hisobla toza β alohida test qilinadi.
5-mashq yechimi¶
Beriladigan savollar: (1) Ular bir xil sababga ko'ra o'zgaradimi? Agar ertaga admin bildirgisiga "majburiy o'qildi-belgisi" kerak bo'lsa-yu, foydalanuvchinikiga kerak bo'lmasa β ular mustaqil rivojlanadi, birlashtirish noto'g'ri. (2) O'xshashlik haqiqiy umumiylikmi yoki tasodifmi? Bugun 80% bir xil bo'lishi tasodif bo'lishi mumkin. (3) Birlashtirsak, qancha if/flag qo'shamiz? adminMi flagi paydo bo'ldi degani β funksiya ichi tarmoqlana boshlaydi, bu hid. "Uch marta qoidasi": hozircha faqat ikki holat bor β shoshmang. Uchinchi shunga o'xshash bildirgi paydo bo'lsa, naqsh tasdiqlanadi; o'shanda umumiy yadroni (masalan, xabarniJonat(kanal, matn)) ajratib, ikkala funksiya shuni chaqirsin β lekin flag bilan emas.
6-mashq yechimi¶
utils.js β past cohesion (axlat qutisi): funksiyalar bir-biriga aloqasiz. Mazmunli taqsimot, masalan:
- formatlash/ (yoki format.js): sanaFormatla, pulFormatla β ikkalasi ham "ko'rsatish uchun matnga aylantirish".
- tasdiqlash/ (yoki validatsiya.js): emailTekshir β kiritmani tekshirish oilasi (keyin telefon, parol kuchi shu yerga qo'shiladi).
- xavfsizlik/ (yoki kripto.js): paroldHashla β maxfiylik/kripto mantig'i.
- massivAralashtir umumiy yordamchi bo'lib qolishi mumkin (massiv.js) yoki faqat bir joyda ishlatilsa β o'sha joyga ko'chiriladi. Mezon har doim bir xil: birga o'zgaradigan va bir mavzuga tegishli narsa birga tursin.
7-mashq yechimi¶
Yagona to'g'ri javob yo'q β bu refleksiv mashq. Yaxshi yechim mezonlari: (1) oldin/keyin kodi real (sun'iy emas); (2) yuqori darajadagi funksiya endi bir xil balandlikdagi nomli qadamlardan iborat; (3) har ajratilgan funksiyaning nomi mazmun qo'shadi (shunchaki qadam1, qism2 emas). Eng muhimi β halol baho: agar refactordan keyin 6 ta fayl ochish kerak bo'lsa-yu, asl 40 qator bir ekranda chiziqli o'qilar edi, ehtimol haddan oshgansiz. To'g'ri savol: "keyingi odam buni tezroq tushunadimi?" β ha bo'lsa, refactor o'rinli; "raqamni kamaytirdim" β yetarli sabab emas.
8-mashq yechimi¶
(a) Yashirin yon ta'sir: funksiya "hisobla" deb nomlangan (so'rovdek), lekin foydalanuvchi.bonus_ishlatildi ni o'zgartiradi va audit_log ga yozadi β ikki yashirin komanda. (b) Ajratish:
def chegirma_summasi(savat): # toza so'rov
if savat.jami > 100000:
return savat.jami * 0.1
return 0
def bonusni_belgila(foydalanuvchi): # ataylab komanda
foydalanuvchi.bonus_ishlatildi = True
audit_log.append(f"chegirma: {foydalanuvchi.id}")
chegirma_summasi endi toza β turli jami qiymatlari uchun bazani, foydalanuvchi obyektini yoki audit log'ni qalbaki qilmasdan natijani tekshirasiz. Avval har bir testda yon ta'sirlarni izolatsiya qilish kerak edi; endi sof matematikani sof tekshirasiz.
β¬ οΈ Oldingi: 05 β Nomlash β eng qiyin oson ish Β· π README Β· Keyingi: 07 β Izoh va o'z-o'zini hujjatlovchi kod β‘οΈ