Dalam proyek besar, tugas mengidentifikasi perubahan untuk pengguna akhir dengan perbedaan dalam kode aplikasi front-end dapat muncul. Pengembang dari Yandex.Market Nikita Sidorov @nickshevr memberi tahu bagaimana kami memecahkan masalah ini menggunakan pustaka Diffector, tentang membangun dan menganalisis grafik modul di aplikasi Node.js dan tentang menemukan cacat pada kode sebelum diluncurkan.

- Hari ini aku akan mencoba untuk berterus terang kepadamu.
Saya telah bekerja di Yandex.Market selama kurang lebih satu setengah tahun. Saya melakukan jumlah web yang sama, dan saya mulai melihat perubahan pada diri saya, Anda juga bisa melihatnya. Panjang rambut rata-rata saya meningkat dan janggut mulai muncul. Dan Anda tahu, hari ini saya melihat rekan-rekan saya: di Sergei Berezhnoy
berbelok , di Vova Grinenko
tadatuta , dan saya menyadari - ini adalah kriteria yang baik untuk apa yang hampir saya kembangkan sebagai pengembang front-end nyata.
Dan datang ke sumpah ini, saya memutuskan untuk berbicara dengan Anda tentang kehidupan, tentang kehidupan di mana kita semua berpartisipasi. Sebagian besar tentang kehidupan sebelum runtime. Sekarang saya akan menjelaskan tentang apa semua ini.

Bagaimana dengan kehidupan? Tentang kehidupan kode, tentu saja. Kode adalah apa yang kami lakukan. Biarkan saya mengingatkan Anda, saya memutuskan untuk tulus dengan Anda di sini, jadi slide pertama sesederhana mungkin. Saya mengambil kebenaran, tahap pertama - adopsi, Anda tahu, tidak ada yang akan berdebat dengan aksioma ini.

Dan kemudian saya menyadari bahwa saya harus memodifikasinya, tetapi supaya jelas. Biarlah semacam penerimaan persyaratan. Kode apa pun dimulai dengan fakta bahwa Anda melihat tugas dan mencoba menerima persyaratan yang membuat Anda.

Setelah itu, tentu saja, kita memulai tahap penulisan - kita menulis kode kita. Lalu kami menutupinya dengan tes, kami memeriksa efektivitasnya sendiri. Setelah itu, kami sudah memeriksa apakah aplikasi kami berfungsi dengan kode kami secara keseluruhan. Setelah itu, kami berikan ke tester - biarkan dia memeriksa. Apa yang Anda pikirkan setelah itu? Saya ingatkan Anda, kehidupan sebelum runtime. Apakah Anda pikir runtime mengikuti ini? Bahkan, ternyata begini. Dan ini bukan kesalahan dalam presentasi. Sangat sering pada setiap tahap pemeriksaan - dan mungkin ada lebih banyak dari yang saya sebutkan - Anda mungkin memiliki beberapa panggilan goto untuk menulis lagi. Setuju, ini bisa menjadi masalah yang cukup besar. Ini dapat memperlambat pengiriman beberapa fitur dalam produksi dan, pada prinsipnya, memperlambat Anda sebagai pengembang, karena tiket akan tergantung pada Anda. Dan di sini semuanya berlalu, berlalu. Ada beberapa kali M lagi untuk cek N, dan hanya kemudian kode sampai ke pengguna di browser. Tapi ini tujuan kami. Tujuan kami adalah menulis kode yang benar-benar akan tersedia bagi pengguna dan benar-benar berfungsi untuk keuntungannya.
Hari ini kita akan berbicara tentang bagian pertama. Tentang apa yang terjadi sebelumnya, tetapi tidak benar-benar tentang tes.

Ngomong-ngomong, tampilannya seperti ini. Aku mengambil giliran kami di pelacak, mengumpulkan milikku, menghitung median. Ternyata tiket saya jauh lebih sedikit dalam pengembangan daripada dalam memeriksa. Dan seperti yang Anda tahu, semakin lama di cek, semakin tinggi kemungkinan goto akan muncul di awal atau goto akan muncul di akhir - dan saya tidak ingin melakukan ini sama sekali.
Dan juga, jika Anda memperhatikan, ada dua kata di slide di sini - pengembangan (inilah yang kami lakukan, pengembang lakukan) dan verifikasi (inilah yang kami lakukan, tetapi juga penguji). Oleh karena itu, masalahnya relevan, pada kenyataannya, untuk penguji.

Tujuannya sangat sederhana. Secara umum, saya suka mengatakan bahwa hidup perlu disederhanakan: kami sudah banyak bekerja dengan Anda. Tujuannya terlihat seperti ini, tetapi Anda harus mengakui, itu agak sementara, jadi mari kita sorot beberapa kriteria dasar yang menjadi tujuan tujuan itu.
Tentu saja, semakin sedikit kode, semakin mudah bagi kita. Semakin cepat kita melakukan pemeriksaan CI, semakin cepat kita menyadari apakah kita benar atau tidak. Artinya, secara lokal, umumnya dapat dimulai selamanya. Kecepatan verifikasi - ini berlaku langsung ke tester. Jika aplikasi kita besar dan perlu diperiksa secara keseluruhan, ini adalah waktu yang sangat lama. Kecepatan rilis tergantung pada semua ini. Termasuk tidak mungkin untuk melepaskannya sampai kita telah melewati semua pemeriksaan, dan sampai kita mengerti bahwa kodenya persis seperti yang kita inginkan.
Untuk memecahkan beberapa masalah yang sedang kita bicarakan, mari kita menganalisis grafik dependensi modul dalam bahasa pemrograman kita. Dan, sebenarnya, mari kita gambarkan.

Grafik berorientasi: memiliki tepi dengan arah. Dalam node grafik, kita hanya akan memiliki modul bahasa yang sedang kita bicarakan. Iga adalah jenis ikatan khusus. Ada beberapa jenis komunikasi.

Mari kita lihat contoh biasa. Ada file A. Di sini, sesuatu dari file B diimpor ke dalamnya, dan ini adalah hubungan antara node.

Hal yang sama akan terjadi jika Anda mengganti impor dengan persyaratan. Faktanya, semuanya tidak begitu sederhana di sini.

Saya menyarankan, karena kita berbicara tentang jenis ketergantungan, pertimbangkan dua jenis setidaknya - untuk mempercepat pipa Anda, untuk mempercepat grafik traversal. Penting untuk menonton tidak hanya modul dependen, tetapi juga modul dependen. Saya mengusulkan untuk memanggil modul A - orang tua, B - anak, dan saya menyarankan Anda untuk selalu menjaga tautannya sebagai daftar yang ditautkan ganda. Ini akan menyederhanakan hidup Anda, saya informasikan sebelumnya.
Setelah kami mendeskripsikan grafik, mari kita sepakati bagaimana kami akan membangunnya.

Ada dua cara. Entah alat favorit Anda dalam bahasa pemrograman favorit Anda menggunakan AST yang sama (pohon sintaksis abstrak) atau tetap. Apa untungnya di sini? Fakta bahwa di sini Anda tidak terikat dengan siapa pun, tetapi pada saat yang sama Anda harus menerapkan semuanya sendiri. Anda harus menggambarkan semua jenis koneksi dari semua hal dan teknologi yang Anda gunakan, apakah itu kolektor CSS yang terpisah, sesuatu yang lain seperti itu. Tetapi Anda memiliki kebebasan penuh untuk terbang.
Selain itu, opsi kedua, saya juga akan mempromosikannya sedikit, ini adalah opsi hanya untuk kebanyakan orang yang sudah memiliki sistem build yang dikonfigurasi. Faktanya adalah bahwa sistem perakitan mengumpulkan grafik tergantung pada desain, secara default.

Mari kita lihat salah satu sistem perakitan paling populer di Yandex, ini adalah webpack. Di sini saya memberi contoh bagaimana Anda dapat mengumpulkan seluruh hasil webpack ke file terpisah, yang kemudian dapat dimasukkan ke kami atau beberapa penganalisa lain. Dia mengumpulkannya dengan bantuan AST, perpustakaan pohon ek digunakan. Anda mungkin telah memperhatikannya ketika sesuatu telah jatuh. Saya perhatikan.
Dan apa kelebihannya. Faktanya adalah ketika Anda mendeskripsikan sistem build Anda, Anda benar-benar secara jujur ββmeminta entri. Ini adalah file-file yang darinya dependensi Anda dicabut, titik pintas awal. Ini bagus, karena Anda tidak perlu merekamnya lagi. Selain itu, webpack dan babel, dan semua ini, dan biji, termasuk, masih belum Anda pertahankan. Dan oleh karena itu, semua jenis fitur baru bahasa, semua jenis bug dan yang lainnya, diperbaiki lebih cepat daripada jika Anda melakukannya, terutama jika Anda tidak memiliki tim yang sangat besar. Ya, meskipun itu besar, maka itu tidak sebesar open source.
Faktanya, ini adalah plus dan minus. Sepertinya ujung ganda (pedang bermata dua) diperoleh. Faktanya adalah bahwa grafik ini dibangun selama perakitan. Agak bagus, yaitu, kita dapat mengumpulkan proyek dan segera menggunakan kembali hasil perakitan. Tetapi bagaimana jika kita tidak ingin membuat proyek, tetapi hanya ingin mendapatkan grafik ini?
Dan minus besar seperti itu, sebenarnya. Jika Anda memiliki hal-hal khusus yang terhubung, kami akan berbicara banyak tentang koneksi nanti, maka sistem build tidak akan membiarkan Anda melakukan ini. Atau, Anda harus mengintegrasikan ini, seperti plugin webpack Anda.

Pertimbangkan contoh spesifik. Saya menjalankan perintah pada proyeksi saya, di mana hanya ada tiga file, dan mendapat output ini. Dan ini saya hanya menunjukkan satu kunci, yang disebut modul. Kami hanya berbicara dengan Anda tentang grafik dependensi modul, jadi kami melihat modul, semuanya logis.

Cukup banyak informasi, tetapi kami tidak membutuhkan semuanya. Tinggalkan beberapa poin dan mari kita bicarakan. Misalkan kita mempertimbangkan modul pertama. Dia punya nama, ada alasannya. Alasannya hanya koneksi, pada kenyataannya, dengan modul "tergantung", ternyata mereka yang mengimpor modul ini untuk diri mereka sendiri. Ini adalah data dasar untuk membuat grafik di atasnya.

Selain itu, harap perhatikan SportsEkspor bekas danEkspor yang disediakan. Kami akan membicarakannya nanti. Tetapi ini juga hal yang sangat penting.


Dan jika Anda menggambarkan keputusan Anda, maka Anda perlu berbicara tentang jenis koneksi yang terjadi antar modul. Yaitu, kita memiliki, tentu saja, sistem modul kita di dalam bahasa kita: apakah itu cjs-modules, atau esm-modules. Selain itu, Anda harus setuju bahwa kami mungkin memiliki koneksi antara file dalam sistem file di tingkat sistem file itu sendiri. Ini adalah semacam kerangka kerja: semacam kerangka kerja akan tergantung pada bagaimana ayah adalah.

Dan contoh yang biasa - jika Anda menulis sisi server Node, maka cukup sering Anda bisa melihat paket npm populer seperti Config. Ini memungkinkan Anda untuk dengan mudah menentukan konfigurasi Anda.

Untuk menggunakannya, Anda perlu mendapatkan folder konfigurasi, di mana Anda memiliki NODE_PATH, dan tentukan beberapa file JavaScript - hanya untuk menyajikan konfigurasi di sana untuk lingkungan yang berbeda. Sebagai contoh, saya membuat ayah, standar yang ditentukan, pengembangan dan produksi.

Dan, pada kenyataannya, seluruh konfigurasi bekerja seperti ini. Artinya, ketika Anda menulis membutuhkan ('config'), itu hanya membaca modul di dalam dirinya sendiri dan mengambil nama modul dari variabel lingkungan. Seperti yang Anda pahami, tidak jelas di sana bahwa file-file ini entah bagaimana digunakan, karena tidak ada impor / persyaratan langsung, webpack bahkan tidak akan mengenalinya.

Hari ini kita juga berbicara tentang Injeksi Ketergantungan. Saya bukan sesuatu yang diilhami, tetapi dalam dukungan saya melihat salah satu perpustakaan di sini. Ini disebut inversify JS. Seperti yang Anda lihat, ini menyediakan sintaks yang agak khusus: lazyInject, nameProvider, dan ini dia. Dan, Anda harus mengakui, tidak jelas penyedia apa itu, modul apa yang benar-benar disuntikkan di sini. Dan kita membutuhkannya, dan kita harus memahaminya. Sekali lagi, sistem pembangunan tidak akan terpecahkan, dan kita harus melakukannya sendiri.
Misalkan kita telah membuat grafik, dan saya sarankan Anda mulai dengan menyimpannya di suatu tempat. Apa yang akan memungkinkan kita melakukan ini? Ini akan memungkinkan kita untuk melakukan semacam analisis heuristik, memainkan sedikit Ilmu Data, dan melakukannya, dengan fokus pada sepotong waktu.

Apa idenya? Di sini, memang, secara langsung data kami. Kami baru saja menerapkan sistem desain kami di Yandex.Market dan, khususnya, menerapkan perpustakaan komponen sebagai bagian dari sistem desain ini. Dan di sini Anda dapat melihat: kami mempertimbangkan jumlah impor, komponen reaksi dari perpustakaan kami, komponen umum. Dan Anda dapat mendistribusikan di direktori. Dalam hal ini, kami memiliki repositori non-mono, dan karenanya kami memiliki platform.desktop, platform.touch dan src.
Apa yang bisa kita pikirkan ketika kita melihat angka-angka ini? Kita dapat berhipotesis bahwa perintah sentuh tampaknya tidak meningkatkan penggunaan komponen umum. Ini berarti komponennya buruk untuk ponsel - dibuat dengan buruk, atau perintah sentuhnya malas. Tapi benarkah demikian?

Jika kita melihat dalam periode yang lebih lama, dalam waktu yang lebih lama, ini memungkinkan kita untuk melakukan penyimpanan grafik setelah setiap rilis, maka kita akan memahami bahwa, pada kenyataannya, semuanya ok untuk disentuh, indikator semakin berkembang di dalamnya. Untuk src, ini lebih baik, untuk desktop, ternyata tidak.

Masih ada pertanyaan dari audiens bagaimana menjelaskan kepentingan manajer. Berikut adalah jumlah total impor perpustakaan, juga berdasarkan waktu. Manajer mana yang tidak suka grafik? Anda dapat membuat jadwal seperti itu dan melihat bahwa penggunaan perpustakaan bertambah, yang berarti bahwa ini setidaknya merupakan hal yang bermanfaat.
Salah satu bagian favorit saya. Saya akan membahasnya secara singkat. Ini adalah pencarian cacat pada grafik. Hari ini saya ingin berbicara dengan Anda tentang dua jenis cacat: ini adalah ketergantungan siklikal dari modul dan beberapa modul yang tidak digunakan, yaitu masalah penghilangan kode mati.

Mari kita mulai dengan ketergantungan melingkar.

Segalanya tampak sangat sederhana di sini. Anda sudah memiliki grafik yang diarahkan, Anda hanya perlu menemukan lingkaran di sana. Saya akan menjelaskan mengapa saya membicarakan hal ini. Faktanya adalah bahwa sebelum saya menulis, pada dasarnya, sisi server pada Node.js, dan kami tidak menggunakan, pada prinsipnya, webpack / babel, tidak ada. Artinya, mereka diluncurkan apa adanya. Dan ada yang membutuhkan. Siapa yang ingat bagaimana impor berbeda dari yang dibutuhkan? Semuanya benar. Jika Anda menulis kode dengan buruk, tetapi saya benar-benar melakukannya, Anda dapat mengetahui di server Anda bahwa modul Anda berada dalam semacam ketergantungan siklus hanya ketika beberapa permintaan datang dari pengguna, atau acara lain akan berfungsi. Itu adalah masalah yang agak global. Sampai runtime tidak mengerti. Artinya, impor jauh lebih baik, tidak akan ada masalah seperti itu.

Kemudian ambil saja algoritma yang Anda suka. Di sini saya mengambil algoritma yang cukup sederhana. Kita perlu menemukan simpul yang hanya memiliki satu jenis tepi - baik inbound atau outbound. Jika ada titik seperti itu, kami menghapusnya, menghapus tepi, dan, pada kenyataannya, melanjutkan proses ini, kami akan menemukan dan membuktikan bahwa ada siklus lima siklus dalam grafik ini.
Setuju, jika Anda melihatnya dengan kode, yaitu, di sana Anda masih dapat menemukan siklus dua atau tiga panjang, tetapi lebih tidak realistis, dan kami benar-benar memiliki siklus tujuh di proyek, tetapi tidak dalam produksi.

Tentang modul yang tidak digunakan. Ada juga algoritma yang agak sepele. Kita perlu menyorot komponen yang terhubung dalam grafik kita, dan lihat saja, cari komponen-komponen itu, yang tidak termasuk salah satu node entri. Dalam hal ini, ini adalah komponen keterhubungan, kedua simpul, ternyata, kedua node. Kemudian disebut entry.js. Sebenarnya, tidak peduli apa namanya, ini adalah apa yang telah Anda gambarkan dalam konfigurasi assembly entri.

Tetapi ada pendekatan lain. Jika Anda belum mengumpulkan grafik, dan Anda hanya memiliki sistem build, lalu bagaimana cara termurah untuk melakukannya? Mari kita tandai semua file yang masuk ke perakitan selama perakitan. Tandai dan buat banyak. Setelah itu, kita harus mendapatkan banyak semua file yang Anda miliki di proyek, dan cukup kurangi. Itu adalah operasi yang sangat sederhana.

Dan sekarang saya tidak hanya mengatakan sesuatu yang teoretis kepada Anda, saya terinspirasi, datang ke proyek saya, dan melakukan ini. Dan perhatian! Saya bahkan tidak menghapus node_modules. Ini saya tinggalkan sebagai titik pertumbuhan untuk ulasan selanjutnya. Singkatnya, saya sangat terinspirasi oleh diri saya sendiri sehingga saya memutuskan untuk membuat slide ini, mengaturnya kembali. Biarkan terlihat seperti ini, karena ini sangat keren!
Angka yang bagus, dapatkah Anda bayangkan bagaimana semuanya menjadi baik? Dan kemudian saya didorong ke padang rumput sehingga saya merasa seperti seorang desainer, dan berpikir bahwa ini adalah pencapaian yang ingin saya tambahkan ke bingkai. Dan, seperti yang Anda tahu, saya bangun, melihat dan menyadari bahwa saya lebih cenderung bukan perancang, tetapi, memang, seorang pengembang web. Tapi aku bukan orang bodoh. Saya mengambil bingkai ini, ditambahkan ke situs saya untuk jimat SEO.

Anda dapat menggunakan, bahkan tautannya. Dan agar Anda tidak berpikir bahwa saya menipu Anda - kami jujur ββhari ini - saya benar-benar melihat ulasan. Saya pikir Anda bisa mempercayai mereka.

Sejujurnya, terlihat seperti ini. Saya melihat perpustakaan hypo thanos-js, mengambilnya, membuat permintaan kumpulan. Secara rahasia, saya memiliki hak administrator di repositori kami. Dan saya mengambil dan membingungkan tuannya. Bagaimana kamu suka itu? Ya, Anda dan saya jujur, dan, pada kenyataannya, semuanya tampak seperti ini. Jika ada yang tidak tahu, thanos-js adalah pustaka yang hanya menghapus 50% kode Anda secara acak.

Sebenarnya, saya menggunakan perpustakaan di sana, tetapi perpustakaan itu disebut berbeda. Itu disebut diffector, dan sekarang kami akan membicarakannya dengan Anda. Dan di sini saya ingin mencatat bahwa permintaan kumpulan cukup signifikan, minus 44 ribu baris kode, dan Anda bisa bayangkan - itu lulus ujian pertama kali. Artinya, apa yang saya bicarakan benar-benar dapat bekerja.

Penyebar Bahkan, ia terlibat tidak hanya dalam tugas mengeluarkan modul yang tidak digunakan, mencari cacat dalam grafik, tetapi juga dalam tugas yang lebih penting. Apa yang awalnya saya nyatakan adalah untuk membantu pengembang dan penguji, sekarang kita akan membicarakannya. Dan kerjanya kira-kira seperti ini.
Kami mendapatkan daftar file yang dimodifikasi menggunakan sistem kontrol versi. Kami telah membuat grafik - diffector membangunnya. Dan untuk setiap file yang dimodifikasi tersebut, kami mencari jalur masuk dan menandai entri yang dimodifikasi. Dan entri akan berhubungan dengan halaman aplikasi yang akan dilihat pengguna. Tapi ini cukup logis.
Dan apa ini memberi kita? Untuk pengujian - kami tahu halaman mana dalam aplikasi yang telah berubah. Kami dapat memberi tahu tester bahwa hanya mereka yang layak untuk diuji. Kami juga dapat memberi tahu ci-job kami, yang menjalankan autotest, bahwa hanya halaman ini yang layak untuk diuji. Dan untuk pengembang, semuanya jauh lebih sederhana, karena sekarang penguji tidak menulis kepada Anda dan tidak bertanya: "Mengapa Anda perlu menguji?"

Mari kita lihat contoh bagaimana diffector bekerja. Di sini kita memiliki direktori tertentu, pages.desktop / *. Itu hanya berisi daftar halaman itu sendiri. Dan halaman-halamannya juga dijelaskan oleh beberapa file. Pengontrol adalah sisi server dari halaman. Lihat adalah semacam bagian reaksi. Dan deps, ini dari sistem build lain. Kami tidak hanya memiliki webpack, tetapi juga ENB.

Dan saya membuat beberapa perubahan pada proyek, ke file kosong, struktur yang Anda lihat. Inilah yang memberi saya diffector. Saya baru saja memulainya, diffector adalah aplikasi baris perintah. Saya meluncurkannya, dia memberi tahu saya bahwa saya telah mengubah satu halaman, yang disebut BindBonusPage.

Saya juga dapat menjalankannya dalam mode verbose, melihat laporan yang lebih rinci, dan benar-benar melihat bahwa itu setidaknya berfungsi dalam kasus yang sangat sederhana. Seperti yang kita lihat, di BindBonusPage kita file indeks dan pengontrol telah berubah.
Tapi mari kita lihat apa yang terjadi jika kita mengubah sesuatu yang lain.

Saya mengubah sesuatu yang lain. Dan difektor mengatakan kepada saya bahwa saya telah mengubah sembilan halaman. Dan ini tidak membuat saya bahagia lagi, seolah-olah dia tidak akan membantu saya.

Mari kita lihat mengapa? Sekarang menunjukkan alasan mengapa halaman ini dianggap dimodifikasi. , . - uikit.

diff. . , diffector . , - , .

, , . , , entry, , , test-scope, . .
. , , , , .

. - , . β i18n, , . , , , . , , - .
? , , , , , .

- . , B , , -2 . . , esm.

.

.

, value, . , , . , .
, AST, , 250 , , . , , - , , .

, - GlobalContext - , . , modify, , ? , - GlobalContext. . . , side effects. , , webpack, , . , webpack sideEffects: true, . .

, - - . , . diffector, . , , . β , . , .
, , diff, expand, log, , , , .

, . D, diff. , , , . , , . , , . .
, , . . . , β , . . . , , , , , . . , .
β diffector ? , , , .

- , , .

, , entry. entry. diffector.

. -. , .

, entry -, .

. diffector. . , , - , -. , . : , BindBonusPage, -, . . , , - . .


β CI. . : , , .

, . 43 β testing, , .

. , , .

, . : , , . , , , , , . , , - .

. , , , . - , - , , , . .
, , , output . , . β . β . Terima kasih