Advertisement
  1. Code
  2. Web Development

Refactoring Legacy Code: Bagian 1 - Golder Master

by
Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called Refactoring Legacy Code.
Refactoring Legacy Code: Part 2 - Magic Strings & Constants

Indonesian (Bahasa Indonesia) translation by Sandi Muamar (you can also view the original English article)

Kode lama. Kode jelek. Kode yang rumit. Kode spaghetti. Jibberish omong kosong. Dalam 2 kata, Lecay code. Ini adalah seri yang akan membantu Anda bekerja dan berurusan dengan itu.

Dalam dunia ideal, Anda akan menulis hanya kode baru. Anda akan menulis indah dan sempurna. Anda tidak akan pernah mengembalikan kode Anda dan Anda tidak akan pernah mempertahankan proyek sepuluh tahun. Dalam dunia yang ideal...

Sayangnya, kita hidup dalam realitas yang tidak ideal. Kita harus mengerti, memodifikasi dan meningkatkan usia-tua kode. Kita harus bekerja dengan legacy code. Jadi apa yang Anda tunggu? Mari kita mendapatkan kepala kita ke dalam tutorial pertama ini, mendapatkan kode, memahami sedikit dan menciptakan jaring pengaman modifikasi masa depan kami.

Definisi Legacy Code

Legacy code didefinisikan dalam banyak cara, mustahil untuk menemukan definisi tunggal, umumnya diterima untuk itu. Beberapa contoh pada awal tutorial ini adalah hanya puncak gunung es. Jadi aku tidak akan memberikan definisi resmi. Sebaliknya, saya akan mengutip satu favorit saya.

Bagi saya, legacy code adalah hanya kode tanpa tes. ~ Michael bulu

Yah, itu adalah definisi formal pertama legacy code ekspresi, diterbitkan oleh Michael bulu dalam bukunya bekerja secara efektif dengan legacy code. Tentu saja, industri menggunakan ekspresi untuk usia, pada dasarnya untuk setiap kode yang sulit untuk diubah. Namun definisi ini memiliki sesuatu yang berbeda untuk memberitahu. Ini menjelaskan masalah yang sangat jelas, sehingga solusi menjadi jelas. "Sulit untuk mengubah" tidak begitu jelas. Apa yang harus kita lakukan untuk membuatnya mudah untuk berubah? Kami tidak tahu! "Kode tanpa tes" di sisi lain sangat konkret. Dan jawaban untuk pertanyaan sebelumnya kami sederhana, membuat kode yang diuji dan mengujinya. Jadi mari kita mulai.

Mendapatkan kode Legacy code

Seri ini akan didasarkan pada Trivia Game oleh J.B. Rainsberger dirancang untuk event Legacy Code Retreat. Hal ini dibuat seperti legacy code asli dan juga menawarkan kesempatan untuk berbagai macam refactoring, pada tingkat kesulitan yang layak.

Memeriksa kode sumber

Permainan Trivia adalah host di GitHub dan GPLv3 berlisensi, sehingga Anda dapat bermain-main dengan bebas. Kita akan mulai seri ini dengan memeriksa repositori resmi. Kode juga dilampirkan tutorial ini dengan semua perubahan yang kita akan membuat, sehingga jika Anda mendapatkan bingung pada titik tertentu, Anda dapat mengambil mengintip pada hasil akhir.

Ketika Anda membuka direktori trivia Anda akan melihat kode kita dalam beberapa bahasa pemrograman. Kami akan bekerja di PHP, tetapi Anda bebas untuk memilih satu favorit Anda dan menerapkan teknik-teknik yang disajikan di sini.

Memahami kode

Menurut definisi, legacy code sulit untuk dipamahami, terutama jika kita bahkan tidak tahu apa yang seharusnya dilakukan. Jadi, langkah pertama adalah untuk menjalankan kode dan membuat semacam penalaran, ini tentang apa.

Kami memiliki dua file dalam direktori kami.

GameRunner.php tampaknya menjadi calon yang baik untuk upaya kami untuk menjalankan kode.

Oke. Dugaan kami itu benar. Kode yang dijalana dan menghasilkan beberapa output. Menganalisis output ini akan membantu kita simpulkan beberapa gagasan dasar tentang kode melakukan apa.

  1. Kita tahu ini adalah permainan Trivia. Kami tahu itu ketika kami memeriksa kode sumber.
  2. Contoh kita memiliki tiga pemain: Chet, Pat dan Sue.
  3. Ada beberapa jenis rolling dadu atau konsep serupa.
  4. Ada lokasi untuk pemain. Mungkin pada beberapa jenis papan?
  5. Ada berbagai kategori dari pertanyaaan yang mana yang ditanya.
  6. Pengguna menjawab pertanyaan.
  7. Jawaban yang benar memberikan pemain emas.
  8. Jawaban yang salah mengirimkan pemain ke kotak penalti.
  9. Pemain dapat keluar dari kotak penalti, berdasarkan beberapa logika tidak cukup jelas.
  10. Tampaknya seperti pengguna yang pertama mencapai enam kemenangan koin emas.

Sekarang itu banyak pengetahuan. Kita bisa tahu sebagian besar perilaku dasar aplikasi dengan hanya melihat output. Dalam kehidupan nyata aplikasi, output tidak mungkin teks pada layar, tetapi dapat menjadi halaman web, error log, database, jaringan komunikasi, dump file dan seterusnya. Dalam kasus lain, module yang kamu butuhkan untuk di edit tidak bisa di jalankan secara isolasi. Jika demikian, Anda akan perlu untuk menjalankan melalui modul lain aplikasi besar. Hanya mencoba untuk menambahkan minimum, untuk mendapatkan beberapa output yang wajar dari legacy code.

Pemindaian kode

Sekarang bahwa kita memiliki ide tentang kode menampilkan apa, kita dapat mulai melihat itu. Kita akan mulai dengan runner.

Game runner

Saya ingin memulai dengan menjalankan semua kode melalui formatter IDE saya. Hal ini sangat meningkatkan keterbacaan dengan membuat bentuk kode akrab dengan apa yang aku sudah terbiasa. Jadi ini:

... akan menjadi ini:

... mana agak lebih baik. Itu tidak mungkin perbedaan besar dengan jumlah kode ini kecil, tapi akan berada di file kami berikutnya.

Melihat file GameRunner.php kami, kita dapat dengan mudah mengidentifikasi beberapa aspek kunci kami mengamati dalam output. Kita dapat melihat garis yang menambahkan pengguna (9-11), yang roll() metode ini dipanggil dan pemenang dipilih. Tentu saja, ini adalah jauh dari rahasia batin logika permainan, tetapi setidaknya kita bisa mulai dengan mengidentifikasi kunci metode yang akan membantu kita menemukan sisa kode.

File Game

Kita harus melakukan format yang sama pada berkas Game.php juga.

File ini jauh lebih besar; Sekitar 200 baris kode. Sebagian besar metode yang tepat ukuran, tetapi beberapa dari mereka cukup besar dan setelah format, kita dapat melihat bahwa di dua tempat indentasi kode melampaui empat tingkat. Tingkat tinggi indentasi biasanya berarti banyak kompleks keputusan, jadi untuk sekarang, kita dapat mengasumsikan bahwa titik-titik tersebut dalam kode kita akan menjadi lebih kompleks dan lebih masuk akal untuk diubah.

Golder Master

Dan memikirkan perubahan membawa kita untuk kita kekurangan tes. Metode yang kita lihat dalam Game.php cukup kompleks. Jangan khawatir jika Anda tidak memahami mereka. Pada titik ini, mereka adalah sebuah misteri bagi saya juga. Legacy code adalah sebuah misteri yang kita butuhkan untuk mengatasi dan memahami. Kami membuat langkah pertama kami untuk memahaminya dan sekarang saatnya untuk satu kedua.

Jadi apa itu Golden Master ini?

Ketika bekerja dengan legacy code, hampir mustahil untuk memahaminya dan menulis kode yang pasti akan melatih semua jalan yang logis melalui kode. Untuk pengujian semacam itu, kita perlu memahami kode, tapi kita lakukan belum. Jadi kita perlu mengambil pendekatan lain.

Daripada mencoba untuk mencari tahu apa yang akan diuji, kita dapat menguji segalanya, banyak kali, sehingga kita berakhir dengan jumlah besar output, tentang yang kita hampir pasti bisa berasumsi bahwa itu diproduksi dengan melatih semua bagian dari kode warisan kita. Dianjurkan untuk menjalankan kode sedikitnya 10.000 (sepuluh ribu) kali. Kami akan menulis sebuah tes untuk menjalankannya dua kali lipat dan menyimpan output.

Menulis Golder Master Generator

Kita bisa berpikir ke depan dan memulai dengan menciptakan sebuah generator dan tes sebagai file terpisah untuk pengujian nanti, tetapi apakah itu benar-benar diperlukan? Kita tidak tahu itu belum pasti. Jadi mengapa tidak hanya mulai dengan ujian dasar file yang akan menjalankan kode kami sekali dan membangun logika kami dari sana.

Anda akan menemukan dalam arsip kode terlampir, di dalam folder source tetapi di luar trivia folder folder Test kami. Dalam folder ini, kami menciptakan sebuah file: GoldenMasterTest.php.

Kita bisa melakukan ini dalam banyak cara. Kita bisa, misalnya, menjalankan kode kita dari konsol dan mengarahkan output ke file. Namun, setelah itu dalam tes yang mudah berjalan di dalam IDE kami adalah keuntungan kita tidak boleh mengabaikan.

Kode ini cukup sederhana, buffer output dan menempatkan ke variabel $output. require_once() juga akan berjalan semua kode di dalam file yang disertakan. Di dump var kami kita akan melihat beberapa hasil yang sudah akrab.

Namun kedua lari, kita dapat mengamati sesuatu yang aneh:

... output berbeda. Meskipun kita menjalankan kode yang sama, output berbeda. Memutar nomor berbeda, para pemain posisi berbeda.

Seeding Random Generator

Dengan menganalisis kode penting dari runner, kita bisa melihat bahwa menggunakan rand() fungsi untuk menghasilkan angka random. Perhentian kami berikutnya adalah dokumentasi PHP resmi untuk penelitian fungsi rand() ini.

Nomor random generator seed secara otomatis.

Dokumentasi memberitahu kita bahwa seeding terjadi secara otomatis. Sekarang kita memiliki tugas lain. Kita perlu menemukan cara untuk mengendalikan seed. Fungsi srand() dapat membantu dengan itu. Berikut ini adalah definisi dari dokumentasi.

Seed nomor random generator dengan seed atau dengan nilai random jika tidak diberikan.

Ia mengatakan, bahwa jika kita menjalankan ini sebelum setiap panggilan ke rand(), kita harus selalu berakhir dengan hasil yang sama.

Kami menempatkan srand(1) sebelum require_once() kami. Sekarang Keluaran adalah selalu sama.

Menempatkan Output dalam File

Perubahan ini tampak wajar. Kan? Kami diekstrak generasi kode ke metode, menjalankannya dua kali, dan diharapkan output untuk menjadi sama. Namun mereka tidak akan.

Alasannya adalah bahwa require_once() tidak akan memerlukan file yang sama dua kali. Panggilan kedua untuk metode generateOutput() yang akan menghasilkan string kosong. Jadi, apa yang bisa kita lakukan? Bagaimana jika kita hanya require()? apa bakal dijalankan setiap kali.

Yah, yang mengarah ke masalah lain: "Cannot redeclare echoln()". Tapi mana yang datang dari? Letaknya tepat di awal Game.php file. Alasan mengapa terjadi kesalahan ini adalah karena di GameRunner.php kami telah include __DIR__. ' / Game.php'; yang mencoba untuk menyertakan file permainan dua kali, setiap kali ketika kita memanggil metode generateOutput().

Menggunakan include_once di GameRunner.php akan memecahkan masalah kita. Ya, kami harus memodifikasi GameRunner.php tanpa memiliki tes untuk itu, sementara! Namun, kita dapat 99% yakin bahwa perubahan kami tidak akan merusak kode itu sendiri. Ini adalah perubahan yang kecil dan cukup sederhana untuk tidak menakut-nakuti kami sangat banyak. Dan yang paling penting, itu membuat tes sukses.

Jalankan beberapa kali

Sekarang bahwa kita memiliki kode yang dapat kita jalankan berkali-kali, itu adalah waktu untuk menghasilkan output beberapa.

Kami ekstrak metode lain di sini: generateMany(). Ini memiliki dua parameter. Satu untuk jumlah waktu yang kami ingin menjalankan generator kami, yang lain adalah file tujuan. Ini akan menempatkan output dihasilkan dalam file. Pada menjalankan pertama mengosongkan berkas, dan untuk sisa iterasi, menambahkan data. Anda dapat melihat ke dalam file untuk melihat output dihasilkan 20 kali.

Tapi tunggu! Pemain yang sama menang setiap kali? Apakah itu mungkin?

Ya! Sangat mungkin! Lebih dari mungkin. Itu adalah suatu hal yang pasti. Kami memiliki seed yang sama untuk fungsi random kami. Kami bermain permainan yang sama berulang-ulang.

Jalankan ini berbeda setiap kali

Kita perlu untuk bermain permainan yang berbeda, sebaliknya hampir pasti bahwa hanya sebagian kecil dari legacy code kita benar-benar dilakukan berulang-ulang. Lingkup golder master adalah untuk dicoba sebanyak mungkin. Kita perlu untuk re-seed generator random setiap kali, tapi dengan cara yang terkendali. Salah satu pilihan adalah untuk menggunakan counter kami sebagai nilai seed.

Ini masih terus pengujian kami melewati, jadi kami yakin kami menghasilkan output lengkap yang sama setiap kali, sementara output memainkan permainan yang berbeda untuk setiap perulangan.

Ada berbagai pemenang untuk permainan dalam mode acak. Ini terlihat bagus.

Mendapatkan hingga 20.000

Hal pertama yang Anda mungkin mencoba adalah dengan menjalankan kode kami untuk iterasi permainan 20.000.

Ini hampir akan bekerja. Dua 55MB file yang akan dihasilkan.

Di sisi lain, tes akan gagal dengan galat memori tidak cukup. Tidak peduli berapa banyak RAM Anda memiliki, hal ini akan gagal. Aku punya 8GB ditambah swap 4GB dan gagal. Dua string terlalu besar untuk dibandingkan dalam assertion kami.

Dengan kata lain, kita menghasilkan file yang baik, tapi PHPUnit tidak bisa membandingkan mereka. Kita perlu kerja-sekitar.

Yang tampaknya menjadi calon yang baik, tetapi masih gagal. Sayang. Kita perlu penelitian situasi lebih lanjut.

Namun, hal ini bekerja.

Dapat membandingkan dua string dan gagal jika mereka berbeda. Namun, memiliki harga kecil. Tidak akan dapat memberi tahu persis apa salah ketika string berbeda. Ia hanya akan berkata "Failed asserting that false is true.". Tapi kita akan berurusan dengan yang di tutorial yang akan datang.

Akhir pikiran

Kami selesai untuk tutorial ini. Kami telah belajar cukup banyak untuk pelajaran pertama kita dan kita berada pada awal yang baik untuk masa depan pekerjaan kami. Kami bertemu kode, kami dianalisis dalam cara yang berbeda dan sebagian besar yang kita mengerti dengan logika yang penting. Kemudian kita menciptakan serangkaian tes untuk memastikan itu dilaksanakan sebanyak mungkin. Ya. Tes sangat lambat. Dibutuhkan waktu mereka 24 detik pada Core i7 CPU untuk menghasilkan output dua kali. Untungnya dalam pengembangan kedepannya kami, kami akan menyimpan gm.txt file belum tersentuh dan menghasilkan satu lagi hanya sekali per run. Tetapi 12 detik masih waktu yang banyak untuk seperti basis kode kecil.

Pada saat kami selesai seri ini, tes harus berjalan dalam waktu kurang dari sedetik dan menguji semua kode dengan benar. Jadi, nantikan untuk tutorial berikutnya kami ketika kami akan mengatasi masalah seperti magic constant, magic string dan kompleks conditional. Terima kasih sudah membaca.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.