Երբևէ այցելե՞լ եք մեծ հանրախանութ ամանորին հաջորդող շաբաթը: Սովորաբար բացարձակ քաոս է տիրում. ամենուր հագուստի կույտեր կան, պիտակները բացակայում են, չափսերը խառնված են, բաժանմունքները՝ նույնպես: Կազմակերպվածության զրոյական զգացողություն կա: Դա հենց այն է, ինչ ձեր կայքը կզգար առանց ճիշտ կառուցվածքի 😅: Բայց ի՞նչ է կայքի կառուցվածքը, և ինչու՞ է այն այդքան կարևոր: Սկսենք հստակ սահմանումից`
«Կայքի կառուցվածքը վերաբերում է կայքի տեղեկատվական կառուցման պլանավորմանը և ձևավորմանը՝ կառուցվածքը հաստատելու և օգտագործելիությունը բարձրացնելու համար»։
Լավ նախագծված կայքը կարևոր է ավելի մեծ լսարանի հասնելու և ավելի շատ հաճախորդներ ներգրավելու համար: Երբ խոսքը գնում է հաջող առցանց հարթակ ստեղծելու մասին, օգտատերի փորձը և կայքում զետեղված տեղեկատվությունը պետք է լինի հնարավորինս պարզ: Դինամիկ վեբկայքի ստեղծումը թույլ է տալիս բարձրացնել էջի որակը, որպեսզի ավելի համապատասխան և գրավիչ լինի այցելուների համար:
Այսպիսով այսօրվա թեման կայքի կամ ներքին ծրագրերի կառուցվածքի մասին է, ինչպես նաև որոշ կարևոր գաղափարների, թե ինչպես կարելի է ճիշտ կազմակերպել կայքի ստեղծման աշխատանքը։ Կայքի զարգացմանն ուղղված քայլերով է կիսվել 7 տարվա փորձ ունեցող, բազմաթիվ հաջողված պրոյեկտների վրա իր ներդրումն ունեցած Բիվեբի Ավագ ծրագրավորողներից Հայկ Դալլաքյանը։
Բոլորս էլ գիտենք՝ ինչ է CRUD–ը: CRUD-ը հապավում է (create, read, update and delete), որը գալիս է ծրագրավորման աշխարհից և վերաբերում է չորս գործառույթներին ՝ ստեղծել, կարդալ, թարմացնել և ջնջել: Դրանք այն մինիմալ 4 բաժիններն են, որոնք թույլ են տալիս վեբ կայքերում կամ ներքին ծրագրերի մեջ պահել ինչ-որ ինֆորմացիա։
Այսօր խոսելու ենք հիմնականում read ֆունկցիայի մասին, որը պետք է օպտիմիզացնել։ Հիմնականում մեր բոլոր բաժիններում ունենում ենք այսպիսի ֆորմա (տես՝ նկար 1)` table, create button, որով որևէ item ենք ավելացնում, update, delete, view և search։
Search ֆորմայի պարագայում, read-ի ժամանակ մենք էջավորում ենք, ինչ-որ քանակ ենք վերադարձնում, search-ի պարամետր ենք գրում, կարողանում ենք search տալ և այլն։ Հետագայում, երբ մեր application-ը անընդհատ մեծանում է, մեր search-ի պարամետրերն էլ են շատանում։ Շատանում են այնքան, որ երբ մենք ինչ-որ պարամետրեր ենք որոնում, GET հարցում է ուղարկվում։
Երբ մենք սկսում ենք շատ պարամետրերով select անել, network-ում բավականին երկար տեսք ենք ունենում։
Սա չօպտմալիզացնելու դեպքում մենք կարող ենք ունենալ լուրջ խնդիր, և մեր հարցումը կարող է չկատարվել, որովհետև այդ GET հարցումների երկարությունը limitation ունի՝ 2048 սիմվոլ։
Նմանատիպ խնդիրներից խուսափելու համար առաջարկում եմ հետևյալը՝ search-ի պարամետրերը պահել տվյալների բազայում, պայմանական անուն տալ՝ search-forms collection։(տես՝ նկար 2)
Բնականաբար, այս պարագայում հիմնականում պետք է մուտք գործած լինենք, ունենանք user ID, form slag (ֆորմայի անունն է), search (օրինակ՝ JSON stringify արված ինֆորմացիա), relations (նույնպես JSON stringify արված ինֆորմացիա է, որին դեռ կանդրադառնանք):
Պատկերացնենք՝ այստեղ ունենք job application-ների էջ, ունենք մեկ collection` job applications, որտեղ հիմնականում պահվում է Job ID, Account ID ու մնացած որոշ պարամետրեր, որոնք կապված են job applications collection-ի հետ։Կան դեպքեր, երբ անհրաժեշտ է ֆիլտրել, օրինակ՝ ըստ job-ի տեսակի, user-ի երկրի, job-ի կազմակերպության տեսակի և այլն։ Search դաշտում մեր search տված պարամետրերը ավտոմատ կերպով պահպանվում են key-value հաջորդականությամբ, օրինակ`
{ title: “web developer”, jobType: 1, companyTitle: “beeweb” }
Երբ մենք ինչ-որ պարամետրերով, օր․՝ job title-ով որոնում ենք job application-ների մեջ, այդ ժամանակ առաջարկում եմ ստատիկ endpoint-ի հարցում ուղարկել և այս բազայում մեր բոլոր search պարամետրերը պահել, ինչից հետո search կոճակը սեղմելիս արդեն մեր հարցումը տեղի կունենա։
✔ Ի՞նչ է relation-ը և ինչի՞ համար է նախատեսված
Պատկերացնենք՝ հիմա job application-ից ցանկանում ենք վերցնել այն job application-ները, որոնց job-ի (աշխատանքի) տեսակը freelance է ( ID=1)։ Սովորաբար job application collection-ը join է արվում job-ի հետ, և եթե մեր job application-ում ունենք 100․000-ավոր միավորներ, ամեն մի միավոր join (lookup in MONGODB) է արվում job-ի հետ։ Դա բավականին մեծ ռեսուրս և ժամանակ է խլում Database-ից։
Այժմ եկեք հասկանանք, թե այս բոլոր relation-ները ինչի համար են: Job-ի տեսակի ID-ով մենք պետք է գտնենք ու բոլոր job-երի ID-ները մեր բազայում պահենք, այսինքն՝ Job ID-ները վերցնում ենք job-ից, տանում ենք այդ relations table-ից պահում ենք relations field-ի մեջ (Stringify արված)։ Ունենում ենք Job-երի ID-ներ: Դրանք կարող են լինել 1000-ներով։
Դիտարկենք այս 2 query-ների միջև տարբերությունը (տես՝ նկար 3, 4, 5 )․ առաջինում այս հարցումը կատարվում է միայն ID-ներով և կատարվում է շատ արագ, իսկ երկրորդ query-ում join է անում job-ի հետ և հետո որոնում ըստ jobType-ի։ Սա աշխատել է ընդամենը 0,011 վայրկյան, իսկ նա` 0,4։ Ստացվում է, որ սա մոտ 40 անգամ ավելի արագ է աշխատում։ Իմ առաջարկը հետևյալն է ՝ ինչպես որ մենք search ենք անում, մենք նախ պետք է գտնենք կոնկրետ այն property-ները job part-ը, որ job applicant-ը ունի և միայն դրանցով որոնենք։ Նախընտրելի է բոլոր job application-ների պարամետրերով որոնում կատարել, այնուհետև վերցնել limitation-ով, հետո join անել, քան հակառակը՝ join-ներ անել, որից հետո նոր որոնում կատարել և վերցնել limitation-ը։
✔ Multi language հնարավորություն
Հաջորդը անդրադառնանք վեբ կայքերի և soft-երի multi language (բազմալեզու) կառուցվածքին։ Ինչպե՞ս ճիշտ կազմակերպենք այս ամենը։
Առհասարակ ցանկացած նոր պրոեկտ սկսելիս, անգամ եթե մենք գիտենք, որ այն մեկ լեզվով է, ցանկալի է միշտ այն կառուցել բազմալեզու հնարավորությամբ։ Ինչպիսի՞ տեսք այն պետք է ունենա՝ languages table/collection։ Ես սա նախագծել եմ 3 լեզվի համար՝ հայերեն, ռուսերեն, անգլերեն։ Ինչ է այն ներառում՝ slug, am ru, en (այս ամենը գրվում է URL-ում), default, sort (սորտավորման համար է) և lable անվանում: (տես՝ նկար 6 )
Եկեք նախագծենք որևէ բաժին, օրինակ news, որը իր հերթին ունի հետևյալ field-երը՝ id, title, description, createdAt, updatedAt: Հիմա մենք ուզում ենք այն դարձնել բազմալեզու հնարավորությամբ, բոլոր այն field-երը որոնք չեն թարգմանվում մնում են news table֊ի մեջ (id, createdAt, updatedAt), իսկ մնացած field-երը որոնք թարգմանվում են առանձին table ենք պատրաստում table_content, որը ունենում է հետևյալ կառուցվածքը՝ id, news_id, language_id, title, description: Այստեղ news_id֊ն news table֊ի id֊ն է, language_id ֊ն, համապատասխանաբար, լեզվի id֊ն։ Հետևաբար եթե կայքը կառուցված է 3 լեզվով, ամեն մի news ավելացնելիս news table-ում ունենում ենք մեկ տող, իսկ table_content-ում՝ 3 տող: Այսինքն բոլոր table-ները/collection-ները, անգամ եթե մենք գիտենք, որ մեկ լեզվով ենք պատրաստում, ավելի լավ է այս կառուցվածքով պատրաստենք, որովհետև հնարավոր է մեկ տարի հետո մեր ծրագիրը զարգանա, երկրորդ լեզու ավելանա, հեշտ կարողանանք ավելացնել այս ամենը։ (տես՝ նկար 7, 8 )
Անգամ ստատիկ թարգմանությունները կարելի է պահել բազայում նման կառուցվածքով։
✔ Permissions
Հաջորդ բաժինը permission-ների վերաբերյալ է: Պատկերացրեք՝ ունենք ինչ-որ soft, ունենք գլխավոր ադմին, իսկ ադմինն էլ իր հերթին ունի իր օգնականները, յուրաքանչյուրին ցանկանում ենք ինչ-որ մեկ permission տալ։ Ունենք մեկ բաժին՝ օրինակ job application-ներ, մեկին ցանկանում ենք տալ դիտելու և ավելացնելու իրավունք, իսկ խմբագրելու և delete-ի իրավունք չենք ցանկանում տալ։ Մյուսին ցանկանում ենք տալ դիտելու իրավունք, իսկ խմբագրելու, ավելացնելու ջնջնելու հնարավորություն չենք տալիս։ Կամ մեկին տալիս ենք հաշվետվություններ export/import անելու իրավունք։
Պետք է ունենանք այսպիսի պայմանական permissions բաժին (table collection) , որտեղ պահելու ենք կոդ (ծրագրավորման համար է, որի միջոցով որոշելու ենք՝ տվյալ ադմինը իրավունք ունի որոշակի գործողության, թե ոչ) ու label (label-ը ուղղակի ինտերֆեյսը տեսնելու համար է)։ Լինելու են հետևյալ հնարավորությունները՝ add_news, edit_news, delete_news, view_news: Առնվազն 4 բաժին պետք է ունենա, եթե կառուցվածքը CRUD է։ Իսկ հավելյալ կարող ենք ունենալ export_news և import_news: Պետք է նաև ունենանք permission_group collection, որը ունենալու է ID և label: Հետևաբար պետք է ունենանք միջանկյալ collection` permission_group-ի և permissions-ի միջև, պայմանական անունը դնենք՝ permission_group_relations, որը ունենալու է field-եր, permission ID և permission_group-ի ID: Եվ արդեն մեր ադմինների մեջ, ով ունի օրինակ email, password, first name, մեկ field ենք ավելացնում՝ permission_group ID։
Ծրագրավորման առումով կարելի է ստեղծել ինչ-որ ֆունկցիոնալ, որը տվյալ կառուցվածքների միջից query-ների միջոցով կորոշի` տվյալ ադմինը իրավունք ունի՞, օրինակ, add_news permission-ի, թե ոչ։ Որոշ query-ների օրինակներ կարող եք տեսնել հետևյալ նկարներում։ (տես՝ նկար 9, 10 )
✔ Menu-ների մասին
Սկզբի համար մեզ անհրաժեշտ է տվյալների բազայից վերցնել բոլոր menu-ները, որոնց ամեն մի item-ը կունենա ID, parentID, label, որտեղ parent ID-ն ցույց է տալիս իր վերադաս մենյուի ID-ն։ Այն բոլոր մենյուները, որոնք ամենավերադասն են, իրենց parentID-ները կլինեն null: Տվյալները վերցնելուց հետո, որը մենք ունենում ենք զանգվածի տեսքով (Array), պետք է ստեղծել ռեկուրսիվ ֆունկցիոնալ, որը կնկարի մեր մենյուն։ (տես՝ նկար 11, 12, 13, 14)
✔ Դինամիկություն
Եվ վերջում խոսենք դինամիկությունից։ Պետք է աշխատենք այնպես կառուցել կայքը կամ soft-ը, որ այն հնարավորինս դինամիկ լինի։ Ինչքան այն դինամիկ դարձնենք, այնքան մի շարք խնդիրներ հեշտ կլուծվեն։
Շնորհակալ ենք Հայկին, մեզ հետ իր գիտելիքներով մանրամասն կիսվելու համար։ Հուսանք՝ հոդվածը շատերին ծանոթացրեց մի շարք մասնագիտական նրբությունների։😊
Կարդացեք նաև՝
Svelte JS՝ նոր մոտեցում User Interface ստեղծելու համար
Manual QA-ից Automation QA