JavaRush /Java блогу /Random-KY /Код жазуу эрежелери: системаны түзүүдөн объекттер менен и...
Константин
Деңгээл

Код жазуу эрежелери: системаны түзүүдөн объекттер менен иштөөгө чейин

Группада жарыяланган
Баарыңарга кутман кеч: бүгүн мен сиз менен codeду туура жазуу жөнүндө сүйлөшкүм келет. Мен программалоону жаңы баштаганда, сен минтип жаз деп эч жерде так жазылган эмес, эгер минтип жазсаң, мен сени табам жана.... Ошондон улам менин башымда бир топ суроолор пайда болду: кантип туура жазуу керек, программанын тигил же бул бөлүмүндө кандай принциптерди сактоо керек ж.б.у.с. Код жазуу эрежелери: системаны түзүүдөн an objectтер менен иштөөгө чейин - 1Ооба, ар бир адам дароо эле Таза Кодекс сыяктуу китептерге киргиси келбейт, анткени аларда көп нерсе жазылган, бирок адегенде анча-мынча түшүнүктүү. Жана сиз окуп бүтүргөнгө чейин, сиз codeдоо каалоосун токтото аласыз. Ошентип, жогоруда айтылгандардын негизинде, бүгүн мен сизге жогорку деңгээлдеги codeду жазуу боюнча чакан колдонмону (кичинекей сунуштардын топтомун) бергим келет. Бул макалада биз системаны түзүүгө жана интерфейстер, класстар жана an objectтер менен иштөөгө тиешелүү негизги эрежелерди жана түшүнүктөрдү карап чыгабыз. Бул материалды окуу сизден көп убакытты талап кылbyte жана зеригүүңүзгө жол бербейт деп ишенем. Мен жогорудан ылдыйга, башкача айтканда, арыздын жалпы структурасынан конкреттүү деталдарга чейин барам. Код жазуу эрежелери: системаны түзүүдөн an objectтер менен иштөөгө чейин - 2

Система

Системанын жалпы керектүү мүнөздөмөлөрү болуп төмөнкүлөр саналат:
  • минималдуу татаалдык - өтө татаал долбоорлордон качуу керек. Негизгиси жөнөкөйлүк жана айкындык (эң жакшы = жөнөкөй);
  • тейлөөнүн жөнөкөйлүгү - тиркемени түзүп жатканда, аны колдоо керек экенин эстен чыгарбоо керек (ал сиз болбосоңуз да), андыктан code так жана айкын болушу керек;
  • начар бириктирүү - программанын ар кандай бөлүктөрүнүн ортосундагы байланыштардын минималдуу саны (OOP принциптерин максималдуу пайдалануу);
  • көп жолу колдонууга жөндөмдүүлүк - анын фрагменттерин башка колдонмолордо кайра колдонуу мүмкүнчүлүгү бар системаны долбоорлоо;
  • портативдик - система башка чөйрөгө оңой ылайыкталышы керек;
  • бирдиктүү стиль - системаны ар кандай фрагменттерде бирдиктүү стилде долбоорлоо;
  • кеңейүү (масштабдуулук) - системаны анын негизги түзүмүн бузбастан жакшыртуу (эгер сиз фрагментти кошсоңуз же өзгөртсөңүз, бул калгандарына таасирин тийгизбеши керек).
Функцияларды кошпостон, өзгөртүүнү талап кылбаган тиркемени түзүү дээрлик мүмкүн эмес. Биздин бала заманга шайкеш келиши үчүн биз дайыма жаңы элементтерди киргизишибиз керек болот. Бул жерде масштабдуулук ойнойт . Масштабдуулук - бул колдонмону кеңейтүү, жаңы функцияларды кошуу, көбүрөөк ресурстар менен иштөө (же башкача айтканда, көбүрөөк жүктөө менен). Башкача айтканда, кээ бир эрежелерди карманышыбыз керек, мисалы, модулдукту жогорулатуу аркылуу системанын кошулушун азайтуу, жаңы логиканы кошуу оңой.

Системаны долбоорлоо этаптары

  1. Программалык камсыздоо системасы - жалпы формадагы тиркемени долбоорлоо.
  2. Чакан системаларга/пакеттерге бөлүү - логикалык жактан бөлүнүүчү бөлүктөрүн аныктоо жана алардын ортосундагы өз ара аракеттенүү эрежелерин аныктоо.
  3. Кичи системаларды класстарга бөлүү - системанын бөлүктөрүн белгилүү класстарга жана интерфейстерге бөлүү, ошондой эле алардын ортосундагы өз ара аракеттенүүнү аныктоо.
  4. Класстарды методдорго бөлүү – бул класстын тапшырмасынын негизинде класска керектүү методдордун толук аныктамасы. Методду долбоорлоо - айрым методдордун функционалдуулугун деталдуу аныктоо.
Эреже катары, жөнөкөй иштеп чыгуучулар дизайн үчүн жооптуу, ал эми колдонмо архитектору жогоруда сүрөттөлгөн нерселер үчүн жооп берет.

Системаны долбоорлоонун негизги принциптери жана концепциялары

Жалкоо инициализация идиома Колдонмо an objectти колдонууга чейин убакытты коротпойт, бул инициализациялоо процессин тездетет жана таштанды жыйгычтын жүгүн азайтат. Бирок сиз муну менен өтө эле алыс барбашыңыз керек, анткени бул модулдуктун бузулушуна алып келиши мүмкүн. Дизайндын бардык кадамдарын белгилүү бир бөлүккө, мисалы, негизгиге же фабрика сыяктуу иштеген класска жылдыруу арзырлык болушу мүмкүн . Жакшы codeдун аспектилеринин бири - тез-тез кайталануучу codeдун жоктугу. Эреже катары, мындай code өз убагында чакырылышы үчүн өзүнчө класска жайгаштырылат. AOP Өзүнчө, мен аспектке багытталган программалоону белгилегим келет . Бул учу-кыйырына логиканы киргизүү аркылуу программалоо, башкача айтканда, кайталануучу code класстарга - аспектилерге киргизилет жана белгилүү бир шарттарга жеткенде чакырылат. Мисалы, белгилүү бир аталыштагы ыкмага же белгилүү бир түрдөгү өзгөрмөгө жеткенде. Кээде аспекттери чаташтырышы мүмкүн, анткени codeдун кайдан чакырылганы дароо эле түшүнүксүз, бирок ошентсе да, бул абдан пайдалуу функция. Атап айтканда, кэштөөдө же журналга жазууда: биз бул функцияны кадимки класстарга кошумча логиканы кошпостон кошобуз. Сиз бул жерде OAP жөнүндө көбүрөөк окуй аласыз . Кент Бек боюнча жөнөкөй архитектураны долбоорлоонун 4 эрежеси
  1. Экспрессивдүүлүк – класстын так айтылган максатына болгон муктаждык туура ат коюу, кичине өлчөмдө жана бирдиктүү жоопкерчorк принцибин сактоо аркылуу ишке ашат (төмөндө аны кененирээк карап чыгабыз).
  2. Минималдуу класстар жана методдор - класстарды мүмкүн болушунча кичине жана бир багыттуу кылып бөлүүнү кааласаңыз, сиз өтө эле алыс кете аласыз (антиптерн - ок атуу). Бул принцип системаны компакттуу сактоого жана өтө алыска барбоого, ар бир чүчкүрүү үчүн класс түзүүгө чакырат.
  3. Кайталануунун жоктугу - чаташтырган кошумча code системанын начар дизайнынын белгиси жана өзүнчө жерге жылдырылат.
  4. Бардык тесттердин аткарылышы - бардык сыноолордон өткөн система көзөмөлдөнөт, анткени ар кандай өзгөртүү тесттердин иштебей калышына алып келиши мүмкүн, ал бизге методдун ички логикасынын өзгөрүшү күтүлгөн жүрүм-турумдун өзгөрүшүнө алып келгенин көрсөтө алат. .
SOLID Системаны долбоорлоодо SOLIDдин белгилүү принциптерин эске алуу зарыл: S - бирдиктүү жоопкерчorк - бирдиктүү жоопкерчorк принциби; О - ачык-жабык - ачыктык/жакындык принциби; Л - Лисков алмаштыруу - Барбара Лисковдун алмаштыруу принциби; I - интерфейсти бөлүү - интерфейсти бөлүү принциби; D - көз карандылыктын инversionсы - көз карандылыктын инversionсынын принциби; Биз ар бир принципке өзгөчө токтолбойбуз (бул макаланын алкагынан бир аз алыс, бирок сиз бул жерден көбүрөөк биле аласыз

Интерфейс

Мүмкүн, адекваттуу классты түзүүнүн эң маанилүү этаптарынын бири класстын ишке ашыруу деталдарын жашырган жакшы абстракцияны билдире турган адекваттуу интерфейсти түзүү жана ошол эле учурда бири-бирине так шайкеш келген методдордун тобун көрсөтөт. . Келгиле, SOLID принциптеринин бирин кененирээк карап чыгалы - интерфейсти бөлүү : кардарлар (класстар) алар колдонбогон керексиз ыкмаларды ишке ашырбашы керек. Башкача айтканда, эгерде бул интерфейстин бирден-бир тапшырмасын аткарууга багытталган минималдуу ыкмалар менен интерфейстерди куруу жөнүндө сөз кылсак (мен үчүн, бул жалгыз жоопкерчorкке абдан окшош ), анда бир нече кичирээктерди түзүү жакшы. бир толгон интерфейстин ордуна. Бактыга жараша, класс мурастоодогудай эле бирден ашык интерфейсти ишке ашыра алат. Интерфейстердин туура аталышын да эстен чыгарбоо керек: аталыш анын милдетин мүмкүн болушунча так чагылдырышы керек. Анан, албетте, канчалык кыска болсо, башаламандык ошончолук азыраак болот. Документке комментарийлер адатта интерфейстин деңгээлинде жазылат , бул, өз кезегинде, метод эмне кылышы керек, кандай аргументтерди талап кылат жана ал эмнени кайтарарын деталдуу сүрөттөп берүүгө жардам берет.

Класс

Код жазуу эрежелери: системаны түзүүдөн an objectтер менен иштөөгө чейин - 3Сабактардын ички уюштурулушун карап көрөлү. Тагыраак айтканда, класстарды курууда карманууга тийиш болгон кээ бир көз караштар жана эрежелер. Адатта, класс белгилүү бир тартипте жайгаштырылган өзгөрмөлөрдүн тизмеси менен башталышы керек:
  1. коомдук статикалык константалар;
  2. жеке статикалык константалар;
  3. жеке инстанция өзгөрмөлөрү.
Андан ары аргументтердин азыраактан көбүрөөк аргументтерине карай ар кандай конструкторлор. Алардан кийин ачык жеткorктүүлүктөн эң жабык ыкмаларга чейинки ыкмалар келет: эреже катары, биз чектөөнү каалаган кээ бир функцияларды ишке ашырууну жашырган жеке ыкмалар эң түбүндө.

Класстын өлчөмү

Эми мен класстын көлөмү жөнүндө айткым келет. Келгиле, SOLID - бирдиктүү жоопкерчorкКод жазуу эрежелери: системаны түзүүдөн an objectтер менен иштөөгө чейин - 4 принциптеринин бирин эстейли . Бирдиктүү жоопкерчorк – бирдиктүү жоопкерчorк принциби. Анда ар бир an objectтин бир гана максаты (жоопкерчorги) бар жана анын бардык ыкмаларынын логикасы аны камсыз кылууга багытталганы айтылат. Башкача айтканда, ушуга таянып, биз чоң класстардан (өз табияты боюнча антипаттерн – “кудай an objectиси”) качышыбыз керек жана класста ар түрдүү, гетерогендик логиканын ыкмалары көп болсо, ойлонушубуз керек. аны бир нече логикалык бөлүктөргө (класстарга) бөлүү жөнүндө. Бул, өз кезегинде, codeдун окулушун жакшыртат, анткени биз берилген класстын болжолдуу максатын билсек, методдун максатын түшүнүүгө көп убакыттын кереги жок. Сиз ошондой эле класстын аталышына көз салышыңыз керек : ал камтылган логиканы чагылдырышы керек. Айталы, эгер бизде аты 20+ сөздөн турган класс болсо, рефакторинг жөнүндө ойлонушубуз керек. Ар бир өзүн-өзү сыйлаган класста мынчалык көп ички өзгөрмөлөр болбошу керек. Чынында, ар бир метод алардын бири же бир нечеси менен иштейт, бул класстын ичинде көбүрөөк кошулууга алып келет (бул так ошондой болушу керек, анткени класс бир бүтүн болушу керек). Жыйынтыгында класстын ырааттуулугун жогорулатуу анын азайышына алып келет жана, албетте, биздин класстардын саны көбөйөт. Кээ бирөөлөр үчүн бул тажатма болуп саналат; алар белгилүү бир чоң тапшырма кандай иштээрин көрүү үчүн класска көбүрөөк барышы керек. Башка нерселердин арасында, ар бир класс башкалар менен минималдуу туташкан болушу керек кичинекей модулу. Бул обочолонуу класска кошумча логиканы кошкондо биз киргизе турган өзгөртүүлөрдүн санын азайтат.

Объекттер

Код жазуу эрежелери: системаны түзүүдөн an objectтер менен иштөөгө чейин - 5

Инкапсуляция

Бул жерде биз биринчи кезекте OOP принциптеринин бири - инкапсуляция жөнүндө сүйлөшөбүз . Ошентип, ишке ашырууну жашыруу өзгөрмөлөр арасында метод катмарын түзүүгө туура келбейт (бир гана методдор, гетер жана сетерлер аркылуу кирүүнү ойлонбой чектөө, бул жакшы эмес, анткени бүтүндөй инкапсуляция пункту жоголот). Жашыруу мүмкүнчүлүгү абстракцияларды түзүүгө багытталган, башкача айтканда, класс жалпы конкреттүү ыкмаларды берет, алар аркылуу биз маалыматтарыбыз менен иштейбиз. Бирок колдонуучу бул маалыматтар менен кантип иштээрин так бorши керек эмес - ал иштейт жана бул жакшы.

Деметр мыйзамы

Деметер мыйзамын да карап көрсөңүз болот: бул класстын жана методдун деңгээлиндеги татаалдыкты башкарууга жардам берген кичинекей эрежелер топтому. Ошентип, бизде an object бар Carжана анын методу бар деп коёлу move(Object arg1, Object arg2). Demeter мыйзамына ылайык, бул ыкма чакыруу менен гана чектелет:
  • an objectинин өзүнүн ыкмалары Car(башкача айтканда, бул);
  • жылы түзүлгөн an objectтердин ыкмалары move;
  • аргумент катары өткөн an objectтердин ыкмалары - arg1, arg2;
  • ички an objectтердин ыкмалары Car(ошол эле бул).
Башка сөз менен айтканда, Деметер мыйзамы балдардын эрежеси сыяктуу бир нерсе - достор менен сүйлөшсө болот, бирок бейтааныш адамдар менен эмес .

Берorштер структурасы

Берorштер структурасы - бул байланышкан элементтердин жыйындысы. Объектти маалымат структурасы катары кароодо бул ыкмалар менен иштетилген маалыматтар элементтеринин жыйындысы, алардын бар экендиги кыйыр түрдө көрсөтүлөт. Башкача айтканда, бул an object, анын максаты сакталган маалыматтарды сактоо жана иштетүү (иштетүү). Кадимки an objectтен негизги айырмачылык an object бул бар экендиги болжолдонгон маалымат элементтеринде иштеген методдордун жыйындысы. Түшүнүп жатасыңбы? Кадимки an objectте негизги аспект методдор болуп саналат, ал эми ички өзгөрмөлөр алардын туура иштешине багытталган, бирок маалымат структурасында бул тескерисинче: методдор бул жерде негизги болгон сакталган элементтер менен иштөөнү колдойт жана жардам берет. Берorштер структурасынын бир түрү Маалыматтарды өткөрүү an objectиси (DTO) . Бул жалпы өзгөрмөлүү класс жана маалымат базалары менен иштөөдө маалыматтарды өткөрүүчү, розеткалардан талдоо билдирүүлөр менен иштөөдө ж.б. методдору жок (же окуу/жазуу ыкмаларын гана аткарат). Адатта, мындай an objectтердеги маалыматтар узак убакытка сакталbyte жана дээрлик дароо биздин колдонмо иштеген an objectке айландырылат. Объект, өз кезегинде, маалымат структурасы болуп саналат, бирок анын максаты - тиркеменин ар кандай деңгээлдеринде бизнес логикасына катышуу, ал эми DTO - тиркемеден/тиркемеден маалыматтарды ташуу. Мисал DTO:
@Setter
@Getter
@NoArgsConstructor
public class UserDto {
    private long id;
    private String firstName;
    private String lastName;
    private String email;
    private String password;
}
Баары ачык көрүнөт, бирок бул жерде биз гибриддердин бар экендиги жөнүндө билебиз. Гибриддер - маанилүү логиканы иштетүү жана ички элементтерди жана аларга жетүү ыкмаларын (алуу/коюу) сактоо ыкмаларын камтыган an objectтер. Мындай an objectилер баш аламан болуп, жаңы ыкмаларды кошууну кыйындатат. Сиз аларды колдонбошуңуз керек, анткени алар эмне үчүн арналганы белгисиз - элементтерди сактоо же кандайдыр бир логиканы аткаруу. Сиз бул жерден an objectтердин мүмкүн болгон түрлөрү жөнүндө окуй аласыз .

Өзгөрмөлөрдү түзүүнүн принциптери

Код жазуу эрежелери: системаны түзүүдөн an objectтер менен иштөөгө чейин - 6Келгиле, өзгөрмөлөр жөнүндө бир аз ойлонуп көрөлү, тагыраак айтканда, аларды түзүүнүн принциптери кандай болушу мүмкүн экендиги жөнүндө ойлонуп көрөлү:
  1. Идеалында, сиз өзгөрмөнү колдонуудан мурун дароо жарыялап, инициализациялашыңыз керек (аны түзүп, унутуп койгондун ордуна).
  2. Мүмкүн болушунча, инициализациялангандан кийин алардын мааниси өзгөрбөшү үчүн өзгөрмөлөрдү акыркы деп жарыялаңыз.
  3. Эсептөөчү өзгөрмөлөр жөнүндө унутпаңыз (көбүнчө биз аларды кандайдыр бир циклде колдонобуз for, башкача айтканда, аларды баштапкы абалга келтирүүнү унутпашыбыз керек, антпесе ал биздин логиканы бузушу мүмкүн).
  4. Сиз конструктордо өзгөрмөлөрдү инициализациялоого аракет кылышыңыз керек.
  5. Объектти шилтемеси бар же шилтемесиз ( ) колдонуунун ортосунда тандоо бар болсо new SomeObject(), ( ) тандаңыз , анткени колдонулгандан кийин бул an object кийинки таштанды чогултуу учурунда жок кылынат жана ресурстарды текке кетирбейт.
  6. Өзгөрмөлөрдүн иштөө мөөнөтүн мүмкүн болушунча кыска кылыңыз (өзгөрмөлөрдү түзүү менен акыркы мүмкүнчүлүктүн ортосундагы аралык).
  7. Циклде колдонулган өзгөрмөлөрдү циклди камтыган ыкманын башында эмес, дароо циклдин алдында баштаңыз.
  8. Ар дайым эң чектелген чөйрөдөн баштаңыз жана аны зарыл болгондо гана кеңейтиңиз (өзгөрмөлөрдү мүмкүн болушунча жергorктүү кылууга аракет кылышыңыз керек).
  9. Ар бир өзгөрмөнү бир гана максат үчүн колдонуңуз.
  10. Жашыруун маанидеги өзгөрмөлөрдөн алыс болуңуз (өзгөрмө эки тапшырманын ортосунда үзүлгөн, демек, анын түрү алардын бирин чечүүгө ылайыктуу эмес).
Код жазуу эрежелери: системаны түзүүдөн an objectтер менен иштөөгө чейин - 7

Методдор

Код жазуу эрежелери: системаны түзүүдөн an objectтер менен иштөөгө чейин - 8Биздин логиканы ишке ашырууга түз өтөлү, тактап айтканда, методдорго.
  1. Биринчи эреже - компакттуулук. Идеалында, бир ыкма 20 саптан ашпашы керек, ошондуктан, айталы, коомдук ыкма олуттуу "шишип" кетсе, бөлүнгөн логиканы жеке ыкмаларга жылдыруу жөнүндө ойлонушуңуз керек.

  2. ifЭкинчи эреже , else, жана башка буйруктардагы блоктор whileөтө уяланган болбошу керек: бул codeдун окулушун бир топ төмөндөтөт. Идеалында, уя эки блоктон ашпашы керек {}.

    Ошондой эле бул блоктордогу codeду компакттуу жана жөнөкөй кылуу максатка ылайыктуу.

  3. Үчүнчү эреже - метод бир гана операцияны аткарышы керек. Башкача айтканда, бир ыкма татаал, ар түрдүү логиканы аткарса, биз аны подметоддорго бөлөбүз. Натыйжада, методдун өзү фасад болот, анын максаты бардык башка операцияларды туура тартипте чакыруу.

    Ал эми операция өзүнчө ыкманы түзүү үчүн өтө жөнөкөй көрүнсө эмне болот? Ооба, кээде замбиректен таранчыларды аткандай сезorши мүмкүн, бирок кичинекей ыкмалар бир катар артыкчылыктарды берет:

    • codeду окуу оңой;
    • методдор тенденциясын иштеп чыгуунун жүрүшүндө татаалдашат жана эгерде метод алгач жөнөкөй болсо, анын функционалдуулугун татаалдантуу бир аз жеңorрээк болот;
    • ишке ашыруу деталдарын жашыруу;
    • codeду кайра колдонууну жеңилдетүү;
    • жогорку code ишенимдүүлүгү.
  4. Төмөнгө карай эреже – codeду жогорудан ылдый карай окуу керек: канчалык төмөн болсо, логиканын тереңдиги жана тескерисинче, канчалык жогору болсо, методдор ошончолук абстракттуу. Мисалы, которуштуруунун буйруктары абдан ыңгайсыз жана жагымсыз, бирок сиз которгучту колдонбостон кыла албасаңыз, аны мүмкүн болушунча төмөн, эң төмөнкү деңгээлдеги ыкмаларга жылдырууга аракет кылышыңыз керек.

  5. Метод аргументтери - канчасы идеалдуу? Идеалында, такыр жок)) Бирок чын эле ушундай болобу? Бирок, мүмкүн болушунча азыраак болгонго аракет кылуу керек, анткени алар канчалык аз болсо, бул ыкманы колдонуу ошончолук жеңил болот жана аны текшерүү ошончолук жеңил болот. Эгер шектенсеңиз, көп сандагы киргизүү аргументтери бар ыкманы колдонуунун бардык сценарийлерин болжолдоого аракет кылыңыз.

  6. Өзүнчө, киргизүү аргументи катары логикалык желеги бар ыкмаларды белгилегим келет , анткени бул табигый түрдө бул ыкма бир нече операцияны ишке ашырарын билдирет (эгерде чын болсо, бирөө, жалган болсо - башка). Мен жогоруда жазгандай, бул жакшы эмес жана мүмкүн болсо, качуу керек.

  7. Эгерде методдо келип түшкөн аргументтердин көп саны болсо (экстремалдуу маани 7, бирок бул тууралуу 2-3төн кийин ойлонушуңуз керек), айрым аргументтерди өзүнчө an objectке топтошуңуз керек.

  8. Эгерде бир нече окшош ыкмалар бар болсо (ашыкча жүктөлгөн) , анда окшош параметрлер бирдей тартипте берorши керек: бул окууга жана колдонууга ыңгайлуулукту жогорулатат.

  9. Параметрлерди методго өткөрүп бергенде, алардын баары колдонулаарына ишенишиңиз керек, антпесе аргумент эмне үчүн? Аны интерфейстен кесип салыңыз жана ушуну менен бүттү.

  10. try/catchАл өзүнүн табияты боюнча анча жакшы көрүнбөйт, андыктан аны ортодогу өзүнчө ыкмага (өзгөчө кырдаалдарды чечүү ыкмасы) которуу жакшы кадам болот:

    public void exceptionHandling(SomeObject obj) {
        try {
            someMethod(obj);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
Мен жогоруда codeду кайталоо жөнүндө айттым, бирок мен аны бул жерге кошом: Эгерде бизде codeдун бөлүктөрүн кайталаган бир нече методдор болсо, анда биз аны өзүнчө методго жылдырышыбыз керек, бул ыкманын да, ыкманын да компакттуулугун жогорулатат. класс. Жана туура ысымдарды унутпаңыз. Класстардын, интерфейстердин, методдордун жана өзгөрмөлөрдүн туура аталышынын чоо-жайын макаланын кийинки бөлүгүндө айтып берем. Ал эми бүгүнкү күндө менде бардыгы ушул. Код жазуу эрежелери: системаны түзүүдөн an objectтер менен иштөөгө чейин - 9Код эрежелери: туура ат коюу күчү, жакшы жана жаман комментарийлер
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION