क्या मुझे स्वच्छ वास्तुकला के लिए सेवा और भंडार के बीच एक परत का उपयोग करना चाहिए - वसंत


9

मैं एक आर्किटेक्चर में काम कर रहा हूं, यह वेब क्लाइंट और मोबाइल एप्स के लिए आराम एपी पेश करने जा रहा है। मैं स्प्रिंग (स्प्रिंग mvc, स्प्रिंग डेटा jpa, ... आदि) का उपयोग कर रहा हूं। डोमेन मॉडल को जेपीए विनिर्देश के साथ कोडित किया गया है।

मैं स्वच्छ वास्तुकला ( https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-Healthecture.html ) की कुछ अवधारणाओं को लागू करने की कोशिश कर रहा हूं । सभी नहीं, क्योंकि मैं jpa डोमेन मॉडल रखने जा रहा हूं।

परतों के माध्यम से वास्तविक प्रवाह यह है:

फ्रंट एंड <-> एपीआई सर्विस -> सर्विस -> रिपोजिटरी -> डीबी

  • फ्रंट एंड : वेब क्लाइंट, मोबाइल ऐप्स
  • API सेवा : बाकी नियंत्रकों, यहाँ मैं कन्वर्टर्स और dto's और कॉल सेवाओं का उपयोग करता हूँ
  • सेवा : कार्यान्वयन के साथ इंटरफेस और उनमें व्यावसायिक तर्क होते हैं
  • रिपोजिटरी : रिपोजिटरी इंटरफेस स्वचालित रूप से कार्यान्वयन (स्प्रिंग डेटा जपा द्वारा किया गया) के साथ होता है, जो सीआरयूआईडी ऑपरेशन और शायद कई एसक्यूएल प्रश्न होते हैं।

मेरा संदेह: क्या मुझे सेवा और भंडार के बीच एक अतिरिक्त परत का उपयोग करना चाहिए?

मैं इस नए प्रवाह की योजना बना रहा हूं:

सामने का छोर <-> एपीआई सेवा -> सेवा -> दृढ़ता -> भंडार -> DB

इस दृढ़ता परत का उपयोग क्यों करें? जैसा कि स्वच्छ वास्तुकला लेख में कहा गया है कि मैं एक सेवा कार्यान्वयन (व्यावसायिक तर्क या उपयोग का मामला) करना चाहूंगा जो एक अज्ञेयवादी निरंतर परत तक पहुंच सके। और परिवर्तनों की आवश्यकता नहीं होगी यदि मैं एक और "डेटा एक्सेस" पैटर्न का उपयोग करने का निर्णय लेता हूं, उदाहरण के लिए यदि मैं रिपॉजिटरी का उपयोग बंद करने का निर्णय लेता हूं।

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

तो मैं सोच रहा हूँ कि इस तरह एक दृढ़ता परत का उपयोग करें:

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

और इस तरह दृढ़ता परत का कार्यान्वयन:

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

इसलिए मुझे केवल दृढ़ता परत के कार्यान्वयन को बदलने की आवश्यकता है, बिना परिवर्तन के सेवा छोड़ दी। इस तथ्य के साथ कि रिपॉजिटरी ढांचे से संबंधित है।

तुम क्या सोचते हो? धन्यवाद।


3
रिपॉजिटरी अमूर्त परत है। एक और एक मदद जोड़ने
इवान

ओह, लेकिन मुझे स्प्रिंग द्वारा प्रस्तावित इंटरफ़ेस का उपयोग करना होगा, मेरा मतलब है, रिपॉजिटरी विधि के नाम। और अगर मैं रिपॉजिटरी बदलना चाहता हूं तो मुझे कॉलिंग नाम रखना होगा, नहीं?
अलेजांद्रो

यह मुझे ऐसा लगता है जैसे वसंत भंडार वस्तु आपको वसंत वस्तुओं को उजागर करने के लिए मजबूर नहीं करती है। बस अज्ञेय इंटरफ़ेस को लागू करने के लिए इसका उपयोग करें
ईवान

जवाबों:


6

फ्रंट एंड <-> एपीआई सर्विस -> सर्विस -> रिपोजिटरी -> डीबी

सही। स्प्रिंग फ्रेमवर्क द्वारा प्रस्तावित चिंताओं के अलगाव से यह मूल डिजाइन है। तो आप " वसंत के सही तरीके " में हैं।

रिपॉजिटरी के बावजूद अक्सर डीएओ के रूप में उपयोग किया जाता है, सच्चाई यह है कि स्प्रिंग डेवलपर्स ने एरिक इवांस / डीडीडी से रिपॉजिटरी की धारणा को लिया । भंडार इंटरफेस अक्सर बहुत क्योंकि CRUD तरीकों में से DAOs के समान दिखाई और होगा, क्योंकि कई डेवलपर्स खजाने 'इंटरफेस बनाने के लिए प्रयास तो जेनरिक अंत में उनका साथ कोई अंतर नहीं है, EntityManager (सच डीएओ यहाँ) 1 लेकिन के समर्थन प्रश्न और कसौटी।

स्प्रिंग घटकों में अनुवादित, आपका डिज़ाइन समान है

@RestController > @Service > @Repository >  EntityManager

रिपॉजिटरी पहले से ही सेवाओं और डेटा स्टोर के बीच एक अमूर्त है। जब हम स्प्रिंग डेटा जेपीए रिपॉजिटरी इंटरफेस का विस्तार करते हैं, तो हम इस डिजाइन को अंतर्निहित रूप से लागू कर रहे हैं। जब हम ऐसा करते हैं, हम एक कर का भुगतान कर रहे हैं: स्प्रिंग के घटकों के साथ एक तंग युग्मन। इसके अतिरिक्त, हम कई तरीकों को विरासत में लेकर LoD और YAGNI को तोड़ते हैं जिनकी हमें आवश्यकता नहीं है या इच्छा नहीं है। यह उल्लेख करने के लिए नहीं कि ऐसा इंटरफ़ेस हमें उन डोमेन के बारे में कोई मूल्यवान जानकारी प्रदान नहीं करता है जिनकी वे सेवा करते हैं।

उस ने कहा, स्प्रिंग डेटा जेपीए रिपॉजिटरी का विस्तार करना अनिवार्य नहीं है और आप कक्षाओं के अधिक सादे और कस्टम पदानुक्रम को लागू करके इन ट्रेडऑफ़ से बच सकते हैं।

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

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

        //Interface implentation
        //...
    }

डेटा स्रोत को बदलना अब सिर्फ एक नया कार्यान्वयन लेता है जो एंटिटी मैनजर को एक अलग डेटा स्रोत के साथ बदल देता है ।

    //@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
        //...
    }

और इसी तरह। 2

इस सवाल पर वापस, कि क्या आपको एक और अमूर्त परत जोड़ना चाहिए, मैं कहूंगा कि यह आवश्यक नहीं है। आपका उदाहरण केवल अधिक जटिलता जोड़ रहा है। आपके द्वारा प्रस्तावित परत सेवाओं और रिपॉजिटरी के बीच प्रॉक्सी के रूप में या एक छद्म सेवा-रिपॉजिटरी परत के रूप में समाप्त होने जा रही है जब विशिष्ट तर्क की आवश्यकता होती है और आप इसे जगह नहीं देते हैं।


1: कई डेवलपर्स सोचते हैं, रिपॉजिटरी इंटरफेस एक दूसरे से पूरी तरह से अलग हो सकते हैं क्योंकि प्रत्येक रिपॉजिटरी डोमेन की अलग-अलग जरूरतों को पूरा करती है। स्प्रिंग डेटा JPA में, DAO की भूमिका EntityManager द्वारा निभाई जाती है । यह सत्र, डेटा स्रोत तक पहुँच , मैपिंग आदि का प्रबंधन करता है ।

2: एक समान समाधान वसंत के भंडार इंटरफेस को बढ़ा रहा है जो उन्हें कस्टम इंटरफेस के साथ मिला रहा है। अधिक जानकारी के लिए, BaseRepositoryFactoryBean और @NoRepositoryBean देखें । हालाँकि, मैंने इस दृष्टिकोण को बोझिल और भ्रामक पाया है।


3

यह साबित करने का सबसे अच्छा तरीका है कि एक डिज़ाइन लचीला है इसे फ्लेक्स करना है।

आप अपने कोड में एक जगह चाहते हैं जो दृढ़ता के लिए ज़िम्मेदार है लेकिन एक रिपॉजिटरी का उपयोग करने के विचार से बंधा नहीं है। ठीक। यह फिलहाल कुछ भी उपयोगी नहीं है ... आह, ठीक है।

ठीक है, अगर यह शंट परत किसी भी अच्छा किया परीक्षण करने देता है। एक फ्लैट फाइल लेयर बनाएं जो आपके उत्पादों को फाइलों में बनाए रखेगा। अब यह नई परत इस डिज़ाइन में कहाँ जाती है?

वैसे यह डीबी जहां है वहां जाने में सक्षम होना चाहिए। आखिरकार हमें डीबी की जरूरत नहीं है क्योंकि हम फ्लैट फ़ाइलों का उपयोग कर रहे हैं। लेकिन इसके लिए रिपॉजिटरी की जरूरत नहीं थी।

विचार करें, शायद रिपॉजिटरी एक कार्यान्वयन विवरण है। आखिरकार मैं रिपॉजिटरी पैटर्न का उपयोग किए बिना डीबी से बात कर सकता हूं।

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

यदि आप सेवा को छुए बिना वह सब कर सकते हैं तो आपके पास लचीला कोड होगा।

लेकिन इसके लिए मेरा शब्द न लें। इसे लिखें और देखें कि क्या होता है। एकमात्र कोड जिस पर मुझे भरोसा है वह लचीला है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.