পাবলিক এপিআই ডিজাইনের সাথে ভারসাম্য নির্ভরতা ইঞ্জেকশন


13

আমি সাধারণ ফিক্সড পাবলিক এপিআই সরবরাহের সাথে নির্ভরতা ইনজেকশন ব্যবহার করে টেস্টেবল ডিজাইনের ভারসাম্য বজায় রাখার বিষয়ে চিন্তাভাবনা করছি। আমার দ্বিধাটি হ'ল: লোকেরা এমন কিছু করতে চায় var server = new Server(){ ... }এবং নির্ভরতাগুলির অনেক নির্ভরতা এবং গ্রাফ তৈরি করার বিষয়ে চিন্তা করতে হবে না Server(,,,,,,)। বিকাশের সময়, আমি খুব বেশি চিন্তা করি না, যেহেতু আমি সমস্তগুলি পরিচালনা করতে আইওসি / ডিআই ফ্রেমওয়ার্ক ব্যবহার করি (আমি কোনও ধারকটির জীবনচক্র পরিচালনার দিকগুলি ব্যবহার করছি না, যা বিষয়গুলিকে আরও জটিল করে তুলবে)।

এখন, নির্ভরতাগুলি পুনরায় বাস্তবায়িত হওয়ার সম্ভাবনা কম। এক্ষেত্রে অংশীকরণ প্রায় সম্পূর্ণরূপে টেস্টিবিলিটির জন্য (এবং শালীন নকশা!) এক্সটেনশনের জন্য সিম তৈরির চেয়ে বেশি People ইত্যাদি People৯.৯৯৯% মানুষ ডিফল্ট কনফিগারেশন ব্যবহার করতে চাইবে। So. আমি নির্ভরতা হার্ডকোড করতে পারে। এটি করতে চাই না, আমরা আমাদের পরীক্ষাটি হারাতে চাই! আমি হার্ড-কোডেড নির্ভরতা এবং নির্ভরতা লাগে এমন একটি দিয়ে একটি ডিফল্ট নির্মাতা সরবরাহ করতে পারি। এটি ... অগোছালো, এবং সম্ভবত বিভ্রান্তিকর, তবে সম্ভব্য। আমি কনস্ট্রাক্টর কনস্ট্রাক্টরকে অভ্যন্তরীণভাবে গ্রহণ করতে পারি এবং আমার ইউনিটটিকে একটি বন্ধু সমাবেশ পরীক্ষা করে তুলতে পারি (সি # ধরে), যা পাবলিক এপিআইকে সজ্জিত করে তবে রক্ষণাবেক্ষণের জন্য কোনও বাজে লুকানো ফাঁদে ফেলে। দু'টি কনস্ট্রাক্টর যা স্পষ্টভাবে পরিবর্তে সুস্পষ্টভাবে সংযুক্ত রয়েছে তা আমার বইয়ের সাধারণভাবে নকশাকোষ হবে।

এই মুহুর্তে আমি সবচেয়ে কম খারাপের কথা ভাবতে পারি। মতামত? উইজডম?

উত্তর:


11

নির্ভরতা ইনজেকশন হ'ল একটি শক্তিশালী প্যাটার্ন যা ভালভাবে ব্যবহৃত হয় তবে এটি প্রায়শই এর অনুশীলনকারীরা কিছু বাহ্যিক কাঠামোর উপর নির্ভরশীল হয়ে পড়ে। এক্সিএমএল ডક્ટ টেপটির সাথে আলগাভাবে আমাদের অ্যাপটি বেঁধে রাখতে চাই না এমন যারা আমাদের জন্য ফলস্বরূপ এপিআই যথেষ্ট বেদনাদায়ক। সাধারণ ওল্ড অবজেক্টস (পিইও) সম্পর্কে ভুলবেন না।

প্রথমে বিবেচনা করুন আপনি কীভাবে আপনার এপিআই ব্যবহার করবেন - এই কাঠামোর সাথে জড়িত না করে।

  • আপনি সার্ভারটি কীভাবে ইনস্ট্যান্ট করবেন?
  • আপনি সার্ভারটি কীভাবে প্রসারিত করবেন?
  • বাহ্যিক এপিআইতে আপনি কী প্রকাশ করতে চান?
  • আপনি বাহ্যিক এপিআইতে কী লুকিয়ে রাখতে চান ?

আমি আপনার উপাদানগুলির জন্য ডিফল্ট বাস্তবায়ন সরবরাহ করার ধারণা এবং আপনার কাছে সেই উপাদানগুলি রয়েছে তা পছন্দ করি। নিম্নলিখিত পদ্ধতির একটি নিখুঁত বৈধ, এবং শালীন OO অনুশীলন:

public Server() 
    : this(new HttpListener(80), new HttpResponder())
{}

public Server(Listener listener, Responder responder)
{
    // ...
}

যতক্ষণ আপনি API ডক্সে উপাদানগুলির জন্য ডিফল্ট বাস্তবায়নগুলি ডকুমেন্ট করেন এবং সমস্ত সেটআপ সম্পাদন করে এমন একটি নির্মাণকারীর সরবরাহ করেন, আপনার ঠিক আছে। যতক্ষণ না কোনও মাস্টার কনস্ট্রাক্টরে সেট আপ কোড হয় ততক্ষণ ক্যাসকেডিং কনস্ট্রাক্টরগুলি ভঙ্গুর হয় না।

মূলত, সমস্ত প্রকাশ্যে মুখোমুখি কনস্ট্রাক্টরগুলির বিভিন্ন উপাদানগুলির মিশ্রণ আপনি প্রকাশ করতে চান would অভ্যন্তরীণভাবে, তারা খেলাপিগুলি ডিফল্টগুলি স্থাপন করবে এবং সেটআপ সম্পূর্ণ করার জন্য একটি প্রাইভেট কনস্ট্রাক্টরকে পিছিয়ে দেবে। সংক্ষেপে, এটি আপনাকে কিছু DRY সরবরাহ করে এবং এটি পরীক্ষা করা বেশ সহজ।

আপনি প্রদান করার প্রয়োজন হলে friendআপনার পরীক্ষা অ্যাক্সেস পরীক্ষার জন্য এটা বিছিন্ন এটি জন্য যান সার্ভার বস্তুর সেট আপ করার জন্য। এটি সর্বজনীন এপিআই-র অংশ হবে না, যা আপনি সাবধান হতে চান।

আপনার এপিআই গ্রাহকদের প্রতি দয়া করুন এবং আপনার লাইব্রেরিটি ব্যবহার করার জন্য কোনও আইওসি / ডিআই ফ্রেমওয়ার্কের প্রয়োজন হবে না । আপনি যে যন্ত্রণা দিচ্ছেন তার অনুভূতি পেতে আপনার ইউনিট পরীক্ষাগুলি আইওসি / ডিআই কাঠামোর উপর নির্ভর করে না তা নিশ্চিত করুন। (এটি একটি ব্যক্তিগত পোষা প্রান্ত, তবে আপনি কাঠামোটি পরিচয় করানোর সাথে সাথে এটি আর ইউনিট টেস্টিং নয় - এটি ইন্টিগ্রেশন টেস্টিংয়ে পরিণত হয়)।


আমি সম্মত, এবং আমি অবশ্যই আইওসি কনফিগার স্যুপের কোনও অনুরাগী নই - এক্সএমএল কনফিগারেশন এমন কিছু নয় যা আমি আইওসি সম্পর্কিত যেখানেই ব্যবহার করি না। অবশ্যই আইওসি ব্যবহারের প্রয়োজনীয়তা হ'ল আমি এড়াচ্ছিলাম - এটি এমন এক ধরণের ধারণা যে কোনও পাবলিক এপিআই ডিজাইনার কখনই করতে পারে না। মন্তব্যের জন্য ধন্যবাদ, এটি আমি যে লাইনে ভাবছিলাম সেগুলি বরাবর এবং এটি বার বার একটি স্যানিটি চেক করার আশ্বাস দেয়!
kolektiv

-1 এই উত্তরটি মূলত "নির্ভরতা ইনজেকশন ব্যবহার করবেন না" বলে এবং এতে ভুল অনুমান রয়েছে। আপনার উদাহরণে যদি HttpListenerকনস্ট্রাক্টর পরিবর্তন হয় তবে Serverক্লাসটিও পরিবর্তন করতে হবে। তারা মিলিত হয়েছে। @ উইনস্টন ইওয়ার্ট নীচে যা বলেছে তার থেকে আরও ভাল সমাধান হ'ল লাইব্রেরির এপিআই-র বাইরে পূর্ব-নির্দিষ্ট করে নির্ভরতা সহ একটি ডিফল্ট শ্রেণি সরবরাহ করা। তারপরে প্রোগ্রামার সমস্ত নির্ভরতা সেট করতে বাধ্য হয় না যেহেতু আপনি তার পক্ষে সিদ্ধান্ত নেন তবে তার পরেও সেগুলি পরিবর্তন করার ক্ষেত্রে তার নমনীয়তা রয়েছে। যখন আপনার তৃতীয় পক্ষের নির্ভরতা থাকে এটি একটি বড় বিষয়।
এম ডুডলি

FWIW প্রদত্ত উদাহরণটিকে "জারজ ইনজেকশন" বলা হয়। stackoverflow.com/q/2045904/111327 stackoverflow.com/q/6733667/111327
এম

1
@ মিশেলডুডলি, আপনি ওপির প্রশ্নটি পড়েছেন? সমস্ত "অনুমান" অপের সরবরাহিত তথ্যের উপর ভিত্তি করে ছিল। কিছু সময়ের জন্য, আপনি যেমন "বেস্টার্ড ইনজেকশন" বলেছেন, এটি ছিল অনুকূল সাপোর্ট ইনজেকশন ইনজেকশন ফর্ম্যাট - বিশেষত এমন সিস্টেমে যাদের রক্ষণকালীন সময়ে রচনাগুলি পরিবর্তন হয় না। সেটার এবং গেটারগুলি নির্ভরতা ইনজেকশনের অন্য একটি রূপ। ওপি কী সরবরাহ করেছে তার ভিত্তিতে আমি কেবল উদাহরণগুলি ব্যবহার করেছি।
বেরিন লরিটস

4

জাভাতে কোনও কারখানার দ্বারা নির্মিত "ডিফল্ট" কনফিগারেশনটি প্রকৃত "সঠিকভাবে" আচরণকারী সার্ভার থেকে স্বতন্ত্র রাখা স্বাভাবিক। সুতরাং, আপনার ব্যবহারকারী লিখেছেন:

var server = DefaultServer.create();

যখন Serverএর কন্সট্রাকটর এখনো তার সকল নির্ভরতা গ্রহণ এবং গভীর স্বনির্ধারণ জন্য ব্যবহার করা যাবে।


+1, এসআরপি ডেন্টিস্ট অফিসের দায়িত্ব ডেন্টিস্ট অফিস তৈরি করা নয়। একটি সার্ভারের দায়িত্ব সার্ভার তৈরি করা নয়।
আর স্মিটজ

2

একটি উপশ্রেণী সরবরাহ করার বিষয়ে যা "পাবলিক এপিআই" সরবরাহ করে

class StandardServer : Server
{
    public StandardServer():
        this( depends1, depends2, depends3)
    {
    }
}

ব্যবহারকারী new StandardServer()তাদের পথে যেতে পারে এবং করতে পারে। তারা যদি সার্ভারটি কীভাবে কাজ করে তার উপর আরও নিয়ন্ত্রণ চায় তবে তারা সার্ভার বেস শ্রেণিও ব্যবহার করতে পারে। এটি আমার ব্যবহারের পদ্ধতিটি কমবেশি। (আমি এখনও কোনও বিন্দুটি দেখতে পাইনি বলে কোনও কাঠামো ব্যবহার করি না))

এটি এখনও অভ্যন্তরীণ এপিআই প্রকাশ করে, তবে আমি মনে করি আপনার উচিত। আপনি নিজের বস্তুগুলিকে বিভিন্ন দরকারী উপাদানগুলিতে বিভক্ত করেছেন যা স্বতন্ত্রভাবে কাজ করা উচিত। কোনও তৃতীয় পক্ষ বিচ্ছিন্নতার মধ্যে যে কোনও একটি উপাদান কখন ব্যবহার করতে চাইবে তা বলার অপেক্ষা রাখে না।


1

আমি কনস্ট্রাক্টর কনস্ট্রাক্টরকে অভ্যন্তরীণভাবে গ্রহণ করতে পারি এবং আমার ইউনিটটিকে একটি বন্ধু সমাবেশ পরীক্ষা করে তুলতে পারি (সি # ধরে), যা পাবলিক এপিআইকে সজ্জিত করে তবে রক্ষণাবেক্ষণের জন্য কোনও বাজে লুকানো ফাঁদ ফেলে leaves

এটি আমার কাছে "বাজে লুকানো ফাঁদ" বলে মনে হয় না। পাবলিক কনস্ট্রাক্টরকে কেবলমাত্র "ডিফল্ট" নির্ভরতা সহ অভ্যন্তরীণটিকে কল করা উচিত। যতক্ষণ না এটা স্পষ্ট যে পাবলিক কনস্ট্রাক্টরকে সংশোধন করা উচিত নয়, সবকিছু ঠিকঠাক করা উচিত।


0

আমি আপনার মতামত সাথে সম্পূর্ণ একমত আমরা কেবল ইউনিট পরীক্ষার উদ্দেশ্যে উপাদান ব্যবহারের সীমানা দূষিত করতে চাই না। এটি ডিআই ভিত্তিক পরীক্ষার সমাধানের পুরো সমস্যা।

আমি ইনজেকটেবল ফ্যাক্টরি / ইনজেকটেবলআইনস্ট্যান্স প্যাটার্নটি ব্যবহার করার পরামর্শ দেব । ইনজেকটেবলআইনস্ট্যান্স হ'ল একটি সাধারণ পুনরায় ব্যবহারযোগ্য ইউটিলিটি ক্লাস যা পরিবর্তনীয় মান ধারক । উপাদান ইন্টারফেসে এই মান ধারকটির একটি রেফারেন্স রয়েছে যা ডিফল্ট প্রয়োগের মাধ্যমে সূচনা হয়েছিল। ইন্টারফেসটি সিঙ্গলটন পদ্ধতিটি () প্রদান করবে যা মান ধারককে প্রতিনিধিত্ব করে। উপাদান নির্ভর করে ক্লায়েন্ট সরাসরি নির্ভরতা এড়াতে বাস্তবায়নের উদাহরণ পেতে নতুন পরিবর্তে get () পদ্ধতিটি কল করবে । পরীক্ষার সময়, আমরা allyচ্ছিকভাবে মক দিয়ে ডিফল্ট প্রয়োগটি প্রতিস্থাপন করতে পারি। অনুসরণ করে আমি একটি উদাহরণ টাইমপ্রোভাইডার ব্যবহার করবশ্রেণি যা তারিখের বিমূর্ততা () তাই এটি ইউনিট পরীক্ষাকে ইনজেকশনের অনুমতি দেয় এবং মককে বিভিন্ন মুহুর্তটি অনুকরণ করতে দেয়। দুঃখিত আমি এখানে জাভা ব্যবহার করব কারণ আমি জাবার সাথে বেশি পরিচিত। সি # এর মতো হওয়া উচিত।

public interface TimeProvider {
  // A mutable value holder with default implementation
  InjectableInstance<TimeProvider> instance = InjectableInstance.of(Impl.class);  
  static TimeProvider get() { return instance.get(); }  // Singleton method.

  class Impl implements TimeProvider {        // Default implementation                                    
    @Override public Date getDate() { return new Date(); }
    @Override public long getTimeMillis() { return System.currentTimeMillis(); }
  }

  class Mock implements TimeProvider {   // Mock implemention
    @Setter @Getter long timeMillis = System.currentTimeMillis();
    @Override public Date getDate() { return new Date(timeMillis); }
    public void add(long offset) { timeMillis += offset; }
  }

  Date getDate();
  long getTimeMillis();
}

// The client of TimeProvider
Order order = new Order().setCreationDate(TimeProvider.get().getDate()));

// In the unit testing
TimeProvider.Mock timeMock = new TimeProvider.Mock();
TimeProvider.instance.setInstance(timeMock);  // Inject mock implementation

ইনজেকটেবলআইনস্ট্যান্স কার্যকর করা খুব সহজ, জাভাতে আমার একটি রেফারেন্স বাস্তবায়ন রয়েছে। বিশদগুলির জন্য, দয়া করে ইনজেকটেবল ফ্যাক্টরি সহ আমার ব্লগ পোস্ট নির্ভরতা ইন্ডিরেশন দেখুন


সুতরাং ... আপনি নির্ভরতা ইনজেকশনটি একটি পরিবর্তনীয় সিঙ্গলটনের সাথে প্রতিস্থাপন করবেন? এটি ভয়াবহ শোনায়, আপনি কীভাবে স্বাধীন পরীক্ষা চালাবেন? আপনি কি প্রতিটি পরীক্ষার জন্য একটি নতুন প্রক্রিয়া খোলেন বা তাদের নির্দিষ্ট সিকোয়েন্সে বাধ্য করেন? জাভা আমার শক্ত মামলা নয়, আমি কি কিছু ভুল বুঝেছি?
নভেম্বর

জাভা মাভেন প্রকল্পে, ভাগ করা উদাহরণটি কোনও সমস্যা নয় কারণ জুনিট ইঞ্জিন ডিফল্টরূপে বিভিন্ন শ্রেণীর লোডারটিতে প্রতিটি পরীক্ষা চালাবে, তবে আমি একই আইডিইতে এই সমস্যাটি দেখতে পাচ্ছি কারণ এটি একই শ্রেণীর লোডার পুনরায় ব্যবহার করতে পারে। এই সমস্যাটি সমাধান করার জন্য, ক্লাসটি প্রতিটি পরীক্ষার পরে মূল অবস্থায় পুনরায় সেট করতে রিসেট পদ্ধতি সরবরাহ করে। অনুশীলনে, এটি একটি বিরল পরিস্থিতি যা বিভিন্ন পরীক্ষা বিভিন্ন মক ব্যবহার করতে চায়। আমরা বছরের পর বছর ধরে বৃহত্তর প্রকল্পগুলির জন্য এই প্যাটার্নটি প্রয়োগ করেছি, সবকিছু কেবল সুচারুভাবে চালিত হয়, আমরা ত্যাগযোগ্য বহনযোগ্যতা এবং পরীক্ষারযোগ্যতা ছাড়াই পঠনযোগ্য, পরিষ্কার কোড উপভোগ করি।
জিয়ানওয়ু চেন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.