Lebih dari lapisan konsentris



Artikel ini adalah bagian dari Kronik Arsitektur Perangkat Lunak , serangkaian artikel tentang arsitektur perangkat lunak. Di dalamnya saya menulis tentang apa yang saya pelajari tentang arsitektur perangkat lunak, apa yang saya pikirkan dan bagaimana saya menggunakan pengetahuan. Konten artikel ini mungkin lebih masuk akal jika Anda membaca artikel sebelumnya dalam seri.

Dalam artikel sebelumnya dalam seri ini, saya menerbitkan peta konsep yang menunjukkan hubungan antara tipe kode.

Tetapi bagi saya selalu tampak bahwa tidak semuanya tercermin dengan baik di sana, saya hanya tidak tahu bagaimana melakukannya dengan lebih baik. Ini tentang inti bersama.

Selain itu, beberapa pemikiran telah muncul yang akan saya uraikan dalam artikel singkat ini.

Dalam infografis dari artikel terakhir dalam seri ini, di bagian paling tengah diagram, kita melihat inti bersama. Tampaknya terletak di dalam lapisan domain dan di atas bagian kerucut, yang merupakan konteks terbatas.



Terlepas dari lokasinya, saya tidak bermaksud bahwa inti umum bergantung pada sisa kode atau bahwa inti umum adalah lapisan lain di dalam tingkat domain.

Apa itu inti bersama ?!


Inti umum, seperti yang didefinisikan oleh Eric Evans, bapak DDD, adalah kode yang diputuskan oleh tim pengembangan untuk dibagi di antara beberapa konteks terbatas:

[...] himpunan bagian dari model domain yang disetujui kedua tim untuk digunakan bersama. Tentu saja, bersama dengan subset dari model ini, inti umum termasuk subset dari kode atau arsitektur basis data yang terkait dengan bagian dari model ini. Materi umum yang jelas ini memiliki status khusus dan tidak boleh diubah tanpa berkonsultasi dengan tim lain.

- “Common Kernel” , DDD Wiki dari Ward Cunningham

Dengan demikian, dapat berupa semua jenis kode: kode tingkat domain, kode tingkat aplikasi, perpustakaan ... apa pun.



Namun, dalam konteks peta konsep kami, saya menyajikannya sebagai subset, sebagai jenis kode tertentu. Dalam peta konsep saya, inti umum berisi kode untuk tingkat domain dan aplikasi, yang dibagikan dalam konteks terbatas sehingga komunikasi antara konteks terbatas dimungkinkan.

Misalnya, ini berarti bahwa peristiwa dipecat dalam satu atau lebih konteks terbatas dan didengarkan dalam konteks terbatas lainnya. Bersama-sama dengan peristiwa ini, kita perlu membagikan semua tipe data yang digunakan oleh peristiwa ini, misalnya: pengidentifikasi entitas, objek nilai, enumerasi, dll. Objek kompleks seperti entitas tidak boleh digunakan secara langsung oleh peristiwa, karena mereka bisa sulit serialize / deserialize ke / dari antrian, sehingga kode generik tidak boleh didistribusikan secara luas.

Tentu saja, jika kita memiliki sistem multibahasa layanan microser, maka inti bersama harus deskriptif, dalam JSON, XML, YAML, dll., Sehingga semua layanan microser dapat memahaminya.

Sebagai hasilnya, inti umum ini benar-benar dipisahkan dari sisa basis kode, dari komponen. Ini luar biasa, karena komponen-komponen itu, walaupun terhubung dengan inti bersama, dipisahkan satu sama lain. Kode generik secara eksplisit diidentifikasi dan mudah diambil ke perpustakaan yang terpisah.

Juga sangat mudah jika kita memutuskan untuk mengekstraksi salah satu konteks terbatas ke dalam layanan mikro, terpisah dari monolit. Kami tahu pasti apa yang umum dan hanya dapat mengekstrak inti umum ke perpustakaan, yang akan dipasang baik di monolith dan di microservice.

Jadi, untuk meringkas, dalam peta konsep saya, inti aplikasi tergantung pada kernel umum yang berisi kode dari domain dan level aplikasi yang dibagi antara konteks terbatas.

Ketika bahasa tidak cukup ...


Jadi, kami memiliki kode aplikasi dengan semua lapisan konsentris, dan inti aplikasi tergantung pada inti umum, yang berada di bawah semua kode ini.

Kita juga dapat mengatakan bahwa semua kode ini tergantung pada bahasa pemrograman yang digunakan, tetapi ini adalah fakta yang sangat jelas sehingga kita cenderung mengabaikannya.

Namun, muncul pertanyaan: "Bagaimana jika bahasa yang dikonstruksikan tidak cukup?!" Yah, jelas, kami membuat konstruksi bahasa ini sendiri dan dengan demikian mengkompensasi kekurangan bahasa. Tetapi saya memiliki pertanyaan penting lanjutan: “Bagaimana dan di mana untuk membenarkan keberadaan kode ini? Bagaimana seseorang dapat dengan jelas menunjukkan kapan dan bagaimana menggunakannya? "

Apa yang saya lihat dan lakukan sendiri adalah paket yang disebut Utils atau Commons, tempat kode ini berada. Namun pada akhirnya, kami akhirnya membuang semua kode di sana, yang kami tidak tahu harus meletakkan di mana! Semua jenis kode untuk tujuan yang berbeda dan kemudahan penggunaan (dibungkus dengan adaptor yang digunakan langsung ...) akhirnya dibuang ke sana. Paket tidak memiliki makna konseptual, tidak ada koherensi, tidak ada koherensi, tidak ada kejelasan, banyak ambiguitas.

Saya ingin meninggalkan paket Utils and Commons!

Semua paket harus memiliki kohesi konseptual! Harus jelas kapan dan bagaimana menggunakan paket! Tidak ada ambiguitas!

Misalnya, jika aplikasi berinteraksi dengan antarmuka baris perintah dalam beberapa cara khusus, maka alih-alih menempatkan 'Acme / Util / SpecialCli' di namespace, Anda dapat menempatkannya di 'Acme / App / Infrastructure / Cli / SpecialCli'. Ini mengatakan bahwa paket ini dikaitkan dengan CLI, itu adalah bagian dari infrastruktur aplikasi Acme App. Afiliasi dengan infrastruktur App juga mengatakan bahwa ada port di kernel aplikasi yang sesuai dengan paket ini.

Atau, jika kita melihat paket ini sebagai sesuatu yang kurang dimiliki oleh bahasa itu sendiri, kita dapat meletakkannya di namespace yang sesuai, misalnya, 'Acme / PhpExtension / SpecialCli'. Ini menunjukkan bahwa paket ini harus dianggap sebagai bagian dari bahasa itu sendiri, dan oleh karena itu kodenya harus digunakan langsung dalam basis kode seperti konstruksi bahasa apa pun. Tentu saja, jika perusahaan lain bergantung pada paket ini, mungkin masuk akal bagi mereka untuk tidak bergantung langsung pada paket tersebut, tetapi lebih aman untuk membuat port / adaptor sehingga mereka dapat menukarnya dengan yang lain. Tetapi jika kita memiliki paket, kita dapat menganggapnya sebagai bagian dari bahasa, karena risiko harus menggantinya dengan alternatif lain tidak begitu besar. Kompromi selalu menjadi masalahnya.

Contoh lain dari apa yang dapat dianggap sebagai bagian dari bahasa adalah UUID unik dalam PHP. Sangat mungkin untuk membayangkan mereka di luar bahasa, karena setiap kali ada versi baru dan itu adalah mimpi buruk dengan dukungan kode, tetapi ini adalah konsep yang sangat umum, konsep yang luas dan cukup konsisten untuk menjadi bagian dari bahasa.

Jadi mengapa tidak membuat implementasi UUID dan menggunakannya seperti bagian dari PHP itu sendiri, bagaimana kita menggunakan objek DateTime ?! Sementara kami mengontrol implementasinya, saya tidak melihat kekurangan.

Bagaimana dengan Bahasa Query Doctrine (DQL)? (Doktrin adalah port Hibernate di PHP) dapatkah kita melihat DQL seolah-olah SQL, Elasticsearch QL, atau Mongo QL?

Kesimpulan


Jadi, pada level makro, saya melihat empat tipe dasar kode dan saya pikir penting untuk menunjukkannya dengan jelas di organisasi basis kode, agar tidak berakhir dengan banyak kotoran.



Bagi saya, kebenaran yang tidak dapat disangkal adalah bahwa arsitektur selalu ada, satu-satunya pertanyaan adalah apakah kita mengendalikannya atau tidak?!

Jadi mari kita mengatur kode dengan jelas sesuai dengan arsitektur , secara keseluruhan atau sebagian, pada peta konsep - milik saya atau yang lain. Hal utama adalah mengatur kode sehingga proyek secara eksplisit melaporkan arsitekturnya melalui struktur dan organisasi kode.

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


All Articles