Bagaimana kami memecahkan pondok tua itu dan membangun gedung pencakar langit di tempatnya

Zurab Bely, ketua tim, praktik Jawa, menceritakan kisahnya bekerja di sebuah proyek untuk satu perusahaan besar dan berbagi pengalamannya.

Bagaimana saya menetap ...


Saya masuk ke proyek pada akhir musim panas 2017 sebagai pengembang biasa. Saya tidak bisa mengatakan bahwa pada waktu itu saya sangat menyukainya: teknologi yang digunakan dalam proyek sudah tua, komunikasi dalam tim diminimalkan, komunikasi dengan pelanggan sulit dan tidak produktif. Jadi proyek itu bertemu saya. Pada saat itu, saya hanya memiliki satu keinginan: untuk keluar darinya dengan cepat.

Saya akan memberi tahu Anda sedikit tentang proyek secara keseluruhan. Ini adalah portal resmi satu perusahaan besar dengan informasi umum, berita, promosi, dan konten lainnya. Semua nawala pemasaran berisi tautan ke halaman-halaman tertentu di situs, yaitu, bebannya stabil secara rata-rata, tetapi pada titik waktu tertentu dapat mencapai nilai tinggi. Stabilitas dan aksesibilitas aplikasi web membutuhkan perhatian khusus - setiap menit downtime layanan menyebabkan kerugian besar bagi pelanggan.

Shanty yang menyipit tertiup angin


Pada awalnya, saya terutama mempelajari kondisi teknis proyek, memperbaiki bug kecil dan membuat perbaikan kecil. Dari sudut pandang teknis, aplikasi tampak mengerikan: arsitektur monolitik yang dibangun di sekitar versi komersial dotCMS, kode yang ditulis dalam versi Java 6, ketika rendering sisi server kesembilan dari bagian klien pada kerangka kerja Velocity, yang belum beberapa tahun saat itu, telah dirilis didukung. Setiap instance diluncurkan di JBoss AS dan dialihkan menggunakan Nginx. Kebocoran memori menyebabkan restart terus-menerus dari node, dan kurangnya cache normal menyebabkan peningkatan beban server. Tapi sempalan terbesar adalah perubahan yang dilakukan pada kode CMS. Mereka mengesampingkan kemungkinan peningkatan tanpa rasa sakit ke versi yang lebih baru. Ilustrasi yang baik tentang hal ini adalah transisi dari versi 3.2 ke 3.7, yang baru saja berakhir pada saat itu. Transisi ke versi minor berikutnya membutuhkan waktu lebih dari satu tahun. Tidak ada solusi populer, seperti Spring Framework, React.js, arsitektur microservice, Docker, dll. Masuk lebih dalam ke proyek, konsekuensi dari kondisi teknis seperti itu menjadi jelas. Yang paling akut adalah ketidakmampuan menjalankan aplikasi secara lokal untuk pengembangan dan debugging. Seluruh tim yang terdiri dari 8 orang bekerja di satu stan pengembangan, di mana salinan versi produksi aplikasi dikerahkan. Dengan demikian, hanya satu pengembang yang dapat men-debug kode mereka pada saat yang sama, dan menggulirkan kode yang diperbarui memblokir seluruh tim. Apogee adalah penjualan yang gagal, di mana jutaan surat, SMS dan pemberitahuan push dikirim ke pengguna yang berbeda melalui puluhan saluran - puluhan ribu sesi dibuka pada waktu yang sama. Server tidak tahan, dan sebagian besar portal tidak tersedia. Aplikasi tidak skala dengan baik. Hanya ada satu cara untuk melakukan ini: menyebarkan salinan lain secara berdampingan dan menyeimbangkan beban di antara mereka menggunakan Nginx. Dan setiap pengiriman kode produksi melibatkan banyak pekerjaan manual dan memakan waktu beberapa jam.

Enam bulan setelah keterlibatan saya dalam proyek, ketika situasinya sudah mulai keluar dari kendali, keputusan dibuat untuk secara radikal mengubah situasi. Proses transisi telah dimulai. Perubahan memengaruhi semua area: komposisi tim, proses kerja, arsitektur, dan komponen teknis aplikasi.

Kami membangun, membangun ...


Pertama-tama, perubahan personel telah terjadi. Digantikan oleh beberapa pengembang, mereka menjadikan saya pemimpin tim. Transisi ke solusi modern dimulai dengan keterlibatan orang-orang dalam tim yang memiliki pengalaman bekerja dengan mereka.

Perubahan prosedural lebih bersifat global. Pada saat itu, pengembangan sudah berjalan pada metodologi Agile- + Scrum, sprint dua minggu dengan pengiriman pada akhir setiap iterasi. Tetapi pada kenyataannya, ini tidak hanya tidak meningkatkan kecepatan kerja, tetapi, sebaliknya, melambat. Demonstrasi harian berlangsung selama satu setengah hingga dua jam dan tidak membuahkan hasil. Perencanaan dan perawatan berubah menjadi perselisihan, sumpah serapah atau komunikasi sederhana. Ada hubungannya dengan ini. Awalnya sangat sulit untuk mengubah apa pun dalam nada ini - atas nama pelanggan, tim hampir kehilangan kepercayaan, terutama setelah penjualan yang gagal. Setiap perubahan harus dibuktikan, didiskusikan dan dibuktikan untuk waktu yang lama. Cukup aneh, tetapi inisiatif datang dari pelanggan. Di pihak mereka, seorang scrum-master dilibatkan untuk mengendalikan aplikasi yang benar dari pendekatan dan metodologi, proses debug dan mengatur tim untuk bekerja. Meskipun ia hanya tertarik pada beberapa sprint, itu membantu kami merakit fondasi dengan benar. Pendekatan komunikasi dengan pelanggan telah banyak berubah. Kami mulai membahas masalah dalam proses lebih sering, retrospektif mulai terjadi lebih produktif, pengembang lebih bersedia untuk memberikan umpan balik, dan pelanggan, untuk bagiannya, maju dan mendukung proses transisi dengan segala cara.

Tapi, jujur, saya akan jujur โ€‹โ€‹mengatakan: ada beberapa saat ketika beberapa perubahan dalam tim dilakukan "secara membabi buta", dan setelah penampilan hasil yang positif, ini dilaporkan kepada pelanggan. Selama enam bulan, sikap telah berubah menjadi komunikasi kerja yang nyaman. Ini diikuti oleh beberapa teambuildings, pertemuan satu hari dan dua hari dari seluruh tim pengembangan dengan tim pelanggan (pemasar, analis, perancang, pengamat produk, manajer konten, dll.), Kunjungan bersama ke bar. Setelah satu tahun, dan hingga hari ini, komunikasi dapat disebut ramah. Suasana telah menjadi ramah, santai dan nyaman. Tentu saja, itu tidak dilakukan tanpa konflik, tetapi bahkan di keluarga yang paling bahagia pun terkadang ada pertengkaran.

Perubahan yang tidak kalah menarik terjadi selama periode ini dalam kode aplikasi, dalam arsitekturnya dan solusi yang digunakan. Jika Anda tidak mengerti secara teknis, Anda dapat dengan aman melewati seluruh teks sampai pada kesimpulan. Dan jika Anda beruntung sama seperti saya - selamat datang! Seluruh transisi dapat dibagi menjadi beberapa tahap. Tentang masing-masing lebih detail.

Tahap 1. Identifikasi area masalah kritis.

Segalanya sesederhana dan sejelas mungkin. Pertama-tama, perlu untuk menghilangkan ketergantungan dari produk komersial pihak ketiga, untuk memotong monolit dan untuk memungkinkan debug secara lokal. Saya ingin memisahkan kode klien dan server, untuk mendistribusikannya secara arsitektur dan fisik. Tempat masalah lain adalah kualifikasi. Proyek ini sama sekali tidak memiliki pengujian otomatis. Ini membuat transisi sedikit sulit, karena semuanya harus diperiksa secara manual. Mengingat bahwa tidak pernah ada tugas teknis untuk fungsional (spesifik proyek dipengaruhi di sini), ada kemungkinan besar kehilangan sesuatu. Setelah mengecat area yang bermasalah, kami sekali lagi melihat daftar itu. Itu tampak seperti sebuah rencana. Saatnya membangun gedung pencakar langit!

Tahap 2. Memperbarui basis kode.

Tahap yang paling lama berjalan. Semuanya dimulai dengan transisi ke arsitektur layanan (jangan dikacaukan dengan layanan microser). Idenya adalah sebagai berikut: untuk memecah aplikasi menjadi beberapa layanan terpisah, yang masing-masing akan berurusan dengan tugas spesifiknya. Layanan seharusnya bukan "mikro," tetapi saya juga tidak ingin meletakkan semuanya dalam satu ketel. Setiap layanan seharusnya menjadi aplikasi Spring Boot yang ditulis dalam Java SE 8 dan dijalankan pada Tomcat.

Yang pertama adalah yang disebut. "Layanan konten", yang telah menjadi lapisan antara aplikasi masa depan dan CMS. Ini telah menjadi abstraksi dalam perjalanan ke konten. Diasumsikan bahwa semua permintaan yang sebelumnya kami buat langsung di CMS akan dilakukan melalui layanan ini, tetapi sudah menggunakan protokol HTTP. Solusi semacam itu memungkinkan kami untuk mengurangi konektivitas dan menciptakan kemungkinan untuk selanjutnya mengganti dotCMS dengan analog yang lebih modern atau bahkan menghilangkan penggunaan produk komersial dan menulis solusi kami sendiri yang dirancang untuk tugas-tugas kami (melihat ke depan, saya akan mengatakan bahwa ini adalah cara kami melangkah).

Segera menciptakan landasan untuk pemisahan kode depan dan backend. Mereka menciptakan layanan front-end, yang menjadi bertanggung jawab untuk mendistribusikan kode yang ditulis pada reaksi. Kami mengacaukan npm, mengkonfigurasi node, dan membongkar perakitan - semuanya sebagaimana mestinya sesuai dengan tren modern bagian klien.

Secara umum, fungsi dialokasikan ke layanan sesuai dengan algoritma berikut:

  • menciptakan aplikasi Boot Musim Semi baru dengan semua dependensi dan pengaturan yang diperlukan;
  • porting semua logika dasar (sering menulisnya dari awal, merujuk ke kode lama, hanya untuk memastikan bahwa Anda tidak melupakan nuansa apa pun), misalnya, untuk layanan caching, ini adalah opsi untuk menambahkan ke cache, membaca dari itu dan menonaktifkannya;
  • semua fungsi baru selalu ditulis menggunakan layanan baru;
  • secara bertahap menulis ulang potongan aplikasi yang lama menjadi layanan baru sesuai dengan kepentingannya.

Pada awalnya, kami memiliki beberapa dari mereka:

  • Layanan konten. Bertindak sebagai lapisan antara aplikasi dan CMS.
  • Layanan cache. Repositori sederhana di Spring Cache.
  • Layanan AA. Pada awalnya, ia hanya terlibat dalam distribusi informasi tentang pengguna yang berwenang. Sisanya tetap di dalam dotCMS.
  • Layanan depan. Bertanggung jawab untuk mendistribusikan kode klien.

Tahap 3. Autotests.

Dengan mempertimbangkan semua pengalaman proyek, kami memutuskan bahwa kehadiran tes fungsional sangat menyederhanakan kehidupan dan kemungkinan pembaruan aplikasi lebih lanjut. Sudah waktunya untuk memperkenalkan mereka ke dalam proyek. Unit test kode, sayangnya mengatakan ini, terhenti segera. Mereka membutuhkan banyak waktu untuk menulis dan mendukung, dan kami memiliki sangat sedikit, karena, selain menulis ulang kode, tugas saat ini pada fungsi baru tergantung pada kami, dan bug sering muncul. Diputuskan untuk fokus hanya pada pengujian antarmuka aplikasi menggunakan Selenium. Ini, di satu sisi, membuatnya lebih mudah bagi kami untuk melakukan pengujian regresi sebelum mengirim ke produksi, di sisi lain, menjadi mungkin untuk melakukan refactoring di sisi server, memantau keadaan di sisi klien. Tim tidak memiliki automator, dan menulis serta menjaga relevansi autotests memerlukan biaya tambahan. Mereka tidak melatih kembali salah satu penguji, dan orang lain ditambahkan ke tim.

Tahap 4. Otomatisasi penyebaran.

Sekarang kami memiliki layanan terpisah, ketika frontend telah terpisah dari backend, ketika fungsi utama mulai dicakup oleh swa-uji, saatnya untuk membuka sekaleng bir dan mengotomatiskan semua pekerjaan manual penggelaran dan mendukung aplikasi secara lokal, pada server demo dan server prod. Memotong monolit menjadi potongan-potongan dan penggunaan Spring Boot telah membuka cakrawala baru bagi kami.

Pengembang dapat men-debug kode secara lokal, hanya menjalankan bagian dari fungsi yang diperlukan untuk ini. Tiang uji akhirnya mulai digunakan untuk tujuan yang dimaksudkan - sudah ada lebih atau kurang kode yang didebug, siap untuk pengujian awal dan kualifikasi. Tetapi masih ada banyak pekerjaan tangan yang menyia-nyiakan waktu dan energi kita yang berharga. Setelah mempelajari masalah dan memilah-milah solusi, kami memutuskan sekelompok Gradle + TeamCity. Karena proyek ini dibangun oleh Gradle, menambahkan sesuatu yang baru tidak masuk akal, dan skrip yang ditulis ternyata bersifat platform independen, mereka dapat dijalankan pada OS apa pun, jarak jauh atau lokal. Dan ini memungkinkan tidak hanya menggunakan solusi apa pun untuk CI / CD, tetapi juga tanpa kesulitan mengubah platform ke yang lain. TeamCity dipilih karena fungsi bawaannya yang kaya, keberadaan komunitas besar dan daftar panjang plug-in untuk semua kesempatan, serta integrasi dengan lingkungan pengembangan Intellij IDEA.

Saat ini, ada lebih dari 100 skrip optimasi dan lebih dari 300 tugas dalam sistem CI untuk menjalankannya dengan parameter yang berbeda. Ini tidak hanya penyebaran untuk menguji bangku dan pengiriman ke produksi, tetapi juga bekerja dengan log, manajemen server, perutean dan hanya solusi untuk tugas-tugas rutin dari jenis yang sama. Beberapa tugas telah dihapus dari bahu kita. Pengelola konten dapat membersihkan sendiri cache. Orang-orang dari dukungan teknis mendapat kesempatan untuk menarik layanan individu sendiri, untuk melakukan tindakan resusitasi primer. Tidur pengembang telah menjadi lebih dalam dan lebih tenang.

Tahap 5. CMS sendiri.

Setelah dimungkinkan untuk abstrak dari CMS komersial, menjadi mungkin untuk menerima data dari sumber lain, tanpa menulis ulang kode aplikasi. Di mana mendapatkan data ini atau itu diputuskan oleh layanan konten. Setelah mencari solusi yang sudah jadi dan menganalisisnya, kami memutuskan untuk menulis sistem manajemen konten kami sendiri, karena tidak ada satupun yang sepenuhnya memenuhi kebutuhan kami. Menulis CMS Anda sendiri adalah proses tanpa akhir, kebutuhan dan keinginan baru terus muncul. Kami memilih beberapa fitur dasar dan pergi ke dunia pengembangan yang indah. Untuk meluncurkan versi pertama dalam prod, kami memiliki waktu satu setengah bulan. Karena fungsionalitas siap di CMS baru, kami mentransfer konten dari yang lama ke sana. Semua halaman baru tidak ada hubungannya dengan dotCMS lagi. Seiring waktu, ini memungkinkan untuk meninggalkan versi berbayar dan beralih ke versi komunitas, dan di masa depan benar-benar meninggalkan sesuatu pihak ketiga.

Tahap 6. Proofreading.

Setelah menyingsingkan celana kami, kami memulai perjalanan kami ke dunia pemrograman hipster. Tahap ini untuk proyek saya adalah yang terakhir dalam proses rekonstruksi. Itu berlanjut hingga hari ini. Area utama di mana tahap ini umumnya muncul adalah penskalaan. Bundel + Kubernetes + bundel Konsul memungkinkan Anda untuk tidak hanya memfasilitasi penyebaran ke server yang berbeda dan mengelola setiap layanan secara terpisah, tetapi juga secara fleksibel mengukur seluruh aplikasi, melakukannya hanya di tempat-tempat yang diperlukan, dan hanya selama diperlukan. Secara lebih rinci saya bisa melukis hanya ketika kita sepenuhnya beralih ke solusi ini dalam produksi.

... dan akhirnya dibangun. Hore!



Setahun telah berlalu sejak pembaruan aplikasi dimulai. Sekarang ini adalah 26 layanan REST yang ditulis dalam Spring Boot. Masing-masing memiliki dokumentasi API terperinci di UI Swagger. Sisi klien ditulis dalam React.js dan dipisahkan dari sisi server. Semua halaman utama portal ditutupi dengan tes. Melakukan beberapa penjualan besar. Transisi ke teknologi modern, menyingkirkan kode lama dan pengoperasian server yang stabil sangat memotivasi pengembang. Dari "seperti yang kami katakan, kami melakukannya" proyek pindah ke arus utama, di mana semua orang tertarik untuk sukses, menawarkan opsi mereka sendiri untuk perbaikan dan optimasi. Sikap pelanggan terhadap tim telah berubah, suasana yang bersahabat telah tercipta.

Ini adalah hasil kerja seluruh tim, masing-masing pengembang dan penguji, manajer dan pelanggan. Itu sangat sulit, gugup dan kadang-kadang di ambang pelanggaran. Tetapi kohesi tim, perencanaan yang kompeten, dan kesadaran akan hasil memungkinkan untuk mengatasi semua kesulitan.

Source: https://habr.com/ru/post/id457624/


All Articles