Kode usang - Kode Pihak Ketiga

gambar

Ada tip di komunitas TDD yang mengatakan kita tidak boleh menggunakan objek tiruan untuk tipe yang tidak kita miliki . Saya pikir ini adalah saran yang baik, dan saya mencoba mengikutinya. Tentu saja, ada orang yang mengatakan bahwa kita tidak boleh menggunakan benda tiruan sama sekali. Tidak peduli apa pendapat Anda, saran “untuk tidak meniru apa yang bukan milik Anda” juga mengandung makna tersembunyi. Orang sering melewatinya, melihat kata "mengejek" dan menjadi marah.

Makna tersembunyi ini adalah bahwa Anda harus membuat antarmuka, klien, jembatan, adaptor antara aplikasi kami dan kode pihak ketiga yang kami gunakan. Apakah kita akan membuat objek tiruan dari antarmuka ini dalam pengujian kita bahkan tidak begitu penting. Yang penting adalah kita membuat dan menggunakan antarmuka yang lebih baik memisahkan kode kita dari kode pihak ketiga. Contoh klasik dari ini di dunia PHP adalah membuat dan menggunakan klien HTTP di aplikasi kami yang menggunakan klien HTTP Guzzle , alih-alih menggunakan Guzzle secara langsung.

Mengapa Sebagai permulaan, Guzzle memiliki API yang jauh lebih kuat daripada yang dibutuhkan aplikasi Anda (dalam banyak kasus). Membuat klien HTTP Anda sendiri, yang hanya menyediakan satu set API Guzzle yang diperlukan, akan membatasi pengembang aplikasi hanya untuk apa yang dapat mereka lakukan dengan klien ini. Jika Guzzle API berubah di masa mendatang, kita perlu melakukan perubahan di satu tempat, alih-alih memperbaiki panggilannya di seluruh aplikasi dengan harapan tidak ada yang akan rusak. Dua alasan yang sangat bagus, dan saya bahkan tidak menyebutkan benda tiruan!

Saya kira ini tidak sulit untuk dicapai. Kode pihak ketiga biasanya terletak di folder terpisah dari aplikasi kita, sering kali itu vendor/ atau library/ . Itu juga berada di namespace yang berbeda dan memiliki konvensi penamaan yang berbeda dari apa yang digunakan dalam aplikasi kita. Kode pihak ketiga cukup mudah untuk diidentifikasi dan, dengan sedikit disiplin, kita dapat membuat kode aplikasi kita kurang bergantung pada bagian pihak ketiga.

Bagaimana jika kita menerapkan aturan yang sama pada kode lama?


Bagaimana jika kita melihat kode warisan kita serta pihak ketiga? Ini bisa sulit dilakukan, atau bahkan kontraproduktif jika kode usang digunakan secara eksklusif dalam mode dukungan, ketika kita hanya memperbaiki bug dan sedikit menyesuaikan bagian kecilnya. Tetapi jika kita menulis kode baru yang (kembali) menggunakan kedaluwarsa, saya percaya bahwa itu layak untuk dipertimbangkan dengan cara yang sama seperti kode pihak ketiga. Setidaknya dari sudut pandang kode baru.

Jika memungkinkan, kode usang dan baru harus ditempatkan di folder dan ruang nama yang berbeda. Sudah lama sejak terakhir kali saya melihat sistem tanpa startup, jadi ini cukup bisa dilakukan. Tetapi alih-alih secara buta menggunakan kode warisan dalam kode baru, bagaimana jika kita membuat antarmuka untuk itu dan menggunakannya?

Kode usang sering kali penuh dengan objek "ilahi" yang melakukan terlalu banyak hal. Mereka menggunakan negara global, memiliki properti publik atau metode ajaib yang memberikan akses ke properti pribadi seolah-olah mereka publik, memiliki metode statis yang hanya sangat nyaman untuk memanggil siapa saja dan di mana saja. Jadi kenyamanan ini telah membawa kita pada situasi di mana kita berada.

Lain, mungkin masalah yang lebih serius dengan kode usang adalah bahwa kita siap untuk mengubahnya, memperbaikinya, memecahkannya karena kita tidak menganggapnya sebagai kode pihak ketiga. Apa yang kita lakukan ketika kita melihat bug atau ingin menambahkan fitur baru ke kode pihak ketiga? Kami menjelaskan masalah dan / atau membuat permintaan tarik. Yang tidak kami lakukan adalah tidak pergi ke vendor/ folder dan tidak mengedit kode di sana. Mengapa kita melakukan ini dengan kode lama? Dan kemudian kami menyilangkan jari kami dan berharap tidak ada yang rusak.

Alih-alih membabi buta menggunakan kode usang dalam kode baru, mari kita coba menulis antarmuka yang hanya akan menyertakan subset API yang diperlukan dari objek "ilahi" yang lama. Katakanlah kita memiliki objek User dalam kode lama yang mengetahui segalanya tentang segalanya. Dia tahu cara mengubah email dan kata sandi, cara meningkatkan pengguna forum ke moderator, cara memperbarui profil pengguna publik, menetapkan preferensi pemberitahuan, menyimpan dirinya sendiri dalam database dan banyak lagi.

src / Legacy / User.php
 <?php namespace Legacy; class User { public $email; public $password; public $role; public $name; public function promote($newRole) { $this->role = $newRole; } public function save() { db_layer::save($this); } } 

Ini adalah contoh kasar, tetapi mencerminkan masalahnya: setiap properti bersifat publik dan dapat dengan mudah diubah ke nilai apa pun, kita harus ingat untuk secara eksplisit memanggil metode save setelah perubahan apa pun untuk menyimpan, dll.

Mari membatasi diri dan melarang akses ke properti publik ini dan mencoba menerka bagaimana sistem yang sudah usang bekerja sambil meningkatkan hak pengguna:

src / LegacyBridge / Promoter.php
 <?php namespace LegacyBridge; interface Promoter { public function promoteTo(Role $role); } 

src / LegacyBridge / LegacyUserPromoter.php
 <?php namespace LegacyBridge; class LegacyUserPromoter implements Promoter { private $legacyUser; public function __construct(Legacy\User $user) { $this->legacyUser = $user; } public function promoteTo(Role $newRole) { $newRole = (string) $newRole; //  ,  $role     ?  ! $legacyRoles = [ Role::MODERATOR => 1, Role::MEMBER => 2, ]; $newLegacyRole = $legacyRoles[$newRole]; $this->legacyUser->promote($newLegacyRole); $this->legacyUser->save(); } } 

Sekarang, ketika kami ingin meningkatkan hak User dalam kode baru, kami menggunakan antarmuka LegacyBridge\Promoter , yang berkaitan dengan semua seluk-beluk meningkatkan pengguna dalam sistem yang ketinggalan zaman.

Ubah Bahasa Warisan


Antarmuka untuk kode yang ketinggalan zaman memberi kita kesempatan untuk meningkatkan desain sistem dan dapat menyelamatkan kita dari kemungkinan kesalahan penamaan yang dibuat sejak lama. Proses mengubah peran pengguna dari moderator menjadi peserta bukan "promosi" (kenaikan), melainkan "penurunan pangkat" (penurunan). Tidak ada yang menghentikan kita dari membuat dua antarmuka untuk hal-hal yang berbeda ini, bahkan jika kode sebelumnya terlihat sama.

src / LegacyBridge / Promoter.php
 <?php namespace LegacyBridge; interface Promoter { public function promoteTo(Role $role); } 

src / LegacyBridge / LegacyUserPromoter.php
 <?php namespace LegacyBridge; class LegacyUserPromoter implements Promoter { private $legacyUser; public function __construct(Legacy\User $user) { $this->legacyUser = $user; } public function promoteTo(Role $newRole) { if ($newRole->isMember()) { throw new \Exception("Can't promote to a member."); } $legacyMemberRole = 2; $this->legacyUser->promote($legacyMemberRole); $this->legacyUser->save(); } } 

src / LegacyBridge / Demoter.php
 <?php namespace LegacyBridge; interface Demoter { public function demoteTo(Role $role); } 

src / LegacyBridge / LegacyUserDemoter.php
 <?php namespace LegacyBridge; class LegacyUserDemoter implements Demoter { private $legacyUser; public function __construct(Legacy\User $user) { $this->legacyUser = $user; } public function demoteTo(Role $newRole) { if ($newRole->isModerator()) { throw new \Exception("Can't demote to a moderator."); } $legacyModeratorRole = 1; $this->legacyUser->promote($legacyModeratorRole); $this->legacyUser->save(); } } 


Bukan perubahan besar, tetapi tujuan kode jauh lebih jelas.

Sekarang, lain kali Anda perlu memanggil beberapa metode dari kode lama, cobalah membuat antarmuka untuk mereka. Itu tidak mungkin, bisa terlalu mahal. Saya tahu bahwa metode statis dari objek "ilahi" ini benar-benar sangat mudah digunakan dan dengan bantuannya Anda dapat melakukan pekerjaan lebih cepat, tetapi setidaknya pertimbangkan opsi ini. Anda hanya dapat sedikit meningkatkan desain sistem baru yang Anda buat.

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


All Articles