Háttérszoftver-architektúra ellenőrzőlista: Hogyan készítsünk egy terméket a Scratch-ból

Egy reggel arra ébredsz, hogy megiszod a csészédet és a voilàt, itt az Eureka pillanat. Végül kitalálta üzleti modelljét, és mindez a helyére kerül. Tudja, hogy a befektetők imádni fogják, és már alig várja, hogy elkezdje a termék építését. Az első mozgató előny a tiéd.

Ezek a pillanatok ritkák, de amikor megtörténnek, akkor a megfelelő időben kell elindulnia. Minden, amire szüksége van, a megfelelő útmutató, amely segít kitalálni, mit kell és mit nem szabad tennie. Ez nem kísérletezés, hanem végrehajtás ideje. Itt az ideje!

MEGJEGYZÉS - Az alábbiak a szoftverarchitektúrák nulláról történő elkészítéséhez kapcsolódnak. Tehát, ha érdekel az érintett technológiák csekély ismerete, folytassa. Ellenkező esetben kérjük, ossza meg azokkal, akik ezt biztosan imádni fogják: P

Honnan jött ez az útmutató

Jómagam egy maroknyi korai stádiumú terméken dolgoztam, és hogy őszinte legyek, hibákat követtem el. Mindig azt kívántam, hogy legyen egy ellenőrzőlista, amelyet követni kell, miközben egy terméket építenek az alapoktól.

Olyan sok dolog vesz részt az építészet nulláról történő felépítésében, hogy bizonyos darabokat teljesen elfelejt. És visszatérnek, hogy megharapjanak a termékciklus későbbi szakaszaiban.

Végül úgy döntöttem, hogy elkészítem ezt az ellenőrzőlistát azokról a dolgokról, amelyeket érdemes megfontolni, mielőtt először megnyomná azt a telepítési gombot.

Tehát további kiépítés nélkül, itt van az ellenőrzőlista, amelyet át kell néznie, miközben a Backend architektúrát készíti egy termékről a semmiből.

Válassza ki a projekt helyes nyelvét és keretrendszerét

A termék megfelelő nyelvének és keretrendszerének kiválasztása bonyolult, és ehhez nincs különösebb ezüstgolyó. Azt tanácsolom, hogy válasszon egy olyan nyelvet, amellyel a legkényelmesebb, és ismeri a be- és a kifinomultságokat.

Ennek ellenére ritka, mert nagyon kevés olyan ember van, aki Javascript Ninjas, vagy Python Panthers, vagy bármilyen funky név van odakint.

Tehát válasszon egy olyan nyelvet, amely valóban jó támogatást nyújt az iparban, például Javascript, Python, Java vagy Go, hogy csak néhányat említsünk. Bármelyik nyelvet választhatja, csak válassza ki, melyik a legkényelmesebb az Ön számára.

És ne feledje - Ön egy MVP-t (Minimum életképes termék) épít, és folyamatban lesz egy POC (Proof of Concept) létrehozása. Tehát a lehető leghamarabb hozza ki a terméket. Nem kell elakadnia olyan kérdésekben, amelyek a város új nyelvéből származhatnak. E problémák elkerülése érdekében válasszon egy szélesebb körben használt, jól dokumentált nyelvet.

Végül később is méretezhet. Ha POC-k készítésének szakaszában van, csak készítse el és hajtsa végre. De ha valami igazán sajátos dolgot építesz, és külön erre van egy nyelv és egy keretrendszer, akkor mindenképpen ezt a technikát kell választanod.

De legtöbbször azok a problémák, amelyeket megpróbálunk megoldani, könnyen kezelhetők a fent említett nyelvek bármelyikével és azok megfelelő kereteivel. Tehát csak válasszon egyet és indítsa el a terméket.

Jó erőforrás a döntéshozatalban -

//content.techgig.com/top-5-programming-languages-for-backend-web-development/articleshow/67337449.cms

Hitelesítési és hitelesítési mikroszolgáltatások megvalósítása

Nagyon sokféleképpen lehet hitelesíteni és hitelesíteni a felhasználókat. Kipróbálhatja a Session Tokeneket, a JWT-t (JSON Web Tokens) vagy az OAuth-ot, hogy csak néhányat említsen. Minden lehetőségnek megvannak a maga előnyei és hátrányai. Tehát nézzük meg néhányukat alaposabban.

JSON web tokenek

A JWT-k gyorsan és egyszerűen kivitelezhetők. Ennek oka, hogy a tokenek soha nem kerülnek tárolásra a rendszeren. Csak kódolják, titkosítják és elküldik a felhasználónak. Tehát a JWT érvényesítése gyorsabb, mint bármely más módszer.

De mivel ezek nincsenek tárolva a rendszeren, valójában nem teheti meg, hogy egy token lejárjon a tényleges lejárati ideje előtt, és ez bizonyos esetekben problémát jelenthet.

Tehát találja ki az egyes hitelesítési rendszerek előnyeit és hátrányait, és válassza ki azt, amelyik a legjobban megfelel az Ön igényeinek. Én személy szerint a JWT-ket részesítem előnyben (de ez a saját választásom).

Engedélyezés

Soha ne felejtse el végrehajtani a felhasználók engedélyezését. Nem akarja, hogy a User1 bejelentkezve megváltoztassa a User2 adatait. Ez tiszta káoszt okozhat a rendszerében.

Azonosítsa a jogosultságot igénylő végpontokat, és azonnal hajtsa végre azokat. Nem akarja, hogy az adatbázis állapota így sérüljön. Ne feledje a 401 és 403 közötti különbséget.

Az alábbiakban bizonyos végpontokat érdemes feltétlenül figyelembe venni a hitelesítési rendszer létrehozása során (én Djangóban hoztam létre a JWT használatával). Lehetnek bizonyos kiegészítések / törlések a használati esethez, de ezeket érdemes megfontolni.

Sok keret biztosítja őket a dobozból, de fontolja meg őket, mielőtt önállóan felépítené őket. További tájékozódásért ellenőrizze a Django Rest Framework hitelesítési osztályait és jogosultsági osztályait.

Tekintse meg ezt a Django REST Framework forrást -

//www.django-rest-framework.org/tutorial/4-authentication-and-permissions/

Hozzon létre egy absztrakt alapmodellt, amelyet az adatbázis minden más modellje örökölhet

Ne feledje a SZÁRAZ elvet - Ne ismételje meg önmagát? A szoftvertervezésben a lényegig kell követni.

A fenti gondolkodási folyamatra építve az adatbázisban lesznek bizonyos oszlopok, amelyek minden táblázatban megtalálhatók lesznek. Ezért jobb egy absztrakt osztályt létrehozni nekik, hogy más modellosztályok örökölhessenek tőlük.

Menjünk át ezen a kódon, és mit jelent:

  • id - Bár nem ide van írva, automatikusan a Django keretrendszer hozza létre. De ha nincs a tiédben, írd le ebbe az osztályba. Ez csak egy automatikusan növelt mező, amely elsődleges kulcsként használható az adatbázis-relációban.
  • created_at - Ez azt jelenti, ha a mezőt / sort beillesztették a táblába, és maga a keretrendszer tölti ki. Nem kell kifejezetten beállítania.
  • updated_at - Ez azt jelenti, hogy a mezőt / sort mikor módosították / frissítették utoljára a táblázatban, és megint maga a keret tölti ki.
  • delete_at + is_deleted - Tehát ez egy ellentmondásos terület. Nincs pontos válaszom arra, hogy ott legyen-e vagy sem - mert hogy őszinte legyek, az interneten soha semmit nem törölnek. Ez a mező, ha kitöltötte, azt ábrázolja, hogy a sort törölték a rendszerből (bár az adatok a rendszerben maradnak a későbbi hivatkozásokhoz, és levehetők az adatbázisból, és biztonsági másolatokban tárolhatók).
  • uuid - Attól függ, hogy ezt szeretné-e betenni az asztalába vagy sem. Ha a táblázat Elsődleges kulcsát külső rendszernek kell kitennie, akkor jobb, ha ezt tesszük ki, nem pedig az automatikus növekményes egész mezőt. Kíváncsi lehet, miért ...? Nos, miért akarja elmondani egy külső rendszernek, hogy 10378 megrendelés van a táblázatában? De ez megint személyes választás.

Állítson be egy értesítési mikroszolgáltatást

Minden terméknek emlékeztetőket és értesítéseket kell küldenie a felhasználónak elkötelezettség és tranzakció céljából. Tehát minden terméknek szüksége lesz erre.

Feltétlenül fontolóra kell vennie egy olyan Mikroszolgáltatás kiépítését, amely értesítési szolgáltatásokat (például push értesítést, e-maileket és SMS-eket) nyújt a végfelhasználók számára.

Ennek egy külön Microservice-nek kell lennie. Ne építse ezt az Authentication Microservice vagy az Application Service (a tényleges üzleti logika) belsejébe.

Nagyon sok harmadik féltől származó könyvtár / szolgáltatás használható az alkalmazás felépítéséhez. Használja ki őket, és építsen rá.

Ne felejtse el felépíteni mind a 3 funkciót:

  • Push Notifications (APNS + FCM),
  • E-mailek (csak az SMTP-kliens integrálása a kezdethez)
  • és SMS

MEGJEGYZÉS - Rendeljen két csatornát SMS-ek küldéséhez, tranzakciós és promóciós célokra. Soha ne küldjön promóciós SMS-t tranzakciós csatornán, mert van esély arra, hogy egy jól informált és motivált felhasználó perelje be.

Az SMTP-ügyfél konfigurálásának egyszerű módja az alkalmazásban, ha ezt használja a beállításaiban:

Ezt Django-ban tettem, de ugyanezt megteheti a választott nyelven és keretrendszerben is.

Állítsa be a hibanaplózást

Középprogram használatával naplózhatja a termelési rendszeren előforduló hibákat. A termelési rendszerét nem figyelik az ott ülő emberek, hogy a nap 24 órájában megtekinthessék az alkalmazás naplóit. Szüksége lesz tehát egy olyan rendszerre, amely ezeket a belső kiszolgáló hibákat központi helyen naplózza. Ezután naponta megnézheti őket, vagy létrehozhat egy webhorgot, hogy a megfelelő időben figyelmeztesse Önt és vigyázhasson rájuk.

Nagyon sok harmadik fél hibakeresési eszköze van a piacon. Csak válasszon egyet, amely megfelel az Ön igényeinek. Leginkább a Sentry / Airbrake-et használom.

Fontolja meg a webhookok konfigurálását, ahogy fentebb említettem. Tájékoztatni fogják a felhasználókat a hibákról, és például közzéteheti ezeket a hibákat, amikor és mikor jelentkeznek bizonyos laza csatornákon. Ezután rendszeresen ellenőrizheti ezeket a csatornákat, és a súlyosságuk alapján kijavíthatja őket.

Az Airbrake hivatalos honlapja - //airbrake.io/

Sentry hivatalos honlapja - //sentry.io/welcome/

Kérés - válasz és alkalmazás naplózás végrehajtása

Forgatókönyv - A felhasználó segítségére van, és azt mondja, hogy nem kapta meg a tranzakciós nyugtát a webhelyén végrehajtott vásárlásról. Mit fogsz csinálni?

Ha az alkalmazásnaplózást beillesztette a rendszerébe, ne aggódjon. Most mit akarok ezzel mondani? Mindig jobb példát mutatni, mint megpróbálni szavakkal magyarázni. Tehát itt van:

Jelentkeztem, hogy elküldöm az e-mailt az említett email_id címre. Az alkalmazás naplóiban megnézhetem, hogy az e-mailt valóban elküldtük-e az ügyfélnek, annak ellenőrzésével, hogy létezik-e ilyen napló a rendszerben. Ügyeljen arra, hogy átfogó naplófájlokat tegyen a rendszerbe, hogy nyomon tudja követni a kérés útját.

Ezenkívül célszerű egy olyan aszinkron rendszert létrehozni, amely az ilyen kérés-válasz és alkalmazásnaplókat kiszedi a rendszerből, és központi helyre teszi őket. Ott azokat könnyebben értelmezhető módon lehet feldolgozni.

Az ELK verem erre jó lehetőség: ElasticSearch - Logstash - Kibana.

További információ az ELK veremről - //www.elastic.co/what-is/elk-stack

MEGJEGYZÉS - A kérelem és válaszok naplózása közben ügyeljen a következőkre:

  • Ne naplózza a jelszavakat.
  • Ne jelentkezzen be tokenek (a hitelesítéshez használt hozzáférési tokenek)
  • Ne jelentkezzen be az OTP-kbe

Vezesse be az API-k fojtását és az alkalmazásszerverek sebességkorlátozását

Forgatókönyv - Most indította szolgáltatását, és a terméket a közösségi média platformjain értékesítette. Egy fekete kalapos hacker rájött, és csak játszani akart a rendszerével. Tehát egy DOS (Denial of Service) támadást terveztek a rendszered ellen.

Ennek leküzdése érdekében különféle tényezők alapján állíthat be sebességkorlátozást az alkalmazáskiszolgálók terheléselosztói tetején. Ez gondoskodik a DOS-támadásokról, és megakadályozza, hogy a rosszindulatú felhasználó megtámadja a szervereit.

Forgatókönyv - Az API végpont / otp / validate, amely négyjegyű OTP-ket vesz igénybe a felhasználó hitelesítéséhez, és visszaadja a tokeneket a hitelesített API-khoz. Egy rosszindulatú felhasználó megkapja az egyik kliens mobilszámát, és az IP-címet megváltoztató durva erőszakos támadással, DDOS (Distributed Denial of Service) támadással eléri az API végpontot. A sebességkorlátozó nem képes megállítani a felhasználót, mert az IP minden bekéréskor folyamatosan változik.

Ennek leállításához az API-kat a felhasználó alapján is fojthatja. Beállíthatja, hogy egy adott felhasználó hány kérést nyújtson be egy API-végponthoz. Az OTP validálásához jó szám az 5 kérelem 10 percenként. Ez megakadályozza, hogy a rosszindulatú felhasználó durva DDOS-támadást hajtson végre a fenti API-n.

Fojtás a Django REST keretrendszerében -

//www.django-rest-framework.org/api-guide/throttling/

Az aszinkron kommunikáció létrehozása és konfigurálása az első naptól kezdve

Forgatókönyv - Üdvözlő e-mailt kell küldenie a felhasználónak, amikor regisztrál az alkalmazásába. A kezelőfelület eltalálja a Register API-t, validálás után létrehozza a felhasználót a háttérprogramban, és ezzel elindítja az üdvözlő e-mail küldését.

Az üdvözlő e-mail elküldése időbe telik, talán néhány másodpercig. De miért szeretné, ha a mobil kliens elakadna egy ilyen folyamatnál? Ez történhet a háttérben anélkül, hogy a felhasználó különösebb ok nélkül elakadna a Regisztráció oldalon. Minden másodperc értékes, és nem akarja, hogy a felhasználó elveszítse ezeket az értékes másodperceket.

Tehát egyszerűen küldje el az e-mailt aszinkron feladaton keresztül. Használja a munkavállalókat, a feladatokat, az üzenetközvetítőket és az eredmény háttereket ennek végrehajtásához.

Ennek egyik jó példája a Python világából a Zeller dolgozója. Csak tegye a végrehajtandó feladatot egy üzenetközvetítőbe (Nyúl MQ / SQS stb.). Zeller meghallgatja ezt, és elküldi a feladatot a kijelölt dolgozónak. Ez a munkavállaló majd feldolgozza a kérést, és az eredményt egy eredmény háttér-háttérbe helyezi, amely lehet Cache rendszer / adatbázis rendszer. (Redis / PostgreSQL például).

Figyelemmel kísérheti ezeket a feladatokat és a sorokat számos harmadik fél könyvtárával. Jó példa erre a Zeller Virág, amely mindezt figyeli.

A RabbitMQ-ról itt olvashat bővebben - //www.rabbitmq.com/

És zeller - //docs.celeryproject.org/en/stable/django/first-steps-with-django.html

És végül: Zellervirág - //flower.readthedocs.io/en/latest/

Állítson be cron-feladatokat

Forgatókönyv - Most indította el termékét, és ajánlásokat kell küldenie a felhasználóknak a platformján található új termékekről. Ezeket minden hétvégén elküldi a vásárlási előzmények alapján.

A fenti feladat könnyen elvégezhető egy cron munka segítségével. Könnyen konfigurálható minden keretrendszerben. Fontos szem előtt tartani, hogy ne helyezze a cron-feladatokat közvetlenül a szerver crontab fájljába. Hagyja, hogy a keretrendszer kezelje.

Ennek oka, hogy a telepítési mérnöknek / a Devops mérnöknek kell lennie az egyetlen olyan embernek, aki biztonsági okokból hozzáférhet ehhez a rendszerhez. Bár nem muszáj így megvalósítania, jó, ha már a kezdetektől fogva van valami.

A Django világban a zellerverés segítségével konfigurálhatja a cronokat zeller munkások segítségével.

Tudjon meg többet a zellerverésről itt - // docs.celeryproject.org/en/latest/userguide/periodic-tasks.html

A titkok megfelelő kezelése (paraméterfájl)

Nagyon sokféleképpen kezelheti a paraméter titkait a termelési kiszolgálókon. Néhány közülük:

  • Titkos fájl létrehozása és tárolása egy privát s3 vödörben, valamint az alkalmazás telepítése során történő meghúzása.
  • Paraméterek beállítása környezeti változókban az alkalmazás telepítése során (ismételt tárolás az s3-ban)
  • Helyezze a titkokat valamilyen titkos kezelő szolgáltatásba (pl. //Aws.amazon.com/secrets-manager/), és használja fel őket a titkok alkalmazásához.

Ezeknek a módszereknek bármelyikét választhatja kényelmi és használati esete szerint. (Kiválaszthatja a különféle titkos fájlok megőrzését a helyi, átmeneti és gyártási környezetek számára is.)

Verzió az API-k az első naptól

Ezt az első naptól kezdve mindenképpen fontolóra kell vennie. Soha nem fogja tudni, hogy üzleti modelljei milyen gyakran változhatnak, és alkalmazásának kompatibilisnek kell lennie előre és hátra. Szóval érdemes verziója az API-ja, hogy mindenki zökkenőmentesen működhessen.

Különböző verziókkal rendelkezhet különböző alkalmazásokkal, és hagyhatja, hogy az nginx kezelje az alkalmazásához. Vagy megverheti magát az alkalmazást, és hagyja, hogy az alkalmazáskiszolgáló útvonalai kezeljék. Bármelyik módszert kiválaszthatja annak megvalósítására - a lényeg az, hogy a verziókezelést már a kezdetektől engedélyezni lehessen.

Döntse el a hardveres és puha frissítések verzióellenőrzését az elülső ügyfelek számára

Tehát mi a különbség a kemény és a puha frissítések között?

A kemény frissítések arra utalnak, amikor a felhasználót arra kényszerítik, hogy az ügyfél verzióját magasabb verziószámra frissítse, mint ami a mobiljára telepítve van.

A friss frissítések arra utalnak, amikor a felhasználó figyelmeztetést kap arra, hogy új verzió érhető el, és ha akarják, frissíthetik alkalmazásukat az új verzióra.

A kemény frissítéseket nem javasoljuk, de vannak esetek, amikor érvényesíteni kell őket. Bármi legyen is az eset, mindenképpen meg kell fontolnia, hogyan fogja ezt megvalósítani az alkalmazásaihoz.

Ezt úgy teheti meg, hogy implementálja vagy konfigurálja a Play Áruházban vagy az App Store-ban. Egy másik módszer egy API létrehozása a háttéralkalmazásban, amelyet minden alkalommal elüt a mobilalkalmazás indítása. Ez két kulcsot küld: hard_update -> true / false és soft_update -> true / false, a felhasználó verziójától és a backend rendszerében beállított hard és soft frissítési verziótól függően.

A változatok tárolására jó hely a gyorsítótárban (Redis / Memcache), amelyet menet közben is megváltoztathat az alkalmazás telepítése nélkül.

Vezesse be a folyamatos integrációt (CI) az első naptól kezdve

Forgatókönyv - a projektben dolgozó egyik gyakornok nem elég jártas a termelési szintű kód megírásához. Lehet, hogy megváltoztattak valamit, ami megtörheti a projekt néhány kritikus elemét. Hogyan biztosíthatja, hogy minden ilyen rendben legyen ilyen esetekben?

Vezesse be a folyamatos integrációt. Minden egyes elkövetésnél foszlányokat és teszteseteket futtat, és megsérül, ha bármilyen szabályt megsértenek. Ez viszont megakadályozza, hogy a lekérési kérelem összevonásra kerüljön, amíg az összes szöszösítési szabály és teszteset át nem megy. Szép dolog, hogy van egy dolog, és ez hosszú távon is segít, ezért tartsd észben.

Nagyon sok lehetőség áll rendelkezésre a piacon. Vagy választhatja saját maga megvalósítását (Jenkins CI / CD), vagy használhatja a TravisCI, CircleCI stb.

Itt olvashat a TravisCI-n - //travis-ci.org/

És a CircleCI - //circleci.com/

Docker támogatás engedélyezése (személyes preferenciák)

Hozzon létre egy Dockerfile és docker-compose.yml fájlt az alkalmazásához, hogy mindenki a kezdetektől a Docker használatával futtassa az alkalmazást. Az ilyen megközelítés egyik fő oka az, hogy következetes legyen a helyi / rendezési / gyártási környezet, így egyetlen fejlesztő sem mondhatja ezt soha többé:

De a gépemen futott.

Nem nehéz az első naptól kezdve alkalmazni. Kezdetben csak a Dockert használja a helyi környezetben, hogy az alkalmazás beállítása nagyon zökkenőmentes legyen. De ne feledje, hogyan futtathatja mind Dockerrel, mind anélkül a gyártásban.

További információ a Docker Hubról - //hub.docker.com/

Használjon APM eszközt

Az alkalmazásfigyelő eszköz elengedhetetlenül szükséges, ha figyelni szeretné az alkalmazás API-ját, tranzakcióit, adatbázis-kapcsolatait stb.

Forgatókönyv - a cron szerver merevlemeze majdnem megtelt, és nem képes futtatni a cron feladatokat. Mivel nem talál helyet a lemezen, a cron-ok nem futnak. Tehát hogyan lehet értesítést kapni, ha ez megtörténik?

Nagyon sok APM eszköz használható ennek ellenőrzésére. Beállíthatja őket aszerint, hogy mikor kell értesítést kapnia. Értesítéseket kap a választott adathordozón, ha ilyen káosz történik a rendszerében - és hidd el, hogy ez mindig megtörténik. Tehát jobb felkészülni rá. Az Új ereklye jó lehetőség.

További információ az Új relikviáról itt - //newrelic.com/

Az ElasticSearch használatával az egész alkalmazásra kiterjedő kereséseket működtetheti az ügyfélalkalmazásokban

A wikipédia szerint

Az Elasticsearch egy keresőmotor, amely a Lucene könyvtárra épül. Ez egy elosztott, sokoldalúan képes teljes szövegű keresőmotort biztosít, HTTP webes felülettel és séma nélküli JSON dokumentumokkal. Az Elasticsearch Java fejlesztés alatt áll.

Az elején megkísérli a hagyományos adatbázis-lekérdezéseket, hogy eredményeket kapjon az ügyfélalkalmazás keresősávjában. Miért? Mert könnyű.

De a hagyományos adatbázisok nem ilyen teljesítő lekérdezésekre szolgálnak. Kitaláljon egy jó alkalmat a keresés áttelepítésére az ElasticSearch webhelyre és egy adatcsatorna bevezetésére a rendszerbe. Ez táplálja a rugalmas keresést adatokkal, majd összeköti a keresést az ElasticSearch-ről az alkalmazásszerverre.

Itt van egy jó áttekintés az Elasticsearchről az induláshoz.

És az ElasticSearch Docs - //www.elastic.co/guide/index.html

Helyezzen tűzfalat a termelési kiszolgálóra

Ezt mindenképpen meg kell tennie - ez kötelező. Helyezzen egy tűzfalat a termelési kiszolgálóra, és zárja be az összes portot, kivéve az API-khoz (https kapcsolatokhoz) használt portokat. Az API-végpontokat egy fordított proxy webszerver, például NGiNX vagy Apache használatával továbbítja. A külvilág számára csak az NGiNX által engedélyezett portok érhetők el.

Miért érdemes használni az NGiNX-et:

  • //www.nginx.com/resources/wiki/community/why_use_it/
  • //blog.serverdensity.com/why-we-use-nginx/
  • //www.freecodecamp.org/news/an-introduction-to-nginx-for-developers-62179b6a458f/

Csomagolás

A fent említett pontok a saját preferenciáimon alapulnak, és az évek során fejlesztettem őket. Itt-ott kis különbségek lesznek, de a koncepciók ugyanazok maradnak.

Végül mindezt azért tesszük, hogy a nulláról felépített sima rendszer a lehető leghamarabb működjön a gyártásban, miután előállt az ötlet.

Próbáltam vonásokat le minden tudásomat, amit szerzett az évek során, és talán tévedhet egy pár helyen .Azt f úgy gondolja, lehet ajánlani, jobb információkhoz , bátran megjegyzést. És mint mindig, kérjük ossza meg, ha úgy gondolja, hogy ez hasznos.