Advertisement
  1. Code
  2. Web Development
Code

Refactoring Legacy Code: Bagian 8 - membalik dependensi untuk Clean Architecture

by
Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called Refactoring Legacy Code.
Refactoring Legacy Code: Part 7 - Identifying the Presentation Layer
Refactoring Legacy Code: Part 9 - Analyzing Concerns

Indonesian (Bahasa Indonesia) translation by Arief Syahrir (you can also view the original English article)

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

Sekarang saatnya untuk berbicara tentang arsitektur dan bagaimana kita mengatur lapisan baru kode kita. Saatnya untuk mengambil aplikasi kita dan mencoba untuk peta itu untuk desain arsitektur teoritis.

Clean Architecture

Ini adalah sesuatu yang kita lihat di seluruh artikel dan tutorial kami. Clean Architecture.

Pada high level, kelihatannya seperti skema di atas dan saya yakin Anda sudah akrab dengannya. Hal ini, solusi arsitektur yang diajukan oleh Robert C. Martin.

Di tengah-tengah arsitektur kami adalah logika bisnis kami. Ini adalah class yang mewakili proses bisnis aplikasi kita berusaha menyelesaikan. Ini adalah entitas dan interaksi yang mewakili domain masalah kita.

Kemudian, ada beberapa jenis lainnya dari modul atau kelas di sekitar logika bisnis kami. Ini dapat dilihat sebagai modul sederhana membantu bantu. Mereka memiliki berbagai keperluan dan kebanyakan dari mereka sangat diperlukan. Mereka menyediakan hubungan antara pengguna dan aplikasi kita melalui mekanisme pengiriman. Dalam kasus kami, ini adalah antarmuka command line. Ada satu set kelas pembantu yang menghubungkan logika bisnis kami untuk persistence layer kita dan semua data dalam layer itu, tapi kita tidak memiliki layer di aplikasi kita. Lalu ada helper class seperti factory dan builder yang membangun dan menyediakan objek baru untuk logika bisnis kami. Akhirnya ada kelas yang mewakili titik masuk ke sistem kami. Dalam kasus kami, GameRunner dapat dianggap seperti class, atau semua pengujian kami juga adalah titik masuk dalam cara mereka sendiri.

Apa yang paling penting untuk melihat pada diagram, adalah dependecy injection. Semua class pembantu tergantung pada logika bisnis. Logika bisnis tidak tergantung pada apa pun. Jika semua benda di logika bisnis kami bisa ajaib muncul, dengan semua data di dalamnya, dan kita bisa melihat apa pun yang terjadi di dalam komputer kita secara langsung, mereka harus mampu berfungsi. Logika bisnis kami harus dapat berfungsi tanpa UI atau tanpa layer persistence. Logika bisnis kami harus terisolasi, dalam gelembung semesta logis.

Prinsip Dependecy Inversion

High level modul tidak boleh bergantung pada tingkat rendah modul. Keduanya harus bergantung pada abstraksi.
B. abstraksi harus tidak tergantung pada rincian. Rincian harus tergantung pada abstraksi.

Ini adalah, prinsip SOLID dan mungkin satu dengan efek terbesar pada kode Anda. Hal ini cukup sederhana untuk memahami dan cukup sederhana untuk diterapkan.

Dalam istilah sederhana, ia mengatakan bahwa hal-hal konkrit harus selalu bergantung pada hal-hal yang abstrak. Database Anda sangat konkret, sehingga harus bergantung pada sesuatu yang lebih abstrak. UI sangat konkret, sehingga harus bergantung pada sesuatu yang lebih abstrak. factory sangat konkret lagi. Tapi apa tentang logika bisnis Anda. Dalam logika bisnis Anda Anda harus terus menerapkan ide-ide ini, sehingga class yang lebih dekat ke batas-batas tergantung pada class yang lebih abstrak, lebih di jantung logika bisnis Anda.

Logika bisnis murni, mewakili dalam cara yang abstrak, proses dan perilaku didefinisikan domain atau model bisnis. Logika bisnis seperti yang tidak mengandung spesifik (hal-hal konkrit) seperti nilai-nilai uang, nama account, password, ukuran tombol atau jumlah kolom dalam form. Logika bisnis tidak peduli tentang hal-hal konkret. Itu hanya harus peduli tentang proses bisnis Anda.

Trik teknis

Jadi, Dependecy Inversion Principel (DI{) mengatakan kita harus membalikkan dependensi kita setiap kali ada kode yang tergantung pada sesuatu yang konkret. Sekarang kami ketergantungan struktur tampak seperti ini.

GameRunner, menggunakan fungsi dalam RunnerFunctions.php adalah menciptakan class Game dan kemudian menggunakannya. Di sisi lain, class kami Game, mewakili logika bisnis kami, menciptakan dan menggunakan Display objek.

Jadi, pelari tergantung pada logika bisnis kami. Ini benar. Di sisi lain, Game kami tergantung pada Display, yang tidak baik. Logika bisnis kami seharusnya tidak bergantung pada presentasi kami.

Trik teknis paling sederhana yang dapat kita lakukan adalah untuk membuat penggunaan konstruksi abstrak dalam bahasa pemrograman kita. Sebuah class tradisional lebih konkret daripada class abstrak, yang lebih konkret daripada sebuah antarmuka.

class abstrak adalah jenis khusus yang tidak harus diinisialisasi. Ini berisi hanya definisi dan implementasi parsial. class dasar abstrak biasanya memiliki beberapa child class. class-class child ini yang mewarisi parsial fungsi umum dari parent abstrak, mereka menambahkan perilaku tambahan mereka sendiri, dan mereka harus melaksanakan semua metode didefinisikan di parent abstrak tetapi tidak diimplementasikan di dalamnya.

Interface adalah jenis khusus yang memungkinkan hanya definisi metode dan variabel. Ini adalah membangun paling abstrak dalam pemrograman berorientasi objek. Setiap implementasi selalu harus menerapkan semua metode parent interface. class konkret dapat menerapkan beberapa interface.

Kecuali bahasa berorientasi objek keluarga C, yang lain seperti Java atau PHP tidak mengizinkan pewarisan berganda. Jadi class konkret dapat memperpanjang class abstrak tunggal tetapi itu dapat menerapkan beberapa interface, bahkan pada saat yang sama jika diperlukan. Atau menaruh dari perspektif lain, kelas abstrak tunggal dapat memiliki banyak implementasi, sementara banyak antarmuka dapat memiliki banyak implementasi.

Untuk penjelasan lebih lengkap dari yang DIP, bacalah tutorial didedikasikan untuk prinsip SOLID.

Pembalikan ketergantungan yang menggunakan interface

PHP sepenuhnya mendukung interface. Mulai dari class Display sebagai model kita, kita bisa mendefinisikan sebuah interface dengan metode public semua class bertanggung jawab dengan menampilkan data akan perlu untuk mengimplementasikan.

Liat di Display daftar metode, ada 12 metode public, termasuk konstruktor. Ini adalah antarmuka cukup besar, Anda harus menyimpan nomor ini serendah mungkin, mengekspos interface sebagai klien membutuhkannya. Prinsip Interface Segregation Principle memiliki beberapa ide yang baik tentang hal ini. Mungkin kita akan mencoba untuk menangani masalah ini dalam nanti.

Sekarang apa yang ingin kita capai adalah arsitektur seperti berikut.

Dengan cara ini, bukan Game bergantung pada Display lebih konkret, keduanya tergantung pada interface sangat abstrak. Game menggunakan interface, sedangkan Display mengimplementasikannya.

Penamaan Interface

Phil Karlton berkata, "ada hanya dua hal yang sulit dalam ilmu komputer: cache penghapusan dan penamaan hal."

Sementara kita tidak peduli tentang cache, kita perlu untuk nama kelas kami, variabel, dan metode. Penamaan antarmuka dapat cukup tantangan.

Di hari tua notasi Hungaria, kita akan melakukannya dengan cara ini.

Diagram ini, kami menggunakan nama file class aktual dan kapitalisasi sebenarnya. Antarmuka ini disebut "IDisplay" dengan kapital "I" di depan "Display". Ada benar-benar bahasa pemrograman membutuhkan seperti penamaan untuk interface. Saya yakin ada beberapa pembaca masih menggunakan mereka dan tersenyum sekarang.

Masalah dengan skema penamaan ini adalah keprihatinan tempatnya. Antarmuka milik klien mereka. Antarmuka kami dimiliki Game. Dengan demikian Game harus tidak tahu menggunakan antarmuka atau objek asli. Game harus tidak peduli tentang pelaksanaan sebenarnya mendapat. Dari Game sudut pandang, hanya menggunakan "Display", itu saja.

Ini memecahkan Game ke Display masalah penamaan. Menggunakan akhiran "Impl" untuk implementasi agak lebih baik. Ini membantu menghilangkan kekhawatiran dari Game.

Hal ini juga jauh lebih efektif bagi kita. Berpikir tentang Game seperti yang terlihat sekarang. Itu menggunakan Display objek dan tahu bagaimana menggunakannya. Jika kita nama interface kami "Display", kami akan mengurangi jumlah perubahan yang dibutuhkan dalam Game.

Tapi tetap, penamaan ini hanya sedikit lebih baik daripada sebelumnya. Hal ini memungkinkan hanya satu implementasi untuk Display dan nama pelaksanaan tidak akan memberitahu kita apa jenis tampilan yang sedang kita bicarakan.

Nah, itu jauh lebih baik. Implementasi kami bernama "CLIDisplay", sebagai output untuk CLI. Jika kita ingin output HTML atau Windows desktop UI, kita dapat dengan mudah menambahkan semua yang arsitektur kami.

Tunjukkan kami kode

Seperti kita memiliki dua jenis tes, slow golder master dan unit test cepat, kami ingin bergantung pada unit test seperti yang kita bisa, dan di golden master sesedikit kita dapat. Jadi mari kita Tandai golder master tes sebagai melewatkan dan mencoba untuk mengandalkan unit tes. Mereka lewat sekarang dan kami ingin membuat perubahan yang akan membuat mereka sukses. Tapi bagaimana kita bisa melakukan hal seperti itu, tanpa melakukan semua perubahan yang diusulkan di atas?

Apakah ada cara untuk pengujian yang akan memungkinkan kita untuk mengambil langkah kecil?

Mocking menyelamatkan hari

Ada sedemikian rupa. Dalam pengujian, ada sebuah konsep yang disebut "Mocking".

Wikipedia mendefinisikan Mocking seperti itu, "Dalam pemrograman berorientasi objek, mock objek adalah simulasi objek yang meniru perilaku benda nyata dalam cara yang terkontrol."

Objek seperti itu akan sangat membantu bagi kita. Pada kenyataannya, kita bahkan tidak perlu sesuatu yang rumit seperti simulasi semua perilaku. Semua yang kita butuhkan adalah sebuah objek yang fake, bodoh yang kami dapat mengirimkan Game bukan logika nyata tampilan.

Menciptakan interface

Mari kita membuat sebuah antarmuka yang disebut Display dengan semua metode umum class konkret saat ini.

Seperti Anda dapat mengamati, Display.php diubah namanya menjadi DisplayOld.php. Ini adalah hanya satu langkah sementara, yang memungkinkan kita untuk mengambil keluar dari jalan dan berkonsentrasi pada interface.

Thats semua ada untuk menciptakan sebuah interface. Anda dapat melihat bahwa ini didefinisikan sebagai "interface" dan bukan sebagai "class". Mari kita menambahkan metode.

Ya. interface adalah hanya sekelompok Deklarasi fungsi. Bayangkan itu sebagai C header file. Tidak ada implementasi, hanya Deklarasi. Itu tidak bisa memegang sebuah implementasi sama sekali. Jika Anda mencoba untuk menerapkan salah satu metode, itu akan menghasilkan kesalahan.

Tapi definisi ini sangat abstrak memungkinkan kita sesuatu yang indah. class kami Game sekarang tergantung pada mereka, bukan sebuah implementasi konkret. Namun, jika kita mencoba untuk menjalankan tes kami, mereka akan gagal.

Itu karena Game mencoba untuk menciptakan tampilan baru sendiri di baris 25, dalam konstruktor.

Kita tahu kita tidak bisa melakukan itu. interface atau class abstrak tidak dapat instantiated. Kita perlu objek asli.

Dependecy Injection

Kita membutuhkan sebuah objek dummy untuk digunakan dalam pengujian kami. class sederhana, menerapkan semua metode Display interface, tetapi tidak melakukan apa-apa. Mari kita menulis secara langsung di dalam unit tes. Jika bahasa pemrograman Anda tidak mengizinkan beberapa class pada file yang sama, merasa bebas untuk membuat file baru untuk class dummy anda.

Segera setelah Anda mengatakan class Anda mengimplementasikan interfface, IDE akan memungkinkan Anda untuk secara otomatis mengisi metode yang hilang. Hal ini membuat membuat objek tersebut sangat cepat, hanya dalam beberapa detik.

Sekarang mari kita menggunakannya dalam Game dengan inisialisasi dalam konstruktor nya.

Hal ini membuat tes sukses, tetapi memperkenalkan masalah besar. Game harus tahu tentang tes nya. Kami benar-benar tidak ingin ini. Tes ini hanyalah titik masuk. DummyDisplay adalah hanya salah satu interface pengguna. Logika bisnis kami, class Game, seharusnya tidak bergantung pada UI. Jadi mari kita membuat tergantung hanya pada interface.

Tapi untuk menguji Game, kita perlu mengirim di display dummy dari pengujian kami.

Thats it. Kami perlu untuk memodifikasi satu barus dalam unit tes. Dalam setup, dan kami akan mengirimkan, sebagai parameter, sebuah instance baru dari DummyDisplay. Itulah dependecy injection. Menggunakan interface dan dependecy injection membantu terutama jika Anda bekerja dalam sebuah tim. Kami di Syneto mengamati dan menentukan interface tipe untuk class dan menyuntikkan itu, akan membantu kita berkomunikasi lebih baik niat dari kode klien. Siapapun di klien akan tahu apa jenis objek yang digunakan dalam parameter. Dan bonus keren adalah bahwa IDE Anda akan autocomplete metode untuk parameter tersebut karena dapat menentukan jenis mereka.

Implementasi yang asli untuk Golden Master

Golden master tes, menjalankan kode kita dalam dunia nyata. Untuk membuat hal itu berlalu, kita perlu mengubah tampilan clas kami lama menjadi nyata implementasi interface dan mengirimkannya ke logika bisnis kami. Berikut adalah salah satu cara untuk melakukannya.

Gnati nama menjadi CLIDisplay dan membuatnya menerapkan Display.

Dalam RunnerFunctions.php, dalam fungsi run(), membuat tampilan baru untuk CLI dan masukan ke Game ketika dibuat.

uncomment dan menjalankan tes golden master tes. Mereka akan sukses.

Akhir pikiran

Solusi ini secara efektif menyebabkan arsitektur seperti pada diagram berikut.

Jadi sekarang game runner, yang merupakan titik masuk ke aplikasi kita, menciptakan CLIDisplay beton dan dengan demikian tergantung pada hal itu. CLIDisplay tergantung hanya pada interface yang terletak di perbatasan antara logika bisnis dan presentasi. Runner kami juga secara langsung tergantung pada logika bisnis. Ini adalah bagaimana aplikasi kita terlihat seperti ketika diproyeksikan pada clean architecture yang kita mulai artikel ini.

Terima kasih telah membaca, dan jangan lewatkan tutorial selanjutnya ketika kita akan berbicara tentang interaksi mokcing dan class dalam rincian lebih lanjut.

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

Sekarang saatnya untuk berbicara tentang arsitektur dan bagaimana kita mengatur lapisan baru kode kita. Saatnya untuk mengambil aplikasi kita dan mencoba untuk peta itu untuk desain arsitektur teoritis.

Clean Architecture

Ini adalah sesuatu yang kita lihat di seluruh artikel dan tutorial kami. Clean Architecture.

Pada high level, kelihatannya seperti skema di atas dan saya yakin Anda sudah akrab dengannya. Hal ini, solusi arsitektur yang diajukan oleh Robert C. Martin.

Di tengah-tengah arsitektur kami adalah logika bisnis kami. Ini adalah class yang mewakili proses bisnis aplikasi kita berusaha menyelesaikan. Ini adalah entitas dan interaksi yang mewakili domain masalah kita.

Kemudian, ada beberapa jenis lainnya dari modul atau kelas di sekitar logika bisnis kami. Ini dapat dilihat sebagai modul sederhana membantu bantu. Mereka memiliki berbagai keperluan dan kebanyakan dari mereka sangat diperlukan. Mereka menyediakan hubungan antara pengguna dan aplikasi kita melalui mekanisme pengiriman. Dalam kasus kami, ini adalah antarmuka command line. Ada satu set kelas pembantu yang menghubungkan logika bisnis kami untuk persistence layer kita dan semua data dalam layer itu, tapi kita tidak memiliki layer di aplikasi kita. Lalu ada helper class seperti factory dan builder yang membangun dan menyediakan objek baru untuk logika bisnis kami. Akhirnya ada kelas yang mewakili titik masuk ke sistem kami. Dalam kasus kami, GameRunner dapat dianggap seperti class, atau semua pengujian kami juga adalah titik masuk dalam cara mereka sendiri.

Apa yang paling penting untuk melihat pada diagram, adalah dependecy injection. Semua class pembantu tergantung pada logika bisnis. Logika bisnis tidak tergantung pada apa pun. Jika semua benda di logika bisnis kami bisa ajaib muncul, dengan semua data di dalamnya, dan kita bisa melihat apa pun yang terjadi di dalam komputer kita secara langsung, mereka harus mampu berfungsi. Logika bisnis kami harus dapat berfungsi tanpa UI atau tanpa layer persistence. Logika bisnis kami harus terisolasi, dalam gelembung semesta logis.

Prinsip Dependecy Inversion

High level modul tidak boleh bergantung pada tingkat rendah modul. Keduanya harus bergantung pada abstraksi.
B. abstraksi harus tidak tergantung pada rincian. Rincian harus tergantung pada abstraksi.

Ini adalah, prinsip SOLID dan mungkin satu dengan efek terbesar pada kode Anda. Hal ini cukup sederhana untuk memahami dan cukup sederhana untuk diterapkan.

Dalam istilah sederhana, ia mengatakan bahwa hal-hal konkrit harus selalu bergantung pada hal-hal yang abstrak. Database Anda sangat konkret, sehingga harus bergantung pada sesuatu yang lebih abstrak. UI sangat konkret, sehingga harus bergantung pada sesuatu yang lebih abstrak. factory sangat konkret lagi. Tapi apa tentang logika bisnis Anda. Dalam logika bisnis Anda Anda harus terus menerapkan ide-ide ini, sehingga class yang lebih dekat ke batas-batas tergantung pada class yang lebih abstrak, lebih di jantung logika bisnis Anda.

Logika bisnis murni, mewakili dalam cara yang abstrak, proses dan perilaku didefinisikan domain atau model bisnis. Logika bisnis seperti yang tidak mengandung spesifik (hal-hal konkrit) seperti nilai-nilai uang, nama account, password, ukuran tombol atau jumlah kolom dalam form. Logika bisnis tidak peduli tentang hal-hal konkret. Itu hanya harus peduli tentang proses bisnis Anda.

Trik teknis

Jadi, Dependecy Inversion Principel (DI{) mengatakan kita harus membalikkan dependensi kita setiap kali ada kode yang tergantung pada sesuatu yang konkret. Sekarang kami ketergantungan struktur tampak seperti ini.

GameRunner, menggunakan fungsi dalam RunnerFunctions.php adalah menciptakan class Game dan kemudian menggunakannya. Di sisi lain, class kami Game, mewakili logika bisnis kami, menciptakan dan menggunakan Display objek.

Jadi, pelari tergantung pada logika bisnis kami. Ini benar. Di sisi lain, Game kami tergantung pada Display, yang tidak baik. Logika bisnis kami seharusnya tidak bergantung pada presentasi kami.

Trik teknis paling sederhana yang dapat kita lakukan adalah untuk membuat penggunaan konstruksi abstrak dalam bahasa pemrograman kita. Sebuah class tradisional lebih konkret daripada class abstrak, yang lebih konkret daripada sebuah antarmuka.

class abstrak adalah jenis khusus yang tidak harus diinisialisasi. Ini berisi hanya definisi dan implementasi parsial. class dasar abstrak biasanya memiliki beberapa child class. class-class child ini yang mewarisi parsial fungsi umum dari parent abstrak, mereka menambahkan perilaku tambahan mereka sendiri, dan mereka harus melaksanakan semua metode didefinisikan di parent abstrak tetapi tidak diimplementasikan di dalamnya.

Interface adalah jenis khusus yang memungkinkan hanya definisi metode dan variabel. Ini adalah membangun paling abstrak dalam pemrograman berorientasi objek. Setiap implementasi selalu harus menerapkan semua metode parent interface. class konkret dapat menerapkan beberapa interface.

Kecuali bahasa berorientasi objek keluarga C, yang lain seperti Java atau PHP tidak mengizinkan pewarisan berganda. Jadi class konkret dapat memperpanjang class abstrak tunggal tetapi itu dapat menerapkan beberapa interface, bahkan pada saat yang sama jika diperlukan. Atau menaruh dari perspektif lain, kelas abstrak tunggal dapat memiliki banyak implementasi, sementara banyak antarmuka dapat memiliki banyak implementasi.

Untuk penjelasan lebih lengkap dari yang DIP, bacalah tutorial didedikasikan untuk prinsip SOLID.

Pembalikan ketergantungan yang menggunakan interface

PHP sepenuhnya mendukung interface. Mulai dari class Display sebagai model kita, kita bisa mendefinisikan sebuah interface dengan metode public semua class bertanggung jawab dengan menampilkan data akan perlu untuk mengimplementasikan.

Liat di Display daftar metode, ada 12 metode public, termasuk konstruktor. Ini adalah antarmuka cukup besar, Anda harus menyimpan nomor ini serendah mungkin, mengekspos interface sebagai klien membutuhkannya. Prinsip Interface Segregation Principle memiliki beberapa ide yang baik tentang hal ini. Mungkin kita akan mencoba untuk menangani masalah ini dalam nanti.

Sekarang apa yang ingin kita capai adalah arsitektur seperti berikut.

Dengan cara ini, bukan Game bergantung pada Display lebih konkret, keduanya tergantung pada interface sangat abstrak. Game menggunakan interface, sedangkan Display mengimplementasikannya.

Penamaan Interface

Phil Karlton berkata, "ada hanya dua hal yang sulit dalam ilmu komputer: cache penghapusan dan penamaan hal."

Sementara kita tidak peduli tentang cache, kita perlu untuk nama kelas kami, variabel, dan metode. Penamaan antarmuka dapat cukup tantangan.

Di hari tua notasi Hungaria, kita akan melakukannya dengan cara ini.

Diagram ini, kami menggunakan nama file class aktual dan kapitalisasi sebenarnya. Antarmuka ini disebut "IDisplay" dengan kapital "I" di depan "Display". Ada benar-benar bahasa pemrograman membutuhkan seperti penamaan untuk interface. Saya yakin ada beberapa pembaca masih menggunakan mereka dan tersenyum sekarang.

Masalah dengan skema penamaan ini adalah keprihatinan tempatnya. Antarmuka milik klien mereka. Antarmuka kami dimiliki Game. Dengan demikian Game harus tidak tahu menggunakan antarmuka atau objek asli. Game harus tidak peduli tentang pelaksanaan sebenarnya mendapat. Dari Game sudut pandang, hanya menggunakan "Display", itu saja.

Ini memecahkan Game ke Display masalah penamaan. Menggunakan akhiran "Impl" untuk implementasi agak lebih baik. Ini membantu menghilangkan kekhawatiran dari Game.

Hal ini juga jauh lebih efektif bagi kita. Berpikir tentang Game seperti yang terlihat sekarang. Itu menggunakan Display objek dan tahu bagaimana menggunakannya. Jika kita nama interface kami "Display", kami akan mengurangi jumlah perubahan yang dibutuhkan dalam Game.

Tapi tetap, penamaan ini hanya sedikit lebih baik daripada sebelumnya. Hal ini memungkinkan hanya satu implementasi untuk Display dan nama pelaksanaan tidak akan memberitahu kita apa jenis tampilan yang sedang kita bicarakan.

Nah, itu jauh lebih baik. Implementasi kami bernama "CLIDisplay", sebagai output untuk CLI. Jika kita ingin output HTML atau Windows desktop UI, kita dapat dengan mudah menambahkan semua yang arsitektur kami.

Tunjukkan kami kode

Seperti kita memiliki dua jenis tes, slow golder master dan unit test cepat, kami ingin bergantung pada unit test seperti yang kita bisa, dan di golden master sesedikit kita dapat. Jadi mari kita Tandai golder master tes sebagai melewatkan dan mencoba untuk mengandalkan unit tes. Mereka lewat sekarang dan kami ingin membuat perubahan yang akan membuat mereka sukses. Tapi bagaimana kita bisa melakukan hal seperti itu, tanpa melakukan semua perubahan yang diusulkan di atas?

Apakah ada cara untuk pengujian yang akan memungkinkan kita untuk mengambil langkah kecil?

Mocking menyelamatkan hari

Ada sedemikian rupa. Dalam pengujian, ada sebuah konsep yang disebut "Mocking".

Wikipedia mendefinisikan Mocking seperti itu, "Dalam pemrograman berorientasi objek, mock objek adalah simulasi objek yang meniru perilaku benda nyata dalam cara yang terkontrol."

Objek seperti itu akan sangat membantu bagi kita. Pada kenyataannya, kita bahkan tidak perlu sesuatu yang rumit seperti simulasi semua perilaku. Semua yang kita butuhkan adalah sebuah objek yang fake, bodoh yang kami dapat mengirimkan Game bukan logika nyata tampilan.

Menciptakan interface

Mari kita membuat sebuah antarmuka yang disebut Display dengan semua metode umum class konkret saat ini.

Seperti Anda dapat mengamati, Display.php diubah namanya menjadi DisplayOld.php. Ini adalah hanya satu langkah sementara, yang memungkinkan kita untuk mengambil keluar dari jalan dan berkonsentrasi pada interface.

Thats semua ada untuk menciptakan sebuah interface. Anda dapat melihat bahwa ini didefinisikan sebagai "interface" dan bukan sebagai "class". Mari kita menambahkan metode.

Ya. interface adalah hanya sekelompok Deklarasi fungsi. Bayangkan itu sebagai C header file. Tidak ada implementasi, hanya Deklarasi. Itu tidak bisa memegang sebuah implementasi sama sekali. Jika Anda mencoba untuk menerapkan salah satu metode, itu akan menghasilkan kesalahan.

Tapi definisi ini sangat abstrak memungkinkan kita sesuatu yang indah. class kami Game sekarang tergantung pada mereka, bukan sebuah implementasi konkret. Namun, jika kita mencoba untuk menjalankan tes kami, mereka akan gagal.

Itu karena Game mencoba untuk menciptakan tampilan baru sendiri di baris 25, dalam konstruktor.

Kita tahu kita tidak bisa melakukan itu. interface atau class abstrak tidak dapat instantiated. Kita perlu objek asli.

Dependecy Injection

Kita membutuhkan sebuah objek dummy untuk digunakan dalam pengujian kami. class sederhana, menerapkan semua metode Display interface, tetapi tidak melakukan apa-apa. Mari kita menulis secara langsung di dalam unit tes. Jika bahasa pemrograman Anda tidak mengizinkan beberapa class pada file yang sama, merasa bebas untuk membuat file baru untuk class dummy anda.

Segera setelah Anda mengatakan class Anda mengimplementasikan interfface, IDE akan memungkinkan Anda untuk secara otomatis mengisi metode yang hilang. Hal ini membuat membuat objek tersebut sangat cepat, hanya dalam beberapa detik.

Sekarang mari kita menggunakannya dalam Game dengan inisialisasi dalam konstruktor nya.

Hal ini membuat tes sukses, tetapi memperkenalkan masalah besar. Game harus tahu tentang tes nya. Kami benar-benar tidak ingin ini. Tes ini hanyalah titik masuk. DummyDisplay adalah hanya salah satu interface pengguna. Logika bisnis kami, class Game, seharusnya tidak bergantung pada UI. Jadi mari kita membuat tergantung hanya pada interface.

Tapi untuk menguji Game, kita perlu mengirim di display dummy dari pengujian kami.

Thats it. Kami perlu untuk memodifikasi satu barus dalam unit tes. Dalam setup, dan kami akan mengirimkan, sebagai parameter, sebuah instance baru dari DummyDisplay. Itulah dependecy injection. Menggunakan interface dan dependecy injection membantu terutama jika Anda bekerja dalam sebuah tim. Kami di Syneto mengamati dan menentukan interface tipe untuk class dan menyuntikkan itu, akan membantu kita berkomunikasi lebih baik niat dari kode klien. Siapapun di klien akan tahu apa jenis objek yang digunakan dalam parameter. Dan bonus keren adalah bahwa IDE Anda akan autocomplete metode untuk parameter tersebut karena dapat menentukan jenis mereka.

Implementasi yang asli untuk Golden Master

Golden master tes, menjalankan kode kita dalam dunia nyata. Untuk membuat hal itu berlalu, kita perlu mengubah tampilan clas kami lama menjadi nyata implementasi interface dan mengirimkannya ke logika bisnis kami. Berikut adalah salah satu cara untuk melakukannya.

Gnati nama menjadi CLIDisplay dan membuatnya menerapkan Display.

Dalam RunnerFunctions.php, dalam fungsi run(), membuat tampilan baru untuk CLI dan masukan ke Game ketika dibuat.

uncomment dan menjalankan tes golden master tes. Mereka akan sukses.

Akhir pikiran

Solusi ini secara efektif menyebabkan arsitektur seperti pada diagram berikut.

Jadi sekarang game runner, yang merupakan titik masuk ke aplikasi kita, menciptakan CLIDisplay beton dan dengan demikian tergantung pada hal itu. CLIDisplay tergantung hanya pada interface yang terletak di perbatasan antara logika bisnis dan presentasi. Runner kami juga secara langsung tergantung pada logika bisnis. Ini adalah bagaimana aplikasi kita terlihat seperti ketika diproyeksikan pada clean architecture yang kita mulai artikel ini.

Terima kasih telah membaca, dan jangan lewatkan tutorial selanjutnya ketika kita akan berbicara tentang interaksi mokcing dan class dalam rincian lebih lanjut.

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.