Pertama, beberapa komentar tentang jejak artikel sebelumnya. Kami dulu pernah bekerja di
Wargaming , tempat kami mengembangkan mesin yang dikenal sebagai
dava.framework atau
dava.engine . Oleh karena itu, banyak kolega lama, dengan siapa kita masih berada dalam hubungan yang baik, secara aktif berpartisipasi dalam diskusi.
Sejumlah orang memiliki keraguan: apakah ini teknologi yang sama atau yang lain? Jawab: ini adalah teknologi baru yang ditulis dari awal.
Bagaimana kami mengelola hanya dalam setahun? Tim kami memiliki pengalaman luas. Banyak yang telah mengembangkan mesin dan game selama lebih dari 15 tahun.
Kenapa dari awal, jika Anda bisa mengambil mesin lama kami, yang juga terletak di open-source? Dia berumur sekitar 10 tahun, dan sebagian besar kode sudah usang. Bahkan bagian-bagian terbaik dari mesin, yang kami banggakan, kadang-kadang berisi potongan-potongan kode dan beberapa dasar 5, 7 dan kadang-kadang bahkan 10 tahun yang lalu. Banyak solusi arsitektur yang dirancang untuk perangkat pada waktu itu - dimulai dengan iPhone 3G. Sekarang kita fokus setidaknya pada iPad Air 1 dan perangkat Android yang memiliki kekuatan serupa. Oleh karena itu, pendekatannya agak berubah.
Dan pertanyaan paling umum: mengapa mesin sendiri? Dalam artikel terakhir, ada beberapa argumen dengan tingkat persuasi yang berbeda-beda. Saya ingin berkonsentrasi pada hal utama: hanya teknologi kami sendiri yang memungkinkan Anda untuk mendapatkan yang terbaik dari besi, membuat jumlah maksimal pengoptimalan khusus untuk gameplay Anda, gaya visual. Kami memposisikan diri, termasuk sebagai perusahaan teknologi, bukan hanya pengembang game. Kami percaya bahwa dengan tingkat insinyur dan pengalaman kami, kami dapat bersaing secara serius di pasar produk seluler berteknologi tinggi.
Dan sekarang pada intinya: alat dan teknik apa yang telah membantu kita menyelesaikan tugas yang agak ambisius ini dalam waktu singkat?
Infrastruktur
Kami memilih Atlassian Bitbucket Server + Jenkins. Di Bitbucket terletak repositori utama (master), yang terhubung dengan Jenkins. Setiap pengembang memiliki garpu sendiri. Untuk setiap tugas, garpu baru dibuat di garpu, yang diintegrasikan kembali melalui permintaan tarik. Secara umum, skema ini cukup standar. Setiap permintaan penarikan menjalani tinjauan wajib dan tes otomatis. Dan, jika berhasil, secara otomatis bergabung ke master.
Jenkins
Jenkins memiliki beberapa kekurangan: dia adalah moncong web kuno, tidak terlalu cepat, rakus, seperti portal Internet dari tahun 90-an. Namun, fleksibilitasnya, sejumlah besar modul dan bebas biaya menjadikannya pilihan yang baik bahkan pada tahun 2019. Setelah bermain dengan modul dan pengaturan, Anda dapat mencapai tampilan yang dapat dicerna, deskripsi deklaratif dari pipa (berbaring di repositori). Omong-omong, ada sekitar 40 saluran pipa sekarang: tes, editor, permainan untuk semua platform; bekerja dengan infrastruktur server dan metagame. Kumpulkan semuanya 20 buildagentov.
Di masa depan, tentu saja, saya ingin mencoba solusi hipster modern, misalnya GitLab atau TravisCI yang dikelola sendiri. Kami tidak mempertimbangkan sepenuhnya solusi cloud (Nevercode, Bitrise, CircleCI, dll.) Karena besarnya repositori, aset, dan, karenanya, waktu pembuatan dan ukuran artefak.
Membangun sistem
Persyaratan utama untuk sistem adalah sebagai berikut: pembuatan proyek untuk iOS, MacOS, Android, Windows, Linux dalam satu skrip. Kami berhasil mencoba Premake, SCons, Bazel, dan CMake. Karena berbagai alasan, kami berhenti di CMake yang teruji waktu.
Dalam beberapa tahun terakhir, CMake hampir menjadi standar untuk pustaka C ++. Hampir semuanya mulai dari abseil hingga SDL dapat dihubungkan ke proyek CMake Anda hanya dalam beberapa baris. Tentu saja ada pengecualian, seperti OpenSSL atau V8, yang saya harus sedikit berkeringat. Di atas Zmeik telanjang kami mengembangkan kerangka kecil (total sekitar 3.000 baris). Fitur utama:
Modularitas. Masing-masing bagian mesin dirancang sebagai modul. Misalnya, suara, UI, fisika, jaringan, dll. Setiap modul dapat memiliki aset sendiri (misalnya, shader) dan mungkin memiliki ketergantungan pada modul lain.
Aplikasi terakhir pada engine (gim, editor, utilitas) hanya menghubungkan modul-modul yang dibutuhkannya. Sedikit terpisah adalah modul inti, yang merupakan ketergantungan untuk sebagian besar modul lainnya. Core mengimplementasikan titik masuk, siklus aplikasi utama, interaksi dengan sistem operasi dan entitas dasar lainnya.
Modul pihak ketiga. Kerangka kerja kami memungkinkan Anda untuk mengunduh repositori git atau arsip dalam beberapa baris, membongkar, mengkompilasi, menyalin pustaka dan / atau sumber. Hari ini kami memiliki 66 modul pihak ketiga tersebut: analitik, format file pihak ketiga, middleware seperti fisika, perpustakaan suara, dll.
Proses pengembangan
Berdasarkan pengalaman sebelumnya, kami memutuskan untuk menambahkan engine dan game ke dalam satu repositori. Hal ini memungkinkan Anda untuk membuat perubahan pada API engine tanpa rasa sakit dan menyesuaikan game secara sinkron untuknya. Hasilnya adalah monorepositori yang disebut dengan kelebihan dan kekurangannya. Tapi, karena kami segera berencana untuk mempertahankan kecepatan pengembangan yang sangat tinggi, kemungkinan refactoring sinkron dari mesin dan permainan melebihi semua kelemahan lain dari solusi ini.
Rata-rata, kami menambahkan lebih dari 20 permintaan tarik per hari. Ini berarti bahwa master berpotensi rusak 20 kali sehari. Untungnya, pada tahun 1991, mereka datang dengan teknik Integrasi Berkelanjutan. Untuk apa kita datang?
Integrasi berkelanjutan
Seperti disebutkan di atas, brunch dibuat untuk setiap tugas di cabang pengembang. Selanjutnya, permintaan tarik dibuat dari brunch ini ke repositori utama. Permintaan penarikan ini melewati serangkaian tes otomatis di Jenkins:
- Tes unit untuk semua platform (windows, linux, macos, ios, android). Googletest digunakan sebagai dasar, dan OpenCppCoverage, yang laporannya diperiksa oleh skrip python tambahan, digunakan untuk memeriksa persentase cakupan. Jika persentase cakupan untuk file tertentu kurang dari 75%, tes dianggap gagal. Dengan demikian, kami telah membahas sebagian besar kelas engine tingkat rendah dengan pengujian.
- Pemformat kode Untuk kode C ++ kami menggunakan format dentang. Pemformatan kode yang diubah pertama kali secara otomatis terjadi ketika melakukan pada mesin pengembang, dan kemudian diperiksa dalam pengujian. Untuk javascript, yang digunakan sebagai bahasa scripting, npm linter digunakan.
- Tes Aset. Sekelompok tes yang cukup besar: dari memvalidasi format file hingga memeriksa dependensi (misalnya, memeriksa apakah tekstur yang digunakan di level gim memang ada).
- Tes unit dan fungsional editor. Bagian integral dari mesin adalah editor, di mana level game dan aset lainnya dibuat dan diedit. Selain tes unit, Squish froglogic untuk Qt digunakan untuk menguji editor - utilitas untuk pengujian GUI otomatis. Semua ini memungkinkan kita untuk melakukannya tanpa pengujian manual dari editor. Selain itu, menurut ulasan seniman dan desainer level, tingkat kualitas dan stabilitasnya lebih tinggi daripada di perusahaan sebelumnya, ketika kami memiliki tim yang terdiri dari lima penguji. Pada saat yang sama, rilis terjadi setiap hari, dan dengan pengujian manual, rilis terjadi setiap 2 minggu.
- Tes fungsional permainan. Jelas saya ingin menggunakan tes fungsional otomatis untuk game. Oleh karena itu, kami mulai mengembangkan sistem berikut:
- aplikasi uji (khusus - skrip python) meluncurkan server permainan dan klien dengan parameter tertentu
- menjalankan server dan klien membuka port jaringan,
- Aplikasi tes terhubung dengan mereka dan mengirimkan perintah: unduh peta, pilih karakter dan senjata, pindah ke satu titik, membidik, menembak, dll.
- sintaks tes itu sendiri adalah python pytest. Sistem ini sedang dalam pengembangan aktif.
Sebagian besar proyek untuk pengujian dikumpulkan dengan bendera "perlakukan peringatan sebagai kesalahan" dihidupkan, dan pada platform MacOS dengan AddressSanitizer dentang juga diaktifkan, yang memungkinkan Anda untuk menangkap lebih banyak kesalahan pada tahap mempersiapkan permintaan tarik.
Selain tes, setiap permintaan tarik ditinjau oleh setidaknya dua pengembang lain dan, jika perlu, dikirim untuk revisi. Ketika semua tes telah selesai dan pengulas tidak memiliki komentar, permintaan tarik otomatis membeku.
Karena beberapa tes dapat memakan waktu yang cukup lama (misalnya, tes editor GUI lengkap berlangsung lebih dari satu jam), skrip pendek digunakan dalam permintaan tarik. Set lengkap pengujian diluncurkan di wizard setiap 4 jam.
Hingga saat ini, 6.600 pull-quest telah dibuat dan diadakan sedemikian rupa.

Pengiriman terus menerus
Kami menggunakan konsep rilis harian otomatis (atau lebih tepatnya harian). Bagaimana tepatnya hal ini terjadi:
- tag git dibuat,
- itu menjalankan versi lengkap dari semua tes,
- jika berhasil, artefak dikumpulkan:
- editor untuk MacOS dan Windows. Jadi, setiap pagi setiap orang memiliki versi alat yang baru. Dan, berkat pengujian otomatis, kami yakin akan kualitas dan stabilitasnya.
- klien game dan server untuk semua platform. Klien untuk iOS diunggah ke TestFlight, untuk Android - ke Google Play, platform lain - ke JFrog Artifactory, server game, dan layanan lainnya - ke cloud. Artinya, setiap pagi kami memiliki versi baru dari permainan, siap untuk pengujian dan uji coba.
Tentu saja, tidak setiap rilis malam berakhir dengan sukses. Beberapa tes mungkin gagal, atau kesalahan kritis akan terjadi pada permulaan aplikasi. Dalam hal ini, masalah yang ditemukan diperbaiki oleh pengembang yang bertugas siang hari dan proses rilis dimulai kembali.
Ada beberapa yang bertugas setiap hari:
- Petugas tingkat 1. Mengawasi stabilitas tes dalam repositori utama.
- Petugas level 2 di game. Memperbaiki bug game.
- Petugas level 2 di redaksi. Memperbaiki bug editorial, menyarankan pengguna (artis, desainer level, desainer game).
Juga pada hari tugas, Anda dapat terlibat dalam hutang teknis: tambahkan tes yang hilang untuk fungsi lama, melengkapi dokumentasi, atau melakukan refactoring, yang tidak memakan waktu selama perencanaan rilis biasa.

Pada artikel selanjutnya, kita akan melihat lebih dekat arsitektur perangkat lunak dari mesin itu sendiri, serta modul utama dan subsistemnya.
Dilanjutkan ...
Bagian pertama:
habr.com/en/post/461623