Кодын чанар
Сайн код бичихэд “анхааралтай бай” гэдэг ганцаараа хангалтгүй. Форматлагч, линтер, тест, CI зэрэг хэрэгслүүд өдөр тутмын жижиг алдааг эрт барьж, багийн кодыг нэг хэв маягтай байлгахад тусалдаг. Энэ лекцээр дараах зүйлсийг үзнэ:
Нэмээд regular expression буюу regex-ийг үзнэ. Regex кодын чанарын хэрэгслүүдэд (жишээ нь нэрээр нь шүүж тест ажиллуулах), мөн IDE-ийн хайх/солих гэх мэт өдөр тутмын ажилд их хэрэглэгддэг.
Эдгээр хэрэгслийн ихэнх нь хэл бүрд өөр нэртэй байдаг. Python дээр Ruff линтер/formatter ашиглаж болно, зарим хэрэгсэл олон хэл дэмждэг (Prettier гэх мэт). Гэхдээ суурь санаа нь бараг бүх хэл дээр адил: форматлагч, линтер, тестийн сан заавал олдоно.
Кодыг форматлах
Автомат форматлагч кодын хэлбэрийг автоматаар цэгцэлдэг. Ингэснээр хашилт ' юу
" юу, x+y юу x + y юу, import-ууд ямар дарааллаар байх вэ гэх жижиг
маргаанд цаг үрэхгүй. Форматлагчийн хамгийн том давуу тал нь багийн бүх хүний код
нэг хэв маягтай харагддагт байгаа.
Prettier зэрэг зарим хэрэгсэл их нарийн тохируулагддаг; тэр тохиргооны файлаа төслийнхөө хувилбарын хяналт-д оруулах хэрэгтэй. Харин Black, gofmt зэрэг нь өчүүхэн зүйлийн төлөөх маргааныг (bikeshedding) багасгахын тулд тохиргоог зориуд цөөн байлгадаг эсвэл огт өгдөггүй.
Форматлагчаа IDE-тэйгээ холбож тохируулбал бичиж байх зуур эсвэл файл хадгалах бүрд код автоматаар форматлагдана. Мөн төсөлдөө EditorConfig файл нэмээд файлын төрөл бүрийн догол мөрийн хэмжээ гэх мэт төслийн түвшний тохиргоог IDE-дээ хэлж өгч болно.
Линтер
Линтер кодыг ажиллуулалгүйгээр статик шинжилгээ хийж, муу хэв маяг (antipattern) болон гарч болзошгүй алдааг олдог. Эдгээр нь форматлагчаас илүү гүнзгий, гаднах хэлбэрээс цааш шалгадаг. Хэр гүнзгий шинжлэх нь хэрэгслээс хамаарна.
Линтерүүд төслийн түвшинд тохируулж болох дүрмүүд болон бэлэн дүрмийн багцуудтай ирдэг. Зарим дүрэм алдаагүй кодыг алдаатай гэж андуурах (false positive) тохиолдол гардаг тул файл эсвэл мөр бүрээр нь унтрааж болно.
Сайн линтер дүрэм бүрийнхээ тайлбар, баримт бичигтэй байдаг — дүрэм яг юуг шалгаж
байгаа, яагаад муу вэ, илүү сайн хувилбар нь юу вэ гэдгийг заадаг. Жишээ нь Python-ы
кодонд шаардлагагүй давхарласан if-ийг илрүүлдэг Ruff-ийн
SIM102 дүрмийн баримт бичгийг
үзээрэй.
Зарим линтер зөвхөн анхааруулаад зогсохгүй, тодорхой асуудлуудыг автоматаар засаж чаддаг.
Хэлний линтерээс гадна semgrep гэдэг
“утгаар хайдаг grep” хэрэг болж магадгүй. Энэ нь (grep шиг) тэмдэгтийн түвшинд биш,
AST (Abstract Syntax Tree) түвшинд ажилладаг бөгөөд олон хэл дэмждэг. Semgrep-ээр
төсөлдөө зориулсан тусгай линтерийн дүрэм амархан бичиж болно. Жишээ нь Python-ы
аюултай subprocess.Popen(..., shell=True) дуудлагыг хориглохыг хүсвэл тэр хэв
загварыг ингэж олно:
semgrep -l python -e "subprocess.Popen(..., shell=True, ...)"
Тест
Програм хангамжийн тест бол бичсэн код тань зөв ажиллаж байгаа гэдэгт итгэлтэй болох стандарт арга. Код бичээд, дараа нь тэр кодыг ажиллуулж шалгадаг өөр код бичнэ; код хүлээснээр ажиллахгүй бол тест алдаа заана.
Тестийг янз бүрийн түвшинд бичиж болно: тусдаа функцийг шалгах unit тест, модуль эсвэл үйлчилгээнүүдийн хоорондын харилцааг шалгах integration тест, хэрэглэгчийн хувилбарыг эхнээс нь дуустал шалгах функциональ тест. Кодоо бичихээсээ өмнө тестээ бичдэг тестэд суурилсан хөгжүүлэлт (test-driven development, TDD) ч хийж болно. Кодноосоо алдаа олбол ирээдүйд тэр боломж дахин эвдрэхийг барих регрессийн тест бичиж болно. Мөн Haskell-ийн QuickCheck-ээс эхтэй, Python-ы Hypothesis гэх мэт олон санд хэрэгжсэн шинж чанарт суурилсан тест (property-based test) бичиж болно. Аль арга тохирох нь төслөөс тань хамаарна; магадгүй хэдийг нь хослуулах байх.
Програм тань өгөгдлийн сан, вэб API гэх мэт гадны хамааралтай бол тестийн үед тэдэнтэй шууд харилцахын оронд хуурамч орлуулагч (mock) хэрэглэх нь тохиромжтой байж болно.
Кодын хамрах хүрээ (code coverage)
Code coverage бол тестүүд тань хэр сайн болохыг хэмжих үзүүлэлт. Тест ажиллах үед кодын аль мөрүүд ажилласныг хянаж, кодын бүх хэсгийг шалгасан эсэхийг харуулна. Coverage хэрэгслүүд мөр бүрээр тайлан гаргаж, дараа нь юунд тест бичихээ шийдэхэд тусалдаг. Codecov гэх мэт үйлчилгээ төслийн түүхийн туршид хамрах хүрээг хянах, харах вэб интерфейс өгдөг.
Бусад хэмжүүрийн адил coverage төгс биш; зөвхөн хувийг нь өсгөх гэж хөөцөлдөхийн оронд чанартай тест бичихэд анхаараарай.
Pre-commit hook
Git-ийн pre-commit hook-ыг pre-commit фреймворк ашиглахад амар болгосон. Hook нь коммит хийх бүрд таны заасан кодыг автоматаар ажиллуулдаг. Төслүүд коммит бүрийн өмнө форматлагч, линтер, заримдаа тестийг автоматаар ажиллуулж, код нэг хэв маягтай, тодорхой алдаагүй байгааг баталгаажуулахад pre-commit hook-ыг өргөн хэрэглэдэг.
Тасралтгүй интеграц (CI)
GitHub Actions гэх мэт тасралтгүй интеграцийн (continuous integration, CI) үйлчилгээ таныг код push хийх бүрд (эсвэл pull request бүр дээр, эсвэл тогтсон хуваарийн дагуу) скриптүүдийг тань ажиллуулж өгдөг. Хөгжүүлэгчид CI-г ихэвчлэн форматлагч, линтер, тест зэрэг кодын чанарын хэрэгслүүдийг ажиллуулахад хэрэглэдэг. Хөрвүүлэгддэг хэлд код хөрвөж байгааг, статик төрөлтэй хэлд төрөл зөв байгааг шалгаж болно. Шинэ коммит бүрийг push хийх бүрд CI ажиллуулбал кодын үндсэн хувилбарт орж буй алдааг барина; pull request дээр ажиллуулбал оролцогчдын илгээсэн өөрчлөлтийн асуудлыг барина; хуваарийн дагуу ажиллуулбал гадны хамаарлын асуудлыг барина (жишээ нь хөгжүүлэгч эвдэх өөрчлөлтийг санамсаргүй semver-тэй нийцтэй гэж гаргачихвал).
CI скриптүүд хөгжүүлэгчийн машинаас тусдаа ажилладаг тул удаан ажилладаг ажлуудыг тэнд хялбар ажиллуулж болно. Жишээ нь янз бүрийн үйлдлийн систем, хэлний хувилбаруудын хослол (matrix) дээр тест ажиллуулж, програм тань бүгд дээр нь зөв ажиллаж байгааг баталгаажуулж болно.
Ерөнхийдөө CI дээрх скриптүүд кодыг тань өөрчилдөггүй: хэрэгслүүдийг “засах” горимоор биш “шалгах” горимоор ажиллуулдаг, жишээ нь код форматлагдаагүй байвал алдаа заагаад зогсдог.
Репонууд README-дээ CI-ийн төлөв, кодын хамрах хүрээ гэх мэт мэдээллийг харуулсан төлөвийн тэмдэг (status badge) байршуулдаг. Жишээ нь доор Missing Semester-ийн одоогийн угсралтын (build) төлөв байна.
Манай холбоос шалгагч proof-html GitHub Action ашигладаг бөгөөд гадны вэбсайтуудын асуудлаас болж байнга алдаа заадаг. Гэсэн ч олон эвдэрсэн холбоос олж засахад тусалсан (заримдаа үсгийн алдаанаас, ихэнхдээ вэбсайтууд агуулгаа зөөхдөө чиглүүлэлт тавиагүй эсвэл бүр алга болсноос).
CI үйлчилгээ, форматлагч, линтер, тестийн сангуудын онцлогийг сурах хамгийн сайн арга
бол жишээнээс суралцах. GitHub дээрээс чанартай нээлттэй эхийн төслүүд олоод
(хэл, чиглэл, хэмжээ, хамрах хүрээгээрээ таны төсөлтэй ойр байх тусмаа сайн),
тэдгээрийн pyproject.toml, .github/workflows/, DEVELOPMENT.md болон бусад
холбогдох файлуудыг судлаарай.
Тасралтгүй deploy (continuous deployment)
Тасралтгүй deploy гэдэг нь CI-ийн дэд бүтцийг ашиглаж өөрчлөлтүүдийг бодитоор
deploy хийх явдал. Жишээ нь Missing Semester-ийн репо GitHub Pages руу тасралтгүй
deploy хийдэг тул лекцийн тэмдэглэлээ шинэчлээд git push хийх бүрд сайт автоматаар
build хийгдэж нийтлэгдэнэ. Мөн CI дээр програмын binary, үйлчилгээний Docker image
гэх мэт бусад бүтээгдэхүүнүүдийг (artifact) үүсгэж болно.
Команд ажиллуулагч
just гэх мэт команд ажиллуулагч төслийн хүрээнд
командуудыг ажиллуулахыг хялбарчилдаг. Төслийнхөө кодын чанарын дэд бүтцийг
боловсруулж байхдаа хөгжүүлэгчдээр uv run ruff check --fix шиг урт командуудыг
цээжлүүлэхийг хүсэхгүй байх. Команд ажиллуулагчаар үүнийг just lint болгоод,
хөгжүүлэгчийн ажиллуулах хэрэгтэй бусад хэрэгслүүдэд just format, just typecheck
гэх мэт товч нэр өгч болно.
Зарим хэлний төсөл эсвэл багц менежер ийм боломжийг өөртөө агуулдаг тул just
шиг хэлнээс хамааралгүй хэрэгсэл заавал хэрэггүй. Жишээ нь Node.js-ийн
npm-ийн
package.json доторх scripts хэсэг, Python-ы Hatch-ийн
pyproject.toml доторх tool.hatch.envs.*.scripts хэсэг ийм боломж олгодог.
Regular expression
Regular expression, товчоор “regex” бол тэмдэгт мөрүүдийн олонлогийг илэрхийлэх
жижиг хэл. Regex-ийн хэв загварыг командын мөрийн хэрэгсэл, IDE гэх мэт олон газарт
таарц хайхад хэрэглэдэг. Жишээ нь ag
бүх кодоос regex-ээр хайх боломжтой (жишээ нь ag "import .* as .*" Python-ы өөр
нэрээр оруулсан бүх import-ыг олно), go test
-run [regexp] сонголтоор тестүүдээ шүүж ажиллуулдаг. Мөн програмчлалын хэлнүүд
regex-ийн суурь эсвэл гадны сантай байдаг тул таарц хайх, шалгах, задлан шинжлэхэд
regex хэрэглэж болно.
Ойлгоход туслах үүднээс хэдэн жишээ авъя. Энэ лекцэд Python-ы regex синтакс хэрэглэнэ. Regex-ийн олон “аялга” (flavor) бий, ялангуяа нарийн боломжууд дээрээ бага зэрэг ялгаатай. Regex-ээ туршиж, алдааг нь олохдоо regex101 шиг онлайн хэрэгсэл ашиглаж болно.
abc— “abc”-тэй яг таарна.missing|semester— “missing” эсвэл “semester”-тэй таарна.\d{4}-\d{2}-\d{2}— “2026-01-14” гэх мэт ЖЖЖЖ-СС-ӨӨ форматтай огноотой таарна. Гэхдээ энэ нь дөрвөн цифр, зураас, хоёр цифр, зураас, хоёр цифр байгааг л шалгадаг, огноо өөрөө зөв эсэхийг шалгадаггүй тул “2026-01-99” ч таарна..+@.+— имэйл хаягтай таарна: хэдэн тэмдэгт, “@”, дахиад хэдэн тэмдэгт. Энэ бол хамгийн энгийн шалгалт, “nonsense@@@email” шиг мөр ч таарна. Имэйл хаягийг ямар ч алдаагүй шалгадаг regex байдаг ч бодит амьдралд хэрэглэхэд хэтэрхий нүсэр.
Regex-ийн синтакс
Regex-ийн синтаксын бүрэн тайлбарыг энэ баримт бичгээс (эсвэл бусад онлайн материалаас) харж болно. Үндсэн бүрэлдэхүүнүүд:
abcтусгай утгагүй тэмдэгтүүд бол тухайн мөртэй яг таарна (энд “abc”).дурын нэг тэмдэгттэй таарна[abc]хаалтан доторх тэмдэгтүүдийн аль нэгтэй таарна (“a”, “b”, эсвэл “c”)[^abc]хаалтан дотор байхгүй дурын тэмдэгттэй таарна (жишээ нь “d”)[a-f]мужид багтах дурын тэмдэгттэй таарна (жишээ нь “c”, гэхдээ “q” биш)a|bаль нэг хэв загвартай таарна (жишээ нь “a” эсвэл “b”)\dдурын цифртэй таарна (жишээ нь “3”)\wүгийн тэмдэгттэй таарна (жишээ нь “x”)\bүгийн хил-тэй (word boundary) таарна (жишээ нь “missing semester”-д “m”-ийн өмнө, “g”-ийн дараа, “s”-ийн өмнө, “r”-ийн дараа)(...)хэв загварыг бүлэг болгоно...?хэв загвар 0 эсвэл 1 удаа орохтой таарна, жишээ ньwords?нь “word” эсвэл “words”-тэй таарна...*хэдэн ч удаа орохтой таарна, жишээ нь.*дурын тэмдэгтүүдийн дурын урттай мөртэй таарна...+1 буюу түүнээс олон удаа орохтой таарна, жишээ нь\d+дор хаяж нэг цифртэй таарна...{N}яг N удаа давтагдахтай таарна, жишээ нь\d{4}4 оронтой тоотой таарна\.жинхэнэ “.”-тэй таарна\\жинхэнэ “\“-тэй таарна^мөрийн эхлэлтэй таарна$мөрийн төгсгөлтэй таарна
Бүлэг барих ба буцааж дуудах
Regex-д (...) бүлэг хэрэглэвэл таарцын тэр хэсгийг тусад нь авах, эсвэл
хайж солихдоо ашиглаж болно. Жишээ нь ЖЖЖЖ-СС-ӨӨ огнооноос зөвхөн сарыг авахдаа
Python-д:
>>> import re
>>> re.match(r"\d{4}-(\d{2})-\d{2}", "2026-01-14").group(1)
'01'
Засварлагч дээрээ хайж солихдоо барьсан бүлгүүдээ буцааж дуудаж болно. Синтакс нь
IDE бүрд өөр: жишээ нь VS Code-д $1, $2, Vim-д \1, \2 гэж бичдэг.
Хязгаарлалт
Регуляр хэлнүүд хүчтэй ч хязгаартай; стандарт regex-ээр илэрхийлж чадахгүй тэмдэгт мөрийн ангиуд бий (жишээ нь {a^n b^n | n ≥ 0}, өөрөөр хэлбэл хэдэн “a”-ийн араас яг тийм тооны “b” орсон мөрүүдийн олонлогтой таарах regex бичих боломжгүй; практик жишээ гэвэл HTML регуляр хэл биш). Бодит байдал дээр орчин үеийн regex-ийн хөдөлгүүрүүд lookahead, backreference гэх мэт регуляр хэлнээс давсан боломж дэмждэг, эдгээр нь их хэрэгтэй, гэхдээ илэрхийлэх чадвар нь хязгаартай хэвээр гэдгийг мэдэж байх нь чухал. Илүү нарийн хэлийг задлан шинжлэхэд илүү чадвартай parser хэрэг болно (нэг жишээ нь PEG parser болох pyparsing).
Regex сурах нь
Энэ хэлний бүх юмыг цээжлэх гэж зүтгэх хэрэггүй. Үндсэн ойлголтуудыг (энэ лекцээр үзсэн зүйлс) аваад, хэрэг гарах бүрд баримт бичгээ харж байхад хангалттай.
AI-тай ярилцдаг хэрэгслүүд regex бичихэд их тустай. Жишээ нь дуртай LLM-дээ ийм промпт өгөөд үзээрэй:
Write a Python-style regex pattern that matches the requested path from log lines from Nginx. Here is an example log line:
169.254.1.1 - - [09/Jan/2026:21:28:51 +0000] "GET /feed.xml HTTP/2.0" 200 2995 "-" "python-requests/2.32.3"
Дасгал ажил
-
Ажиллаж буй төсөлдөө форматлагч, линтер, pre-commit hook тохируулаарай. Олон алдаа гарвал: форматын алдааг автомат форматлагч засна. Линтерийн алдааг засахдаа AI агент ашиглаад үзээрэй. Агент линтерийг өөрөө ажиллуулж, үр дүнг нь харж, алдаа бүгд засагдтал давтан ажиллаж чадахаар тохируулаарай. AI кодыг тань эвдээгүй эсэхийг сайтар шалгаарай!
-
Мэддэг хэлнийхээ тестийн сантай танилцаад, ажиллаж буй төсөлдөө unit тест бичээрэй. Coverage хэрэгсэл ажиллуулж HTML тайлан гаргаад үзээрэй. Кодын аль мөрүүд хамрагдсаныг харж чадаж байна уу? Хамрах хүрээ тань магадгүй маш бага байх. Хэдэн тест гараараа бичиж сайжруулаад үзээрэй. Дараа нь AI агент-аар хамрах хүрээг (coverage) сайжруулаарай; агент тестүүдийг хамрах хүрээний хэмжилттэй нь ажиллуулж, мөр бүрийн тайлан гаргаж чадаж байгааг шалгаарай, ингэвэл хаана анхаарахаа мэднэ. AI-ийн бичсэн тестүүд үнэхээр сайн байна уу?
-
Ажиллаж буй төсөлдөө push хийх бүрд ажилладаг CI тохируулаарай. CI-д форматын шалгалт, линтер, тестүүдийг ажиллуулаарай. Кодоо зориуд эвдээд (жишээ нь линтерийн дүрэм зөрчсөн код нэмээд) CI үүнийг барьж байгааг шалгаарай.
-
Regex бичээд, командын мөрийн хэрэгсэл болох
grep-ээр кодоосооsubprocess.Popen(..., shell=True)дуудлагуудыг олоорой. Одоо regex-ээ “эвдэх” гээд үзээрэй. Grep-ийг тань хуурч чадсан аюултай кодыг semgrep олж чадсаар байна уу? -
Энэ лекцийн тэмдэглэл доторх
-Markdown жагсаалтын тэмдэгтийг*-оор солиж, IDE эсвэл засварлагч дээрээ regex-ээр хайж солихыг дадлагажуулаарай. Файл доторх бүх “-“-ийг шууд солих нь буруу гэдгийг анхаараарай: тэр тэмдэгт жагсаалтын тэмдэгтээс өөр олон газар хэрэглэгдсэн. -
{"name": "Alyssa P. Hacker", "college": "MIT"}хэлбэрийн JSON-оос нэрийг (энэ жишээндAlyssa P. Hacker) барьж авах regex бичээрэй. Сэжүүр: эхний оролдлогоорAlyssa P. Hacker", "college": "MIT-ийг сугалдаг regex бичиж магадгүй; яаж засахыг мэдэхийн тулд Python-ы regex баримт бичиг-ээс шуналтай (greedy) тоологчийн тухай уншаарай.- Нэр нь өөрөө
"агуулсан байсан ч (JSON-д давхар хашилтыг\"гэж бичдэг) ажилладаг болгож засаарай. - Бодит амьдрал дээр нарийн задлан шинжлэх ажилд regex хэрэглэхийг бид
зөвлөдөггүй. Хэрэглэдэг хэлнийхээ JSON задлагчийг яаж хэрэглэхийг олж
мэдээрэй. Стандарт оролтоос дээрх хэлбэрийн JSON аваад, нэрийг нь стандарт
гаралт руу хэвлэдэг командын мөрийн програм бичээрэй. Хэдхэн мөр л хэрэгтэй.
Python-д
import json-оос гадна ганцхан мөр кодоор хийж болно.
- Нэр нь өөрөө
Лиценз: CC BY-NC-SA.