JavaRush /Java Blog /Random-TK /Kod düzgünleri: dogry atlandyrmagyň güýji, gowy we erbet ...

Kod düzgünleri: dogry atlandyrmagyň güýji, gowy we erbet teswirler

Toparda çap edildi
Kod ýazmagyň düzgünleri: dogry atlandyrmagyň güýji, gowy we erbet teswirler - 1 Başga biriniň koduna näçe gezek düşünmeli bolduň? Bir-iki sagadyň ýerine, bolup geçýän zatlaryň logikasyna düşünmek üçin birnäçe gün sarp edýärsiňiz. Iň gülkünç zat, bu kody ýazan adam üçin hemme zat düşnükli we gaty aç-açan. Bu geň galdyryjy däl: ahyrsoňy, kämil ýa-da ideal kod gaty düşnüksiz düşünje, sebäbi her bir işläp düzüjiniň degişlilikde dünýä we kody göz öňünde tutýar. Birnäçe gezek kärdeşim bilen şol bir koda seredip, onuň dogrulygy we arassalygy barada dürli pikirlerimiz bolan bir ýagdaýa duş geldim. Kod ýazmagyň düzgünleri: dogry atlandyrmagyň güýji, gowy we erbet teswirler - 2Bu tanyş duýgy, şeýlemi? Şeýle-de bolsa, berjaý edilmeli käbir wagt synaglary bar, netijede bu biziň peýdamyz üçin peýdaly bolar, sebäbi koduňyzy özüňiz almak isleýän döwletiňizde goýsaňyz, dünýä birneme bagtly bolardy we arassalaýjy. Kod ýazmagyň düzgünleri (has dogrusy, kiçijik gollanma) baradaky soňky makalamyzdaKod ýazmagyň düzgünleri: dogry atlandyrmagyň güýji, gowy we erbet teswirler - 3 ulgamy tutuşlygyna ýazmak we onuň obýektleri, interfeýsleri, synplary, usullary we üýtgeýjileri ýaly elementleri barada azajyk durup geçdik. Şol ýerde käbir elementleriň dogry atlandyrylmagyny gysgaça aýtdym. Bu gün men bu barada takyk gürleşmek isleýärin, sebäbi dogry atlar kod okamagyny has aňsatlaşdyrýar. Koddaky pikirleriň we kiçijik düşündirişleriň kömegi bilen dogry kod mowzugyny ýaparys - bu gowy ýa-da beýle gowy däl. Geliň, başlalyň.

Dogry at bermek

Dogry atlar koduň okalmagyny gowulandyrýar, şoňa görä tanyşlyga wagt tygşytlaýar, sebäbi adyň işleýşini takmynan suratlandyranda usuly ulanmak has aňsat. Koddaky hemme zat atlardan (üýtgeýjiler, usullar, synplar, faýl obýektleri we ş.m.) ybarat bolany üçin, dogry, arassa kod döredilende bu nokat gaty möhüm bolýar. Aboveokardakylara esaslanyp, at näme üçin üýtgeýjiniň bardygyny, näme edýändigini we nähili ulanylýandygyny düşündirmeli. Üýtgeýjini suratlandyrmak üçin iň gowy teswiriň dogry adydygyny gaýtalap bellärin. Kod ýazmagyň düzgünleri: dogry atlandyrmagyň güýji, gowy we erbet teswirler - 4

Interfeýslere at bermek

Interfeýsler, adatça baş harp bilen başlanýan we düýe harpynda ýazylan atlary ulanýarlar (CamelCase). Ony interfeýs hökmünde bellemek üçin I bilen prefiks ýazmak üçin interfeýs ýazylanda gowy tejribe bardy (mysal üçin IUserService), ýöne bu gaty ýigrenji we ünsüňi çekiji. Şeýle ýagdaýlarda, (UserService) ýazman, ýerine ýetirilmegine -Impl (UserServiceImpl) goşmak has gowudyr. Bolýar, ýa-da iň soňky ýol hökmünde, ýerine ýetirilişine C (CUserService) prefiksini goşuň.

Synp atlary

Edil interfeýsler ýaly atlar baş harp bilen ýazylýar we düýe stilini ulanýar (CamelCase). Haýsy apokalipsisiň bolup geçýändigine garamazdan, möhletler näçe çalt bolsa-da, synpyň ady hiç haçan işlik bolmaly däldir! Synp we obýekt atlary atlar we olaryň utgaşmalary bolmaly (UserController, UserDetails, UserAccount we ş.m.). Her bir synpyň adyny bu programmanyň gysgaldylyşy bilen üpjün etmeli däl, sebäbi bu diňe gereksiz çylşyrymlylygy goşar (mysal üçin, Ulanyjy maglumatlary göçürmek programmasy bar we her synpa UDM goşarys - UDMUserDeatils, UDMUserAccount, UDMUserController ).

Usul atlary

Adatça usullaryň atlary kiçi harpdan başlaýar, ýöne düýe stilini hem ulanýarlar (CamelCase). Oveokarda synp atlarynyň hiç haçan işlik bolmaly däldigi hakda gürleşdik. Bu ýerde ýagdaý düýpgöter ters: usullaryň atlary işlikler ýa-da işlikler bilen utgaşmasy bolmaly: findUserById, findAllUsers, createUser we ş.m. Bulaşyklygyň öňüni almak üçin usul (şeýle hem üýtgeýjiler we synplar) döredilende, at dakmagyň bir usulyny ulanyň. Mysal üçin, ulanyjy tapmak üçin bu usul getUserById ýa-da findUserById diýip ýazylyp bilner. Moreene bir zat: degişmäni usullaryň atlarynda ulanmaň, sebäbi olar degişmä we bu usulyň näme edýändigine düşünip bilmezler.

Üýtgeýän atlar

Köplenç üýtgeýän atlar kiçi harp bilen başlaýar we üýtgeýjiniň global üýtgewsiz ýagdaýlaryndan başga ýagdaýlarda Camelcase-den peýdalanýar. Şeýle ýagdaýlarda adyň ähli harplary baş harp bilen ýazylýar we sözler aşaky çyzyk bilen bölünýär - “_”. Üýtgeýjilere at berlende, amatlylyk üçin manyly kontekst ulanyp bilersiňiz. Başga sözler bilen aýdylanda, has uly bir zadyň bölegi hökmünde üýtgeýji bar bolsa - mysal üçin, FirstName, familiýa, status - şeýle ýagdaýlarda bu üýtgeýjiniň obýektini görkezýän prefiksi goşup bilersiňiz. Mysal üçin: userFirstName, userLastName, userStatus. Şeýle hem üýtgeýänler üçin düýbünden başga manylary bolan meňzeş atlardan gaça durmaly. Üýtgeýjiler üçin umumy antonimler:
  • başla / gutar
  • birinji / soňky
  • gulplanan / açylmadyk
  • min / max
  • indiki / öňki
  • köne / täze
  • açyldy / ýapyldy
  • görünýän / görünmeýän
  • çeşme / maksat
  • Çeşme / barmaly ýer
  • ýokary / aşak

Gysga üýtgeýän atlar

Haçan-da x ýa-da n ýa-da şuňa meňzeş üýtgeýjiler bar bolsa, kod ýazan adamyň niýetini derrew göremzok. N usulynyň näme edýändigi belli däl: has oýlanyşykly pikirlenmegi talap edýär (we bu wagt, wagt, wagt). Mysal üçin, bir meýdançamyz bar - jogapkär ulanyjynyň ID-si, x ýa-da diňe id ýaly käbir atlaryň ýerine, okalýanlygy we manylylygy derrew ýokarlandyrýan bu üýtgeýän jogapkärUserId diýeris. Şeýle-de bolsa, n ýaly gysga atlaryň kiçi usullara ýerli üýtgeşmeler hökmünde öz orny bar, bu üýtgeşme bilen kod bloky diňe iki setir kod bolup, usulyň ady ol ýerde nämeleriň bolup geçýändigini doly suratlandyrýar. Şeýle üýtgeýjini görüp, dörediji ikinji derejeli ähmiýetine we örän çäkli çägine düşünýär. Netijede üýtgeýän adyň uzynlygyna belli bir derejede baglylyk bar: näçe uzyn bolsa, üýtgeýän şonça-da global bolýar we tersine. Mysal üçin, soňky saklanan ulanyjyny senä görä tapmagyň usuly:
public User findLastUser() {
   return findAllUsers().stream()
           .sorted((x, y) -> -x.getCreatedDate().compareTo(y.getCreatedDate()))
           .findFirst()
           .orElseThrow(() -> new ResourceNotFoundException("Any user doesn't exist "));
}
Bu ýerde akymyň tertibi düzmek we olary ýatdan çykarmak üçin x we ​​y gysga atlary ulanýarys.

Iň amatly uzynlyk

Adyň uzynlygy mowzugyny dowam etdireliň. Iň amatly at uzynlygy, iň ýokaryNumberOfUsersInTheCurrentGroup adynyň uzynlygy bilen n arasynda. Tooagny, gaty gysga adamlar manysyzlykdan ejir çekýärler we gaty uzynlary programmany okamaga goşmazdan uzadýarlar we her gezek ýazmak üçin gaty ýalta. Aboveokardaky ýagdaýy göz öňünde tutman, n ýaly gysga ady bolan üýtgeýjiler üçin uzynlygy takmynan 8 -16 simwola çenli saklamaly. Bu berk düzgün däl: has köp görkezme.

Kiçijik tapawutlar

Atlardaky inçe tapawutlary äsgermezlik edip bilmerin, sebäbi bu hem erbet tejribe, sebäbi atlaryň ownuk tapawudyny görüp, bulaşyp ýa-da köp wagt sarp edip bilersiňiz. Mysal üçin, InvalidDataAccessApiUsageException bilen InvalidDataAccessResourceUsageException arasyndaky tapawudy bir göz bilen görmek kyn. Şeýle hem, kiçijik L we O ulanylanda ýalňyş maglumatlar köplenç ýüze çykyp biler, sebäbi olary 1 we 0 bilen aňsatlyk bilen bulaşdyryp bolar: käbir şriftlerde tapawut has aýdyň, beýlekilerde beýle az.

Semantik bölek

Semantiki bölegi atlara salmalydyrys, ýöne manydaş sözler bilen gabat gelmeli däl, sebäbi, mysal üçin, UserData we UserInfo aslynda birmeňzeş many berýär we haýsy anyk obýektiň gerekdigine düşünmek üçin kody birneme çuňlaşdyrmaly bolarys. . Maglumat bermeýän sözlerden gaça duruň, mysal üçin, FirstNameString: näme üçin setir sözi gerek? Ady sene görnüşli obýekt bolup bilermi? Elbetde ýok: şonuň üçin ýönekeý - firstName. Mysal üçin, üýtgeýän üýtgeýänleri, mysal üçin flagDelete bellemek isleýärin. Baýdak sözüniň manysy ýok. Muny isDelete diýip atlandyrmak has ýerlikli bolardy.

Dezinformasiýa

Nädogry at dakmak barada birnäçe söz aýtmak isleýärin. “UserActivityList” adymyz bar diýeliň we şeýle atlandyrylan obýekt Sanaw görnüşine däl-de, başga bir konteýner ýa-da saklamak üçin ýörite obýektdir. Bu ortaça programmisti bulaşdyryp biler: ony userActivityGroup ýa-da userActivities ýaly bir zat diýip atlandyrsaň gowy bolardy.

Gözlemek

Gysga we ýönekeý atlaryň kemçiliklerinden biri, köp mukdarda kod tapmak kyn, sebäbi näme tapmak has aňsat: at ýa-da NAME_FOR_DEFAULT_USER atly üýtgeýji? Elbetde, ikinji wariant. Atlarda ýygy-ýygydan ýüze çykýan sözlerden (harplardan) gaça durmaly, sebäbi bu diňe gözleg wagtynda tapylan faýllaryň sanyny artdyrar, bu gowy däl. Programmistleriň kod ýazmakdan has köp wagt sarp edýändigini ýatladýarys, şonuň üçin programmaňyzyň elementleriniň adyny ýatdan çykarmaň. Emma üstünlikli at goýup bilmeseňiz näme? Usulyň ady onuň işleýşini gowy suratlandyrmasa näme etmeli? Ine, şu ýerde oýnaýar, indiki elementimiz teswirler.

Teswirler

Kod ýazmagyň düzgünleri: dogry atlandyrmagyň güýji, gowy we erbet teswirler - 5Degişli teswir ýaly zat ýok, ýöne manysyz, köne ýa-da ýalňyş teswirler ýaly moduly hiç zat gysmaýar. Iki ýüzli gylyç, şeýlemi? Şeýle-de bolsa, teswirleri birkemsiz ýagşylyk hökmünde kabul etmeli däl, has gowusy ýamanlyk hökmünde garamaly dälsiňiz. Galyberse-de, teswir, aslynda, kodda şowsuz beýan edilen pikiriň öwezini dolmakdyr. Mysal üçin, gaty bulaşyk bolsa, usulyň düýp manysyny bermek üçin ulanýarys. Şeýle ýagdaýda düşündirişli bellikleri ýazman, kody dogry üýtgetmek has gowudyr. Teswir näçe köne bolsa, şonça-da erbet bolýar, sebäbi kod ösmäge we ösmäge ýykgyn edýär, ýöne teswir öňküligine galyp biler we näçe öňe gitse, bu bellikler şonça-da şübheli bolýar. Nädogry teswirler teswirlerden has erbetdir, sebäbi ýalan garaşýanlary bulaşdyryp, aldaýar. Örän kyn kodumyz bar bolsa-da, bu barada teswir bermeli däl, täzeden ýazmaly.

Teswirleriň görnüşleri

  • kanuny düşündirişler, kanuny sebäplere görä her çeşme kod faýlynyň başynda galan teswirlerdir:

    * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
    * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.

  • Maglumat beriji düşündirişler , koduň düşündirişini berýän düşündirişlerdir (goşmaça maglumat ýa-da berlen koduň niýeti).

    Mysal hökmünde:

    /*
    * Объединяет пользователя из бд и пришедшего для обновления
    * Когда в requestUser поле пустое, оно заполняется старыми данными из foundUser
    */
    private User mergeUser(User requestUser, User foundUser) {
           return new User(
           foundUser.getId(),
           requestUser.getFirstName() == null ? requestUser.getFirstName() : foundUser.getFirstName(),
           requestUser.getMiddleName() == null ? requestUser.getMiddleName() : foundUser.getMiddleName(),
           requestUser.getLastName() == null ? requestUser.getLastName() : foundUser.getLastName(),
           requestUser.getAge() == null ? requestUser.getAge() : foundUser.getAge()
           );
           }

    Bu ýagdaýda düşündiriş bermezden edip bilersiňiz, sebäbi usulyň ady we argumentleri, örän aç-açan işlemek bilen özlerini gaty gowy suratlandyrýar.

  • duýduryş düşündiriş - maksady käbir hereketleriň islenilmeýän netijeleri barada beýleki döredijilere duýduryş bermekden ybarat teswir (mysal üçin, synagyň näme üçin @Ignore diýip bellendi):

    // Слишком долго отрабатывает
    // Не запускайте, если не располагаете избытком времени
    @Ignore
    @Test
    public void someIntegrationTest() {
           ……
           }
  • TODO - edilmeli geljek üçin bellikler, ýöne näme üçindir häzir edip bolmaýar. Bu gowy tejribe, ýöne bulaşyklykdan gaça durmak üçin ähmiýetsizleri aýyrmak üçin henizem yzygiderli gözden geçirilmeli.

    Примером послужит:

    //TODO: Add a check for the current user ID (when will be created security context)
    
    @Override
    public Resource downloadFile(File file) {
           return fileManager.download(file);
           }

    Тут мы помечаем, что нужно добавить проверку юзера, который скачивает (id которого мы вытащим из security контекста) с тем, кто сохранил.

  • усorвающий комментарий — комментарий, подчеркивающий важность Howого-то обстоятельства, что на первый взгляд может показаться несущественным.

    Как пример, кусочек метода, заполняющий тестовую БД, некими скриптами:

    Stream.of(IOUtils.resourceToString("/fill-scripts/" + x, StandardCharsets.UTF_8)
           .trim()
           .split(";"))
           .forEach(jdbcTemplate::update);
    // Вызов trim() очень важен, убирает возможные пробелы в конце скрипта
    // чтобы при считке и разбивке на отдельные requestы не было пустых

  • javaDoc — комментарии, которые описывают API определенного функционала для общего пользования. Наверное, самые полезные комментарии, так How с documentированным API в разы легче работать, но они также могут устаревать, How и любые другие. Поэтому не забываем, что главный вклад в documentацию вносится не комментариями, а хорошим codeом.

    Пример вполне обычного метода обновления пользователя:

    /**
    * Обновляет передаваемые поля для пользователя по id.
    *
    * @param id  id обновляемого пользователя
    * @param user пользователь с заполненными полями для обновления
    * @return обновленный пользователь
    */
           User update(Long id, User user);

Плохие сценарии комментариев

Kod ýazmagyň düzgünleri: dogry atlandyrmagyň güýji, gowy we erbet teswirler - 7
  • бормочущий комментарий — комментарии, которые обычно пишут на скорую руку, смысл которых понятен только разработчику, писавшего их, так How только он видит ту ситуацию с теми нюансами, на которые он и ссылается.

    Рассмотрим данный пример:

    public void configureSomeSystem() {
           try{
           String configPath = filesLocation.concat("/").concat(CONFIGURATION_FILE);
           FileInputStream stream = new FileInputStream(configPath);
           }  catch (FileNotFoundException e) {
           //В случае отсутствия конфигурационного file, загружается конфигурация по умолчанию
          }
    }

    Кто загружает эти настройки? Были ли они загружены ранее? Метод предназначен для перехвата исключений и вызова дефолтных настроек? Слишком много вопросов возникает, ответы на которые можно получить лишь углубившись в изучение других частей системы.

  • избыточный комментарий — комментарий, который не несёт смысловой нагрузки, так How и так понятно что происходит в заданном участке codeа (он читается не проще, чем code).

    Смотрим пример:

    public class JdbcConnection{
    public class JdbcConnection{
       /**
        * Журнальный компонент, связанный с текущим классом
        */
       private Logger log = Logger.getLogger(JdbcConnection.class.getName());
    
       /**
        * Создаёт и возвращает connection с помощью входящих параметров
        */
       public static Connection buildConnection(String url, String login, String password, String driver) throws Exception {
           Class.forName(driver);
           connection = DriverManager.getConnection(url, login, password);
           log.info("Created connection with db");
           return connection;
       }

    Какой смысл таких комментариев, если мы и так всё прекрасно видим

  • недостоверные комментарии — комментарии, не соответствующие истине и лишь вгоняющие в заблуждение (дезинформирующие). Как например:

    /**
    * Вспомогательный метод, закрывает соединение со сканером, если isNotUsing истинно
    */
    private void scanClose(Scanner scan, boolean isNotUsing) throws Exception {
       if (!isNotUsing) {
           throw new Exception("The scanner is still in use");
       } scan.close();
    }

    What в этом комменте не так? А то, что он немножко врёт нам, ведь соединение закрывается, если isNotUsing = false, но ниHow не наоборот, How нам вещает пометка.

  • обязательные комментарии — комментарии, которые считают обязательными (Javadoc), но кои по факту иногда бывают излишне нагромождающими, недостоверными и ненужными (нужно задуматься, а нужны ли здесь такие комментарии).

    Пример:

    /**
    *  Creation пользователя по переданным параметрам
    * @param firstName Name созданного пользователя
    * @param middleName среднее Name созданного пользователя
    * @param lastName фамorя созданного пользователя
    * @param age возраст созданного пользователя
    * @param address addressс созданного пользователя
    * @return пользователь который был создан
    */
    User createNewUser(String firstName, String middleName, String lastName, String age, String address);

    Смогли бы вы понять, что делает метод без этих комментариев? Скорее всего да, поэтому комментарии в этом случае стают бессмысленными.

  • журнальные комментарии — комментарии, которые иногда добавляют в начало модуля, при каждом его редактировании (что-то вроде журнала вносимых изменений).

    /**
    *  Записи ведутся с 09 января 2020;
    **********************************************************************
    *  09.01.2020  : Обеспечение соединения с БД с помощью Jdbc Connection;
    *  15.01.2020  : Добавление интерфейсов уровня дао для работы с БД;
    *  23.01.2020  : Добавление интеграционных тестов для БД;
    *  28.01.2020  : Имплементация интерфейсов уровня дао;
    *  01.02.2020  : Разработка интерфейсов для сервисов,
    *  согласно требованиям прописанным в user stories;
    *  16.02.2020  : Имплементация интерфейсов сервисов
    *  (реализация бизнес логики связанной с работой БД);
    *  25.02.2020  : Добавление тестов для сервисов;
    *  08.03.2020  : Празднование восьмого марта(Миша опять в хлам);
    *  21.03.2020  : Рефакторинг сервис слоя;
    */

    Когда-то этот проход был оправдан, но с появлением систем управления исходным codeом (например — Git), это стало лишним нагромождением и усложнением codeа.

  • комментарии ссылки на авторов — комментарии, преднаmeaningм которых является, указание человека, писавшего code, чтобы можно было связаться и обсудить, How что и зачем:

    * @author  Bender Benderovich

    Опять же, системы контроля версий прекрасно запоминают, кто и когда добавил данный code, и подобный подход излишен.

  • düşündirişli kod, bir sebäbe görä teswirlenen kod. Iň erbet endikleriň biri, sebäbi teswir ýazdyňyz we ýatdan çykardyňyz, beýleki döredijiler bolsa ony pozmaga batyrlyk edip bilmeýärler (gymmatly zat bolsa näme).

    //    public void someMethod(SomeObject obj) {
    //    .....
    //    }

    Netijede, hapa ýaly ýygnanýar. Hiç hili ýagdaýda beýle kod galdyrylmaly däldir. Eger hakykatdanam size zerur bolsa, wersiýa dolandyryş ulgamyny ýatdan çykarmaň.

  • düşnüksiz teswirler, bir zady gereksiz çylşyrymly suratlandyrýan teswirlerdir.

    /*
        * Начать с массива, размер которого достаточен для хранения
        * всех byteов данных (плюс byteы фильтра) с запасом, плюс 300 byte
        * для данных заголовка
        */
    this.dataBytes = new byte[(this.size * (this.deep + 1) * 2)+300];

    Teswir, kody düşündirmeli, düşündirişiň özi gerek däl. Bu ýerde näme? “Süzgüç baýtlary” näme? Munuň bilen +1 näme baglanyşygy bar? Näme üçin takmynan 300?

Teswir ýazmak kararyna gelseňiz, olary ulanmak üçin birnäçe maslahat:
  1. Saklamak aňsat stilleri ulanyň: gaty ajaýyp we ekzotik görnüşleri saklamak bizar we wagt talap edip biler.
  2. Setirleriň soňundaky teswirleri ýeke setirlere ulanmaň: bu köp sanly teswir döredýär we her setir üçin täsirli teswir ýazmak kyn.
  3. Teswir döredeniňizde, "nädip" däl-de, "näme üçin" diýen soraga jogap bermäge synanyşyň.
  4. Gysgaltmalardan gaça duruň. Aboveokarda aýdyşym ýaly, teswir üçin düşündiriş gerek däl: teswir düşündiriş.
  5. Ölçeg birliklerini we kabul ederlikli bahalaryň diapazonyny bellemek üçin teswirleri ulanyp bilersiňiz.
  6. Teswirleri beýan edýän koduna ýakyn ýerleşdiriň.
Netijede, size henizem ýatlatmak isleýärin: iň gowy teswirler teswiriň ýoklugy we onuň ýerine programmada dogry at bermek. Düzgün bolşy ýaly, köplenç eýýäm taýýar kod bilen işleýäris, ony saklaýarys we giňeldýäris. Bu kody okamak we düşünmek aňsat bolanda has amatly bolýar, sebäbi erbet kod ýoldan çykýar, tigirleri gürleýär we howlukmaçlyk onuň wepaly ýoldaşydyr. Näçe erbet kod bar bolsa, şonça-da öndürijilik peselýär, şonuň üçin wagtal-wagtal reaktor etmeli. Theöne ilkibaşdan indiki döredijiler sizi tapmak we öldürmek islemeýän kod ýazmaga synanyşsaňyz, ony ýygy-ýygydan gaýtadan işlemeli bolarsyňyz. Stillöne henizem zerur bolar, sebäbi önüme bolan şertler we talaplar yzygiderli üýtgeýär, goşmaça birikmeler goşmak bilen üsti ýetirilýär we mundan gutulyp bolmaýar. Ahyrynda, bu mowzuk bilen şu ýerde , şu ýerde we şu ýerde tanyşmagyňyz üçin birnäçe gyzykly baglanyşyk goýaryn , okanlaryň hemmesine sag bolsun aýdýaryn) Kod ýazmagyň düzgünleri: dogry atlandyrmagyň güýji, gowy we erbet teswirler - 8
Teswirler
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION