Nama saya Danil Mukhametzyanov dan saya telah bekerja sebagai pengembang backend di Badoo selama tujuh tahun. Selama ini, saya berhasil membuat dan mengubah sejumlah besar kode. Begitu besarnya sehingga suatu hari seorang manajer mendatangi saya dan berkata: “Kuota sudah habis. Untuk menambahkan sesuatu, Anda perlu menghapus sesuatu. "
Oke, itu hanya lelucon - dia tidak mengatakan itu. Itu sangat disayangkan! Selama seluruh keberadaan perusahaan, Badoo telah mengumpulkan lebih dari 5,5 juta baris kode bisnis logis, tidak termasuk baris kosong dan tanda kurung tutup.
Kuantitasnya sendiri tidak terlalu menakutkan: dia berbohong, tidak meminta makanan. Tetapi dua atau tiga tahun yang lalu, saya mulai memperhatikan bahwa saya semakin sering membaca dan mencoba mencari tahu kode yang tidak benar-benar berfungsi di lingkungan produksi. Itu sebenarnya sudah mati.
Tren ini diperhatikan tidak hanya oleh saya. Badoo menyadari bahwa teknisi kami yang bergaji tinggi terus-menerus membuang waktu untuk kode mati.
Saya memberikan ceramah ini di Badoo PHP Meetup # 4
Dari mana asal kode yang mati itu?
Kami mulai mencari penyebab masalahnya. Membaginya menjadi dua kategori:
- proses - yang muncul sebagai hasil dari perkembangan;
- sejarah - kode warisan.
Pertama-tama, kami memutuskan untuk membongkar sumber proses untuk mencegah munculnya masalah baru.
Pengujian A / B
Badoo mulai aktif menggunakan pengujian A / B empat tahun lalu. Sekarang kami memiliki sekitar 200 pengujian yang terus berjalan, dan semua fitur produk melalui prosedur ini.
Hasilnya, sekitar 2000 tes yang diselesaikan dikumpulkan dalam empat tahun, dan angka ini terus bertambah. Dia membuat kami takut bahwa setiap pengujian adalah potongan kode mati yang tidak lagi dijalankan dan tidak diperlukan sama sekali.
Solusi untuk masalah ini datang dengan cepat: kami mulai membuat tiket secara otomatis untuk memotong kode setelah pengujian A / B selesai.
Contoh tiket
Tapi faktor manusia secara berkala dipicu. Berulang kali, kami menemukan kode pengujian yang terus berjalan, tetapi tidak ada yang memikirkannya dan menyelesaikan pengujian.
Lalu ada kerangka kerja yang kaku: setiap tes harus memiliki tanggal akhir. Jika manajer lupa membaca hasil tes, dia akan otomatis berhenti dan mati. Dan, seperti yang telah saya sebutkan, tiket secara otomatis dibuat untuk memotongnya sambil mempertahankan versi asli dari logika fitur tersebut.
Dengan bantuan mekanisme sederhana seperti itu, kami menyingkirkan banyak lapisan pekerjaan.
Keragaman klien
Beberapa merek didukung di perusahaan kami, tetapi servernya satu. Setiap merek diwakili dalam tiga platform: web, iOS dan Android. Di iOS dan Android, kami memiliki siklus pengembangan mingguan: seminggu sekali, bersama dengan pembaruan, kami menerima versi baru aplikasi di setiap platform.
Mudah ditebak bahwa dengan pendekatan ini, dalam sebulan kami memiliki belasan versi baru yang perlu didukung. Lalu lintas pengguna tidak terdistribusi secara merata di antara mereka: pengguna secara bertahap beralih dari satu versi ke versi lainnya. Beberapa versi lama memiliki lalu lintas, tetapi sangat kecil sehingga sulit untuk mempertahankannya. Sulit dan tidak berguna.
Jadi kami mulai menghitung jumlah versi yang ingin kami dukung. Ada dua batasan untuk klien: batas lunak dan batas keras.
Ketika batas lunak tercapai (ketika tiga atau empat versi baru telah dirilis, dan aplikasi masih belum diperbarui), pengguna melihat layar dengan peringatan bahwa versinya sudah kedaluwarsa. Ketika batas keras tercapai (ini sekitar 10-20 versi yang "terlewat", tergantung pada aplikasi dan merek), kami cukup menghapus opsi untuk melewati layar ini. Ini menjadi memblokir: Anda tidak dapat menggunakan aplikasi dengan itu.

Layar untuk batas keras
Dalam hal ini, tidak ada gunanya terus memproses permintaan yang datang dari klien - dia tidak akan melihat apa pun kecuali layar.
Tapi di sini, seperti dalam kasus pengujian A / B, muncul nuansa. Pengembang klien juga manusia. Mereka menggunakan teknologi baru, chip sistem operasi - dan setelah beberapa saat versi aplikasi tidak lagi didukung pada versi sistem operasi berikutnya. Namun, server terus menderita karena harus terus memproses permintaan ini.
Kami datang dengan solusi terpisah untuk kasus ini ketika dukungan untuk Windows Phone berakhir. Kami menyiapkan layar yang memberi tahu pengguna: “Kami sangat mencintaimu! Kamu sangat keren! Tetapi bisakah Anda mulai menggunakan platform lain? Fitur keren baru akan tersedia untuk Anda, tetapi di sini kami tidak dapat melakukan apa pun. " Sebagai aturan, kami menawarkan platform web sebagai platform alternatif, yang selalu tersedia.
Dengan mekanisme yang begitu sederhana, kami membatasi jumlah versi klien yang didukung server: sekitar 100 versi berbeda dari semua merek, dari semua platform.
Bendera fitur
Namun, dengan menonaktifkan dukungan untuk platform lama, kami tidak sepenuhnya memahami apakah mungkin untuk sepenuhnya memotong kode yang mereka gunakan. Atau platform yang tetap untuk versi OS yang lebih lama terus menggunakan fungsi yang sama?
Masalahnya adalah bahwa API kita tidak dibangun pada bagian berversi, tetapi pada penggunaan tanda fitur. Bagaimana kami sampai pada hal ini, Anda dapat mengetahui dari laporan ini .
Kami memiliki dua jenis tanda fitur. Saya akan memberi tahu Anda tentang mereka dengan contoh.
Fitur kecil
Klien berkata ke server, “Halo, ini saya. Saya mendukung posting foto. " Server melihatnya dan menjawab: “Bagus, dukung! Sekarang saya tahu tentang itu dan akan mengirimi Anda pesan foto. " Fitur utama di sini adalah bahwa server tidak dapat memengaruhi klien dengan cara apa pun - server hanya menerima pesan darinya dan dipaksa untuk mendengarkannya.
Kami menyebut tanda ini sebagai fitur minor. Saat ini, kami memiliki lebih dari 600.
Apa kerugian menggunakan flag-flag ini? Secara berkala, ada fungsionalitas berat yang tidak dapat ditutupi hanya dari sisi klien - Anda juga ingin mengontrolnya dari sisi server. Untuk ini, kami memperkenalkan jenis bendera lainnya.
Fitur aplikasi
Klien yang sama, server yang sama. Klien berkata: “Server, saya telah belajar untuk mendukung streaming video. Hidupkan? " Server menjawab, "Terima kasih, saya akan mengingatnya." Dan dia menambahkan: “Bagus. Mari kita tunjukkan fungsi ini kepada pengguna tercinta, dia akan senang. " Atau: "Oke, tapi kami belum memasukkannya."
Kami menyebutnya fitur aplikasi fitur. Mereka lebih berat, jadi kami memiliki lebih sedikit, tetapi masih cukup: lebih dari 300.
Jadi, pengguna berpindah dari satu versi klien ke versi lain. Beberapa jenis tanda mulai didukung oleh semua versi aktif aplikasi. Atau, sebaliknya, tidak didukung. Tidak sepenuhnya jelas bagaimana mengontrol ini: 100 versi klien, 900 bendera! Untuk mengatasinya, kami membangun dasbor.
Kotak merah berarti bahwa semua versi platform ini tidak mendukung fitur ini; hijau - semua versi platform ini mendukung tanda ini. Jika bendera dapat dimatikan dan dinyalakan, bendera akan berkedip secara berkala. Kita bisa melihat apa yang terjadi di versi mana.
Layar dasbor
Tepat di antarmuka ini, kami mulai membuat tugas untuk memotong fungsionalitas. Perlu diperhatikan bahwa tidak semua sel merah atau hijau di setiap baris perlu diisi. Ada bendera yang hanya berjalan di satu platform. Ada bendera yang diisi hanya untuk satu merek.
Mengotomatiskan proses tidak begitu nyaman, tetapi, pada prinsipnya, itu tidak perlu - Anda hanya perlu mengatur tugas dan secara berkala melihat dasbor. Pada iterasi pertama, kami berhasil memotong lebih dari 200 bendera. Itu hampir seperempat dari bendera yang kami gunakan!
Di sinilah sumber proses berakhir. Mereka muncul sebagai hasil dari aliran pengembangan kami, dan kami telah berhasil mengintegrasikan pekerjaan dengan mereka ke dalam proses ini.
Apa yang harus dilakukan dengan kode lama
Kami telah menghentikan munculnya masalah baru dalam sumber proses. Dan kami dihadapkan pada pertanyaan sulit: apa yang harus dilakukan dengan kode warisan yang terkumpul selama bertahun-tahun? Kami mendekati solusi dari sudut pandang teknik, yaitu, kami memutuskan untuk mengotomatiskan semuanya. Tetapi tidak jelas bagaimana menemukan kode yang tidak digunakan. Dia bersembunyi di dunia kecilnya yang nyaman: dia tidak dipanggil dengan cara apa pun, dia tidak membiarkan siapa pun tahu tentang dirinya sendiri.
Kami harus pergi dari sisi lain: mengambil semua kode yang kami miliki, mengumpulkan informasi tentang bagian mana yang benar-benar dieksekusi, dan kemudian melakukan inversi.
Kemudian kami menggabungkannya dan menerapkannya pada level paling minimal - pada file. Dengan cara ini kita bisa dengan mudah mendapatkan daftar file dari repositori dengan menjalankan perintah UNIX yang sesuai.
Tetap mengumpulkan daftar file yang digunakan dalam produksi. Ini cukup sederhana: untuk setiap permintaan saat shutdown, panggil fungsi PHP yang sesuai. Satu-satunya pengoptimalan yang kami lakukan di sini adalah mulai meminta OPCache alih-alih meminta setiap permintaan. Jika tidak, jumlah datanya akan sangat besar.
Hasilnya, kami menemukan banyak artefak menarik. Tetapi dengan analisis yang lebih dalam, kami menyadari bahwa kami kehilangan metode yang tidak digunakan: perbedaan jumlahnya tiga hingga tujuh kali lipat.
Ternyata file tersebut dapat dimuat, dijalankan, dikompilasi hanya untuk satu konstanta atau sepasang metode. Segala sesuatu yang lain tetap tidak berguna untuk berbaring di laut tanpa dasar ini.
Menyusun daftar metode
Namun, ternyata cukup cepat untuk mengumpulkan daftar lengkap metode. Kami baru saja mengambil parser Nikita Popov , memberinya repositori kami dan mendapatkan semua yang kami miliki di kode.
Pertanyaannya tetap: bagaimana merakit apa yang sedang dimainkan dalam produksi? Kami tertarik pada produksi, karena pengujian dapat mencakup apa yang tidak kami butuhkan sama sekali. Tanpa berpikir dua kali, kami mengambil XHProf. Ini telah dijalankan dalam produksi untuk sebagian dari kueri, dan oleh karena itu kami memiliki contoh profil yang disimpan dalam database. Cukup pergi ke database ini, parsing snapshot yang dihasilkan - dan dapatkan daftar file.
Kerugian dari XHProf
Kami mengulangi proses ini di cluster lain di mana XHProf tidak dimulai, tetapi sangat dibutuhkan. Ini adalah cluster untuk menjalankan skrip latar belakang dan pemrosesan asinkron, yang penting untuk beban tinggi, menjalankan banyak logika.
Dan kemudian kami memastikan bahwa XHProf tidak nyaman bagi kami.
- Ini membutuhkan perubahan kode PHP. Anda perlu memasukkan kode awal penelusuran, menyelesaikan penelusuran, mendapatkan data yang dikumpulkan, menulisnya ke file. Bagaimanapun, ini adalah profiler, dan kami memiliki produksi, yaitu, ada banyak permintaan, Anda perlu memikirkan pengambilan sampel. Dalam kasus kami, ini diperburuk oleh sejumlah besar cluster dengan titik masuk yang berbeda.
- . . , OPCache. : XHProf, . , core- .
- . . XHProf . ( XHProf): CPU, , . , , . - XHProf aggregator ( XHProf Live Profiler, open-source) , , , . , : «, , », CPU , , Live Profiler . , , .
- XHProf. , . . , . : , ( , youROCK, ini tidak diperlukan oleh lsd , tetapi lebih mudah untuk mempertahankan satu pembungkus di atasnya). Menambal XHProf bukanlah yang ingin kami lakukan, karena ini adalah profiler yang agak besar (bagaimana jika kami merusak sesuatu secara tidak sengaja?).
Ada satu ide lagi - untuk mengecualikan namespace tertentu, misalnya, namespace vendor dari komposer, yang dijalankan dalam produksi, karena tidak berguna: kami tidak akan memfaktor ulang paket vendor dan memotong kode tambahan darinya.
Persyaratan solusi
Sekali lagi kami berkumpul dan melihat solusi apa yang ada. Dan mereka merumuskan daftar persyaratan akhir.
Pertama: overhead minimal. Bagi kami, XHProf adalah barnya: tidak lebih dari yang dibutuhkan.
Kedua, kami tidak ingin mengubah kode PHP.
Ketiga, kami ingin solusi tersebut berfungsi di mana saja - baik di FPM maupun di CLI.
Keempat, kami ingin menangani percabangan. Mereka secara aktif digunakan di CLI, di server cloud. Saya tidak ingin membuat logika khusus untuk mereka di dalam PHP.
Kelima: pengambilan sampel di luar kotak. Sebenarnya, ini mengikuti dari persyaratan untuk tidak mengubah kode PHP. Di bawah ini saya akan menjelaskan mengapa kami membutuhkan pengambilan sampel.
Keenam dan terakhir:kemampuan untuk memaksa dari kode. Kami senang saat semuanya bekerja secara otomatis, tetapi terkadang lebih nyaman untuk memulai, menyesuaikan, melihat secara manual. Kami membutuhkan kemampuan untuk mengaktifkan dan menonaktifkan semuanya langsung dari kode, dan bukan dengan keputusan acak dari mekanisme yang lebih umum dari modul PHP, yang menetapkan kemungkinan penyertaan melalui pengaturan.
Bagaimana funcmap bekerja
Hasilnya, kami memiliki solusi yang kami sebut funcmap.
Funcmap pada dasarnya adalah ekstensi PHP. Dalam istilah PHP, ini adalah modul PHP. Untuk memahami cara kerjanya, mari kita lihat bagaimana proses PHP dan modul PHP bekerja.
Jadi, Anda memulai sebuah proses. PHP memungkinkan untuk berlangganan hook saat membangun modul. Proses dimulai, hook GINIT (Global Init) diluncurkan, di mana Anda dapat menginisialisasi parameter global. Kemudian modul diinisialisasi. Konstanta dapat dibuat dan dialokasikan di sana, tetapi hanya untuk modul tertentu, dan bukan untuk permintaan, jika tidak, Anda akan gagal.
Kemudian permintaan pengguna masuk, hook RINIT (Request Init) dipanggil. Setelah menyelesaikan permintaan, shutdown akan terjadi, dan pada akhirnya - modul shutdown: MSHUTDOWN dan GSHUTDOWN. Semuanya logis.
Jika kita berbicara tentang FPM, maka setiap permintaan pengguna datang ke pekerja yang sudah ada. Pada dasarnya, RINIT dan RSHUTDOWN hanya bekerja dalam lingkaran sampai FPM memutuskan bahwa pekerja tersebut sudah usang, saatnya untuk menembaknya dan membuat yang baru. Jika kita berbicara tentang CLI, maka itu hanya proses linier. Semuanya akan dipanggil sekali.

Bagaimana funcmap bekerja
Dari set ini, kami tertarik pada dua kait. Yang pertama adalah RINIT . Kami mulai menyetel tanda pengumpulan data: ini adalah jenis acak yang dipanggil untuk mengambil sampel data. Jika berhasil, maka kami memproses permintaan ini: kami mengumpulkan statistik untuk panggilan ke fungsi dan metode untuk itu. Jika tidak berhasil, maka permintaan tidak akan diproses.
Hal berikutnya adalah membuat tabel hash jika tidak ada. Tabel hash disediakan secara internal oleh PHP itu sendiri. Tidak perlu menemukan apa pun di sini - ambil saja dan gunakan.
Selanjutnya, kami menginisialisasi pengatur waktu. Saya akan membicarakannya di bawah ini, untuk saat ini, ingatlah bahwa dia penting dan dibutuhkan.
Hook kedua adalah MSHUTDOWN... Saya ingin mencatat bahwa ini adalah MSHUTDOWN, bukan RSHUTDOWN. Kami tidak ingin mengerjakan sesuatu untuk setiap permintaan - kami tertarik pada seluruh pekerja. Di MSHUTDOWN, kami mengambil tabel hash kami, memeriksanya dan menulis file (apa yang bisa lebih andal, lebih nyaman dan serbaguna daripada file lama yang bagus?).
Tabel hash diisi secara sederhana dengan hook PHP yang sama zend_execute_ex, yang dipanggil setiap kali fungsi yang ditentukan pengguna dipanggil. Record berisi parameter tambahan yang dengannya Anda dapat memahami jenis fungsinya, nama dan kelasnya. Kami menerimanya, membaca namanya, menuliskannya ke tabel hash, dan kemudian memanggil hook default.
Pengait ini tidak menulis fungsi sebaris. Jika Anda ingin mengganti fungsi bawaan, ada fungsionalitas terpisah untuk itu yang disebut zend_execute_internal.
Konfigurasi
Bagaimana saya bisa mengkonfigurasi ini tanpa mengubah kode PHP? Pengaturannya sangat sederhana:
- diaktifkan: apakah itu diaktifkan atau tidak.
- File yang kami tuju. Ada placeholder pid untuk mengecualikan kondisi balapan ketika proses PHP yang berbeda menulis ke file yang sama pada waktu yang sama.
- Dasar probabilitas: bendera probabilitas kami. Jika Anda menyetelnya ke 0, maka tidak ada permintaan yang akan ditulis; jika 100 - itu berarti semua permintaan akan dicatat dan dimasukkan dalam statistik.
- flush_interval. Ini adalah frekuensi kami membuang semua data ke sebuah file. Kami ingin pengumpulan data dijalankan di CLI, tetapi ada skrip yang dapat dieksekusi dalam waktu lama, memakan memori jika Anda menggunakan banyak fungsi.
Selain itu, jika kita memiliki cluster yang tidak terlalu banyak dimuat, FPM memahami bahwa pekerja siap untuk memproses lebih banyak, dan tidak menghentikan proses - ia hidup dan memakan sebagian memori. Setelah jangka waktu tertentu, kami membuang semuanya ke disk, mengatur ulang tabel hash dan mulai mengisinya lagi. Namun, jika batas waktu belum tercapai, maka pengait MSHUTDOWN akan terpicu, tempat kami akhirnya menulis semuanya.
Hal terakhir yang kami inginkan adalah kemampuan untuk memanggil funcmap dari kode PHP. Ekstensi yang sesuai menyediakan satu-satunya metode yang memungkinkan Anda mengaktifkan atau menonaktifkan pengumpulan statistik terlepas dari cara kerja probabilitas.
Overhead
Kami bertanya-tanya bagaimana semua ini memengaruhi server kami. Kami telah membuat grafik yang menunjukkan jumlah permintaan yang datang ke mesin tempur nyata dari salah satu cluster PHP yang paling banyak dimuat.
Ada banyak mesin seperti itu, jadi grafik menunjukkan jumlah permintaan, bukan CPU. Penyeimbang menyadari bahwa mesin telah mulai mengonsumsi lebih banyak sumber daya daripada biasanya, dan mencoba untuk menyamakan permintaan sehingga mesin dimuat secara merata. Ini cukup untuk memahami bagaimana server itu merendahkan.
Kami mengaktifkan ekstensi kami secara berurutan pada 25%, 50% dan 100% dan melihat gambar berikut:
Garis putus-putus adalah jumlah permintaan yang kami harapkan. Baris utama adalah jumlah permintaan yang masuk. Kami melihat penurunan sekitar 6%, 12% dan 23%: server ini mulai memproses hampir seperempat lebih sedikit permintaan masuk.
Grafik ini pertama-tama membuktikan bahwa pengambilan sampel penting bagi kami: kami tidak dapat menghabiskan 20% sumber daya server untuk mengumpulkan statistik.
Hasil yang salah
Pengambilan sampel memiliki efek samping: beberapa metode tidak dimasukkan dalam statistik, tetapi kenyataannya digunakan. Kami mencoba melawan ini dengan beberapa cara:
- . -, . , , , , .
- . , : , , .
Kami mencoba dua solusi untuk penanganan kesalahan. Yang pertama adalah mengaktifkan pengumpulan statistik secara paksa mulai dari saat kesalahan terjadi: kumpulkan log kesalahan dan analisis. Namun ada jebakan di sini: ketika sumber daya jatuh, jumlah kesalahan langsung meningkat. Anda mulai memprosesnya, ada lebih banyak pekerja - dan cluster mulai mati perlahan. Oleh karena itu, melakukan hal tersebut tidak sepenuhnya benar.
Bagaimana melakukannya secara berbeda? Kami membaca dan, menggunakan pengurai Nikita Popov, memeriksa taruhannya, mencatat metode mana yang dipanggil di sana. Dengan demikian, kami telah menghilangkan beban di server dan mengurangi jumlah positif palsu.
Tetapi masih ada metode yang jarang dipanggil dan tidak jelas apakah diperlukan atau tidak. Kami telah menambahkan helper yang membantu menentukan fakta penggunaan metode tersebut: jika pengambilan sampel telah menunjukkan bahwa metode tersebut jarang dipanggil, maka Anda dapat mengaktifkan pemrosesan 100% dan tidak memikirkan apa yang terjadi. Eksekusi apa pun dari metode ini akan dicatat. Anda akan tahu tentang itu.
Jika Anda tahu pasti metode yang digunakan, itu mungkin berlebihan. Mungkin ini adalah fungsi yang diperlukan, tetapi jarang. Bayangkan Anda memiliki opsi "Mengeluh", yang jarang digunakan, tetapi penting - Anda tidak dapat menghentikannya. Untuk kasus seperti itu, kami telah mempelajari cara memberi label secara manual pada metode tersebut.
Kami telah membuat antarmuka yang menunjukkan metode mana yang sedang digunakan (menggunakan latar belakang putih) dan mana yang berpotensi tidak digunakan (menggunakan latar belakang merah). Di sini Anda juga dapat menandai metode yang diperlukan.
Layar antarmuka
Antarmukanya bagus, tapi mari kita kembali ke awal, yang merupakan masalah yang kami selesaikan. Itu terdiri dari fakta bahwa teknisi kami membaca kode mati. Dimana mereka membacanya? Di IDE. Bayangkan bagaimana rasanya memaksa penggemar kerajinannya meninggalkan dunia IDE dengan antarmuka web dan melakukan sesuatu di sana! Kami memutuskan bahwa kami perlu bertemu rekan-rekan kami di tengah jalan.
Kami telah membuat plugin untuk PhpStorm yang memuat seluruh database dari metode yang tidak digunakan dan menampilkan apakah metode ini digunakan atau tidak. Selain itu, Anda dapat menandai metode yang sedang digunakan di antarmuka. Ini semua akan masuk ke server dan tersedia untuk kontributor basis kode lainnya.
Ini mengakhiri bagian utama pekerjaan kami dengan Legacy. Kami mulai memperhatikan lebih cepat bahwa kami tidak mengeksekusi, merespons lebih cepat dan jangan buang waktu mencari kode yang tidak digunakan secara manual.
Ekstensi funcmap tersedia di GitHub . Kami akan senang jika itu berguna bagi seseorang.
Alternatif
Dari luar, kami di Badoo sepertinya tidak tahu harus berbuat apa dengan diri kami sendiri. Mengapa tidak melihat apa yang ada di pasaran?
Ini pertanyaan yang wajar. Kami melihat - dan tidak ada apa-apa di pasar saat itu. Hanya ketika kami mulai secara aktif menerapkan solusi kami, kami menemukan bahwa pada saat yang sama, seorang pria bernama Joe Watkins, yang tinggal di Inggris Raya yang berkabut, menerapkan ide serupa dan membuat ekstensi Makam.
Kami tidak mempelajarinya dengan sangat hati-hati, karena kami sudah memiliki solusi sendiri, namun kami menemukan beberapa masalah:
- Kurangnya pengambilan sampel. Di atas, saya menjelaskan mengapa kita membutuhkannya.
- . , APCu ( ), .
- CLI. , , CLI-, .
- . Tombs, , , , , , . funcmap («» , ): , . Tombs , , FPM CLI. - , .
Pertama, pikirkan terlebih dahulu tentang bagaimana Anda akan menghapus fungsionalitas yang diimplementasikan dalam waktu singkat, terutama jika pengembangannya sangat aktif. Dalam kasus kami, ini adalah pengujian A / B. Jika Anda tidak memikirkannya sebelumnya, maka Anda harus membersihkan puing-puingnya.
Kedua: kenali pelanggan Anda dengan melihat. Tidak masalah apakah mereka internal atau eksternal - Anda harus mengenal mereka. Pada titik tertentu, Anda perlu memberi tahu mereka: “Sayang, berhenti! Tidak".
Ketiga: bersihkan API Anda. Ini mengarah pada penyederhanaan seluruh sistem.
Dan keempat: Anda dapat mengotomatiskan semuanya, bahkan mencari kode mati. Yang kami lakukan.