Haruskah saya menggunakan lapisan antara layanan dan repositori untuk arsitektur bersih - Spring


9

Saya bekerja dalam arsitektur, ia akan menawarkan api sisanya untuk klien web dan aplikasi seluler. Saya menggunakan Spring (pegas mvc, pegas data jpa, ... dll). Model domain dikodekan dengan spesifikasi JPA.

Saya mencoba menerapkan beberapa konsep arsitektur bersih ( https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html ). Tidak semua, karena saya akan mempertahankan model domain jpa.

Aliran aktual melalui lapisan adalah ini:

Ujung depan <--> Layanan API -> Layanan -> Repositori -> DB

  • Ujung depan : klien web, aplikasi seluler
  • Layanan API : Rest Controllers, di sini saya menggunakan konverter dan dto dan layanan panggilan
  • Layanan : Antarmuka dengan implementasi dan mengandung logika bisnis
  • Repositori : Antarmuka repositori dengan implementasi otomatis (dilakukan oleh pegas data jpa) yang mengendalikan operasi CRUD dan mungkin beberapa kueri sql

Keraguan saya: Haruskah saya menggunakan lapisan ekstra antara layanan dan repositori?

Saya merencanakan aliran baru ini:

Ujung depan <--> Layanan API -> Layanan -> Kegigihan -> Repositori -> DB

Mengapa menggunakan lapisan kegigihan ini? Seperti yang dikatakan dalam artikel arsitektur bersih saya ingin memiliki implementasi layanan (logika bisnis atau kasus penggunaan) yang mengakses lapisan ketekunan agnostik. Dan tidak akan diperlukan perubahan jika saya memutuskan untuk menggunakan pola "akses data" yang lain, misalnya jika saya memutuskan untuk berhenti menggunakan repositori.

class ProductServiceImpl implements ProductService {
    ProductRepository productRepository;
    void save(Product product) {
        // do business logic
        productRepository.save(product)
    }
}

Jadi saya berpikir menggunakan lapisan ketekunan seperti ini:

class ProductServiceImpl implements ProductService {
    ProductPersistence productPersistence;
    void save(Product product) {
        // do business logic
        productPersistence.save(product)
    }
}

dan implementasi dari layer persistence seperti ini:

class ProductPersistenceImpl implements ProductPersistence {
    ProductRepository productRepository;
    void save(Product product) {
        productRepository.save(product)
    }
}

Jadi saya hanya perlu mengubah implementasi layer persistence, meninggalkan layanan tanpa perubahan. Ditambah dengan fakta bahwa Repositori terkait dengan framework.

Bagaimana menurut anda? Terima kasih.


3
repositori ADALAH lapisan abstraksi. menambahkan satu lagi tidak membantu
Ewan

Oh, tapi saya harus menggunakan antarmuka yang diusulkan oleh Spring, maksud saya, nama metode repositori. Dan jika saya ingin mengubah repositori saya harus menyimpan nama panggilan, Tidak?
Alejandro

bagi saya sepertinya repositori pegas tidak memaksa Anda untuk mengekspos objek pegas. Cukup gunakan untuk mengimplementasikan antarmuka agnostik
Ewan

Jawaban:


6

Ujung depan <--> Layanan API -> Layanan -> Repositori -> DB

Baik. Ini adalah desain dasar dengan pemisahan masalah yang diusulkan oleh Spring Framework. Jadi Anda berada di " jalan yang benar Spring ".

Meskipun Repositori sering digunakan sebagai DAO, kebenarannya adalah bahwa pengembang Spring mengambil gagasan tentang Repositori dari Eric Evans 'DDD. Antarmuka repositori akan sering terlihat sangat mirip dengan DAO karena metode CRUD dan karena banyak pengembang berusaha untuk membuat antarmuka repositori begitu umum sehingga, pada akhirnya, mereka tidak memiliki perbedaan dengan EntityManager (DAO yang sebenarnya di sini) 1 tetapi dukungan dari pertanyaan dan kriteria.

Diterjemahkan ke dalam komponen Pegas, desain Anda mirip dengan

@RestController > @Service > @Repository >  EntityManager

Repositori sudah merupakan abstraksi di antara layanan dan penyimpanan data. Ketika kami memperluas antarmuka repositori Spring Data JPA, kami mengimplementasikan desain ini secara implisit. Ketika kami melakukan ini, kami membayar pajak: hubungan erat dengan komponen Spring. Selain itu, kami melanggar LoD dan YAGNI dengan mewarisi beberapa metode yang mungkin tidak perlu atau tidak ingin kami miliki. Belum lagi antarmuka seperti itu tidak memberi kami wawasan berharga tentang kebutuhan domain yang mereka layani.

Yang mengatakan, memperluas repositori Spring Data JPA tidak wajib dan Anda dapat menghindari pertukaran ini dengan menerapkan hierarki kelas yang lebih jelas dan khusus.

    @Repository
    public class MyRepositoryImpl implements MyRepository{
        private EntityManager em;

        @Autowire
        public MyRepository (EntityManager em){    
             this.em = em;
        }

        //Interface implentation
        //...
    }

Mengubah sumber data sekarang hanya membutuhkan implementasi baru yang menggantikan EntityManager dengan sumber data yang berbeda .

    //@RestController > @Service > @Repository >  RestTemplate

    @Repository
    public class MyRepositoryImpl implements MyRepository{
        private RestTemplate rt;

        @Autowire 
        public MyRepository (RestTemplate rt){    
             this.rt = rt;
        }

        //Interface implentation
        //...
    }
    //@RestController > @Service > @Repository >  File

    @Repository
    public class MyRepositoryImpl implements MyRepository{

        private File file; 
        public MyRepository (File file){    
            this.file = file;
        }

        //Interface implentation
        //...
    }
    //@RestController > @Service > @Repository >  SoapWSClient

    @Repository
    public class MyRepositoryImpl implements MyRepository{

        private MyWebServiceClient wsClient; 

        @Autowire
        public MyRepository (MyWebServiceClient  wsClient){    
               this.wsClient = wsClient;
        }

        //Interface implentation
        //...
    }

dan seterusnya. 2

Kembali ke pertanyaan, apakah Anda harus menambahkan satu lapisan abstraksi lagi, saya akan mengatakan tidak karena itu tidak perlu. Contoh Anda hanya menambah kompleksitas. Lapisan yang Anda usulkan akan berakhir sebagai proksi antara layanan dan repositori atau sebagai lapisan pseudo-layanan-repositori ketika logika tertentu diperlukan dan Anda tidak tahu di mana harus meletakkannya.


1: Tidak seperti yang dipikirkan banyak pengembang, antarmuka repositori dapat sangat berbeda satu sama lain karena setiap repositori melayani kebutuhan domain yang berbeda. Di Spring Data JPA, peran DAO dimainkan oleh EntityManager . Ia mengelola sesi, akses ke DataSource , pemetaan , dll.

2: Solusi serupa meningkatkan antarmuka repositori Spring yang mencampurkannya dengan antarmuka khusus. Untuk info lebih lanjut, cari BaseRepositoryFactoryBean dan @NoRepositoryBean . Namun, saya merasa pendekatan ini rumit dan membingungkan.


3

Cara terbaik untuk membuktikan bahwa suatu desain fleksibel adalah dengan melenturkannya.

Anda ingin tempat dalam kode Anda yang bertanggung jawab untuk kegigihan tetapi tidak terikat dengan ide menggunakan repositori. Baik. Itu tidak melakukan apa pun yang bermanfaat saat ini ... desah, baiklah.

OK, mari kita coba apakah lapisan shunt ini ada gunanya. Buat layer file datar yang akan bertahan produk Anda dalam file. Sekarang kemana lapisan baru ini masuk dalam desain ini?

Yah itu harus bisa pergi ke tempat DB. Lagipula kita tidak membutuhkan DB lagi karena kita menggunakan file flat. Tapi ini seharusnya juga tidak membutuhkan repositori.

Pertimbangkan, mungkin repositori adalah detail implementasi. Lagi pula saya bisa berbicara dengan DB tanpa menggunakan pola repositori.

Front end <--> API Service -> Service -> Repository -> DB

Front end <--> API Service -> Service -> Repository -> Files

Front end <--> API Service -> Service -> Persistence -> DB

Front end <--> API Service -> Service -> Persistence -> Files

Jika Anda dapat membuat semua itu berfungsi tanpa menyentuh Layanan, Anda memiliki kode yang fleksibel.

Tapi jangan mengambil kata-kata saya untuk itu. Tulis dan lihat apa yang terjadi. Satu-satunya kode yang saya percaya fleksibel adalah kode tertekuk.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.