
مرحبا بالجميع!
تقدم شركتنا خدمة لتخزين ومعالجة البيانات من الأجهزة الصناعية (المضخات والمثاقب وغيرها من المعدات الصناعية). نقوم بتخزين بيانات عملائنا وتوفير وظائف لتحليلهم: بناء التقارير والرسوم البيانية وأكثر من ذلك بكثير.
وفي سياق العمل ، لاحظنا أن تكامل كل عميل جديد يتأخر كثيرًا ، وأن عدد الأخطاء المختلفة في تزايد مستمر. ثم أصبح من الواضح أن الوقت قد حان للتعامل مع هذا. كما أظهر تحليل الوضع ، قام قسم تكنولوجيا المعلومات لكل من عملائنا بتطوير حل خاص بهم لجمع البيانات محليًا من الأجهزة وإرسالها إلى خدمتنا. إنه يعقد حقيقة أنه ، مع مراعاة تفاصيل الصناعة ، لا يوجد دائمًا وصول إلى الإنترنت ومن الضروري تخزين البيانات محليًا وإرسالها في أقرب وقت ممكن. وهناك عدد كبير بما فيه الكفاية من مثل هذه الفروق الدقيقة ، مما يؤدي إلى زيادة في عدد الأخطاء.
ثم أدركنا أن أفضل حل في هذه الحالة هو تطوير SDK وتقديمه للعميل. بدأت على الفور في البحث عن أفضل الممارسات والاعتبارات المتعلقة بتطوير SDK وفوجئت جدًا - لا يوجد شيء عمليًا في RuNet ، ولكن هناك القليل جدًا من المعلومات على الإنترنت Basurmani ومبعثرة. حسنًا ، المهمة واضحة ومدروسة ومنفذة.
لكن نقص المعلومات حول هذا الموضوع هو الذي خلق الرغبة في إخبار المجتمع بالأفكار والقرارات التي تم التوصل إليها والاستنتاجات بشأن تطوير SDK. تتناول هذه المقالة حلًا لـ .NET ، ولكنها فكرة ، لذلك ستكون مثيرة للاهتمام للكثيرين. التفاصيل تحت الخفض!
حان الوقت للتحديد
لنبدأ بتحديد ما هو SDK ولماذا قد تكون هناك حاجة إليه.
SDK (من مجموعة تطوير البرامج الإنجليزية) هي مجموعة من أدوات التطوير التي تسمح لمتخصصي البرمجيات بإنشاء تطبيقات لمجموعة برامج معينة ، وبرامج تطوير أساسية ، ومنصة أجهزة ، ونظام كمبيوتر ، ووحدات تحكم في الألعاب ، وأنظمة تشغيل وأنظمة تشغيل أخرى. يستفيد SDK من كل نظام أساسي ويقلل وقت التكامل.
...
يتلقى مهندس البرمجيات عادةً SDK من مطور النظام الهدف.
حسنًا ، هذا منطقي. بكلمات بسيطة ، فإن SDK هي حزمة من المكتبات ، بحيث يمكن للعميل بدء العمل مع نظامك بسهولة وسرعة (في هذه المقالة سنتحدث عن خدمتنا ، ولكن كل شيء موصوف في المقالة ينطبق على أنواع أخرى من SDKs) أو تنفيذ نفس الإجراءات.
ولكن ، مثل أي نهج ، فإن مسار SDK له مزايا وعيوب.
الفوائد
تكامل عالي السرعة لعميل جديد - يحتاج عملاؤك إلى كتابة كود أقل.
إعادة استخدام الرمز - يتم استخدام نفس الرمز في عدة أماكن في وقت واحد. يمكننا القول أن هذه نسخة من الفقرة السابقة ، لكننا نتحدث عن حقيقة أن منطق العمل وحيد في كل مكان ، مما يعني
إمكانية التنبؤ بالسلوك - إن استخدام نفس المكتبات يجلب سلوك الأنظمة إلى معيار معين ، مما يسهل إلى حد كبير البحث عن الأخطاء ونقاط الضعف والقضاء عليها.
جودة الشفرة هي المكان الذي يفضل فيه الكثير من الأشخاص التوفير في الاختبار (نأسف للميزانية والمواعيد النهائية وأسباب أخرى). من الواضح أن اختبار جميع أقسام المشروع بالاختبارات في العالم الحقيقي مهمة شاقة للغاية. ولكن الاختبار النوعي لجميع وحدات SDK ، ثم استخدامها يعد وسيلة لزيادة النسبة المئوية لتغطية الاختبار ، مما سيؤدي إلى تقليل عدد الأخطاء.
الوثائق هي نفس السيناريو كما هو الحال مع الاختبارات. توثيق المشروع بأكمله يمثل مشكلة كبيرة. تؤدي إعادة استخدام حزم SDK إلى زيادة النسبة المئوية لتغطية الوثائق ، مما يقلل من حد دخول الموظفين الجدد إلى المشروع ويساعد بشكل عام في الحياة.
جميع المزايا ، في الواقع ، هي عواقب أهم شيء - نكتب الشفرة بجودة عالية جدًا مرة واحدة ، ثم نعيد استخدامها .
العيوب
متطلبات الجودة العالية لرمز SDK هي نتيجة الميزة الرئيسية. سيحدث خطأ في SDK أخطاء في جميع الأنظمة التي تستخدمه.
قيود الإعداد - SDK عبارة عن مجموعة من المكتبات لتنفيذ البرامج النصية القياسية . في بعض الأحيان يعتقد مطورو SDK أنه بصرف النظر عن تنفيذ أحد السيناريوهات المقدمة ، لا يحتاج العميل إلى أي شيء ، وأنه من الأسهل على العميل القيام بكل شيء من الصفر بمفرده من بناء قاعدة من العكازات لـ SDK.
جحيم التبعية والتحديثات - عند توسيع الوظيفة (على سبيل المثال ، تخصيص حل لعميل معين) ، ستقوم بإصدار إصدار جديد من المكتبة. ولكن هناك تبعيات ومجموعات مختلفة من إصدارات المكتبة لعملاء مختلفين ، وتحتاج إلى مراقبة التوافق العكسي أو الإصدارات الصارمة بعناية.
عندما تكون هناك حاجة حقا SDK
لديك العديد من السيناريوهات القياسية التي يتم تنفيذها من وقت لآخر - في الواقع ، حالتنا.
التطوير الداخلي - في المشاريع المختلفة ، هل تستخدم أنظمة التسجيل وتكوينات النظام والعمل مع HttpRequest وقواعد البيانات والملفات؟ بناء SDK داخلي - مجموعة من المكتبات للاستخدام الداخلي. يمكنك توسيع وظيفة SDK في أي وقت ، ولكن سرعة تطوير المشاريع الجديدة ، ونسبة التغطية بالاختبارات والوثائق ستزداد ، وستقل عتبة دخول المطورين الجدد.
عندما يكون من المرجح أن تكون SDK زائدة عن الحاجة
سيناريوهات الاستخدام غير محددة أو تتغير باستمرار - اترك تنفيذ الحلول المخصصة للعملاء وساعدهم. لا حاجة لصنع معجزة من wunderwaffle ، والتي سوف تتدخل فقط. مناسب جدًا للشركات الناشئة والشركات الناشئة.
أنت لا تعرف كيف تفعل ذلك نوعًا - لدي أخبار سيئة لك: حان وقت التعلم. لكن اتخاذ قرار معوج للعميل أمر خاطئ للغاية. يجب احترام العملاء ، بعد كل شيء.
لذلك ، قررنا ما هو SDK ، بمزاياه وعيوبه ، وعندما نحتاج إليه. إذا كنت قد أدركت بعد ذلك أن حزمة SDK مطلوبة حقًا - فأنا أدعوك للشروع في "مسار SDK" ومعرفة ما يجب أن تكون وكيف تفعل ذلك؟
"هل تحب ليغو؟" - النمطية
تخيل كل السيناريوهات المحتملة لاستخدام SDK (لقد قررت بالفعل لماذا تحتاجها ، أليس كذلك؟) وقم بعمل نص للمكتبة. ما ليس خيارا؟ لكن هذا نهج سيئ ، ولذا فإننا لن نفعل ذلك. وسنكون هكذا:
- تقسيم جميع البرامج النصية إلى خطوات
- تحديد الخطوات المشتركة
- إنشاء قائمة بالوحدات النمطية التي تنفذ جميع الخطوات الممكنة (وحدة واحدة مسؤولة عن تنفيذ شيء محدد ، على سبيل المثال ، العمل مع التكوينات)
على سبيل المثال ، مع مراعاة تفاصيل المهمة ، نحتاج إلى تعيين كل المنطق من التكوينات. نقوم بتنفيذ الوحدة النمطية للعمل مع التكوينات (القراءة والكتابة والتحديث والتحقق من صحة التكوينات ومعالجتها) وسنستخدمها في جميع الوحدات الأخرى.
ولتنفيذ السيناريوهات القياسية ، سنقوم حقًا بإنشاء وحدات - نوعًا ما من وحدات "التحكم" ، كل منها ينفذ سيناريو محدد واحد باستخدام وحدات أخرى من نفس SDK. وبالتالي ، لتنفيذ السيناريوهات القياسية ، يحتاج العميل فقط إلى توصيل وحدة التحكم في البرنامج النصي (وسوف يسحب كل التبعيات) ، ولتنفيذ السيناريوهات غير القياسية ، نستخدم الوحدات الأساسية ، ونعيد أيضًا استخدام الرمز.
هذا هو بالتحديد السبب في أن SDK لا ينبغي أن تكون مكتبة واحدة (على الرغم من أنني أريد ذلك حقًا ، كما أفهم. بعد كل شيء ، عندما تكون SDK بأكملها في مكتبة واحدة ، يمكنك نسيان التبعيات وكل ما يتعلق بها) ، ولكن كن مجموعة من المكتبات. ميزة إضافية لهذا النهج هي تخفيض "وزن" برنامج العميل - سوف يسحب SDK ثقيل الوزن ، وسيسحب فقط الوحدات الضرورية.
ولكن لا يجب أن تنتج وحدات على أي حال ، لأنه كلما زاد عدد الوحدات ، زاد الصداع من تبعياتها! أي من المهم تقسيم المنطق بشكل صحيح إلى وحدات ، والحفاظ على التوازن بين القرار "الكل في واحد" و "كل وحدة لها وحدة خاصة بها."
"وهكذا كان من الممكن ؟!" - براعة
تزويد العميل بواجهات مختلفة للعمل مع مكتبتك. سأعطي مثالا:
public void LoadConfiguration(string filename); public async Task LoadConfigurationAsync(string filename);
إذا قمت بتوفير إصدار متزامن فقط ، فعند تنفيذ تطبيق غير متزامن ، سيتم إجبار العميل على إجراء أغلفة غير متزامنة لطريقتك المتزامنة. إذا قمت بتوفير الإصدار غير المتزامن فقط ، فإن الوضع مشابه. أعط العميل كلاهما وسيشكرك.
سوف يكون Generics إضافة لطيفة. على سبيل المثال ، لدينا فئة للعمل مع التكوينات التي تطبق طرق تعبئة التكوين في سلسلة ، وتحميل التكوين من ملف ، إلخ. سيتم تكوين تكوين وحدة معينة من الفئة الأساسية ، ولكن للعمل مع الفئة الجديدة ، نحتاج أيضًا إلى توفير طرق التفريغ.
class BaseConfiguration{ public BaseConfiguration FromString(string source){...} public BaseConfiguration FromString(string source,Type configurationType){...} public T FromString<T>(string source) where T:BaseConfiguration } class CustomConfiguration : BaseConfiguration{}
وبالتالي ، قدمنا للعميل ثلاث عمليات تنفيذ يمكنه استخدامها. تعتبر العبارات العامة مريحة للغاية ، ولكن عند العمل مع أنواع ديناميكية ، لا يمكن استدعاؤها إلا من خلال التفكير ، وهو أمر غير مربح. آمل أن يكون المبدأ العام للعالمية واضحاً.
"Parent 1، Parent 2، Children []" - التسمية
ما هو أصعب جزء في المبرمج؟ أسماء الاختراعات للمتغيرات.
ومع ذلك ... ستساعد التسمية الصحيحة للوحدات والفئات والخصائص والأساليب بشكل كبير أولئك الذين سيعملون مع SDK الخاص بك. مثال لا يتطلب تعليقات:
مثال على Kinect 2.0 SDK
var skeletons = new Skeleton[0]; using (var skeletonFrame = e.OpenSkeletonFrame()) { if (skeletonFrame != null) { skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength]; skeletonFrame.CopySkeletonDataTo(skeletons); } } if (skeletons.Length == 0) { return; } var skel = skeletons.FirstOrDefault(x => x.TrackingState == SkeletonTrackingState.Tracked); if (skel == null) { return; } var rightHand = skel.Joints[JointType.WristRight]; XValueRight.Text = rightHand.Position.X.ToString(CultureInfo.InvariantCulture); YValueRight.Text = rightHand.Position.Y.ToString(CultureInfo.InvariantCulture); ZValueRight.Text = rightHand.Position.Z.ToString(CultureInfo.InvariantCulture);
كل شيء واضح من أسماء الفئات والأساليب. وإذا كان هناك اكتمال الشفرة في IDE ، فمن الممكن غالبًا عدم النظر في الوثائق إذا كان كل شيء واضحًا بالفعل.
"أنا متأكد من أنه إذا كان الموت يعرف ما هي البيروقراطية ، فلن يموت الناس أبداً ، إلى الأبد في الصف ..." - التوثيق
ولكن حتى إذا تم تسمية جميع الوحدات والفئات والأساليب والخصائص بشكل جميل للغاية وعلى وجه السرعة ، فلا تزال بحاجة إلى كتابة الوثائق. أولاً ، سيوفر أعصابك بشكل كبير (يتم تقليل عدد أسئلة العملاء بأمر من الحجم. كل شيء موجود في الوثائق) ، وثانيًا ، من الواضح دائمًا سبب قيامك بذلك وليس خلاف ذلك.
عادةً ما تكون الوثائق الموجودة في SDK بسيطة وموجزة. وعادة ما يتم تقسيمها إلى جزأين: البرنامج التعليمي - دورة خطوة بخطوة بأسلوب "بناء مدينة في 10 دقائق" والقسم المرجعي - مرجع لكل شيء يمكن القيام به باستخدام حزمة SDK هذه.
لقد اخترنا أسهل طريقة - ملخص + مقالات. نضيف سمات Xml للأساليب والفئات التي تتألق في التحسس في شكل تلميحات أدوات. باستخدام Docfx ، نبني وثائق حول هذه السمات ونحصل على وثائق مفصلة ومريحة ، تكملها مقالات تصف حالات الاستخدام والأمثلة.
"- لأبقيها نظيفة - كيف أنظفها بشوكة؟" - الاختبار
ما يمكن أن يقال عن الاختبار كجزء من مناقشة SDK ... يجب أن يكون! الحل الأفضل سيكون TDD (على الرغم من أن لدي موقف سلبي تجاه هذا النهج ، في هذه الحالة قررت استخدامه). نعم ، منذ وقت طويل. نعم ممل. ولكن في المستقبل ، لن تعلق نفسك من السقوط المستمر لـ SDK على الجانب وعواقب هذا الخريف.
إن السبب الرئيسي للموقف هو أن إعطاء SDK للعميل يفقد السيطرة: لا يمكنك إصلاح الخطأ بسرعة ، ومن الصعب العثور على هذا الخطأ ، وستبدو غبيًا بما يكفي في مثل هذه الحالة. لذلك - اختبار. اختبار أفضل. ومرة أخرى. وفقط في حالة اختبار اختباراتك. واختبارات الاختبار. حسنًا ، لقد حملت شيئًا ما ، ولكن آمل أن تكون أهمية اختبار SDK واضحة.
"الضحية التي لم تستطع مقاومة ماضيها كانت تستهلكه" - لوجي
نظرًا لأنك تقدم SDK إلى شركة تابعة لجهة خارجية ، ونتيجة لذلك تفقد السيطرة على الموقف ، في حالة حدوث خطأ (في مرحلة الاختبار قررت جميعًا "ستفعل" ، أليس كذلك؟) ، تنتظرك عملية طويلة ومؤلمة إلى حد ما للبحث عن هذا الخطأ. هذا هو المكان الذي تأتي فيه السجلات لمساعدتك.
سجّل كل شيء ، كل شيء تمامًا ، وإذا حدث خطأ ، فاطلب من العميل سجلات. بهذه الطريقة ستوفر الكثير من الوقت ولن تكون قادرًا على فرك وجهك أمام العميل.
"إنذار! Achtung! انتباه!" - أخطاء

أثناء التفكير كثيرًا في الأخطاء ، توصلت إلى استنتاج مثير للاهتمام - لا يجب أن تعطي طريقة واحدة في SDK خطأً غير موصوف في الوثائق . يجب أن تعترف أنه من المزعج للغاية عند توصيل مكتبة خارجية للعمل مع HttpRequest ، ويلقي عليك بعض NullPointerException و StackTrace ، مما يأخذك إلى أحشاء المكتبة. وعليك أن تغوص في هذه "الأمعاء" ، في محاولة لفهم مدى عمق حفرة الأرنب ، وما هي المشكلة في الواقع.
لذلك ، أقترح الحل التالي - أعلن قائمة مغلقة من الاستثناءات المحتملة وتوثيقها. لكن لأن لا يمكنك التأكد من أنك قدمت كل شيء ، وقم بلف الطريقة في محاولة الالتقاط ، والخطأ الذي تم اكتشافه في الطريقة المعلنة. على سبيل المثال ، يعد ConfigurationException الذي سيحتوي على InnerException خطأ تم اكتشافه. سيسمح ذلك لمطور برامج تابع لجهة خارجية بالقبض على جميع الأخطاء المحتملة ، ولكن إذا حدث شيء ما ، فاستكشف بسرعة الأمر.
إصدارات أو "كيف لا تعض ذيلك"
لتجنب المشاكل المستقبلية ، أوصي بشدة باستخدام الإصدارات الصارمة. اختر نظام الإصدار الذي يناسبك واستخدمه. ولكن إذا كان الإصدار الجديد من المكتبة لا يحتوي على توافق عكسي ، فيجب الإشارة إلى ذلك. كيفية حلها - تعتقد. ولكن يجب عليك بالتأكيد التفكير في الأمر.
"قطار يمكن" - نشر
الحاجة إلى أهمية الوثائق والنسخ تثير الحاجة إلى صحة النشر. في قرارنا ، نستخدم الحل التالي (العكازات ، لكنها تعمل).
عندما يكون من الضروري إصدار إصدار جديد ، قام المطور بسحب bat'nik برقم الإصدار ، ثم الملف الدفعي:
- بناء الإصدار
- يضع جميع المكتبات في الأرشيف
- إنشاء أحدث إصدار من الوثائق (docfx)
- يشير إلى نسخة الإصدار في الوثائق واسم الأرشيف
- يضع جميع العناصر الطازجة في مستودع git
- يسحب WebApp على MS Azure تنفيذ ربط git الجديد وينشر التغييرات
عند الإخراج ، نحصل على نسخة محدثة من الموقع مع وثائق ، حيث يمكنك تنزيل الأرشيف بأحدث إصدار من SDK.
تتضمن الخطط المستقبلية تعبئة كل شيء في حزم Nuget ونشرها في مستودع Nuget المحلي.
أوصي بإيلاء الاهتمام لهذه النقطة ، لأنه يمكنك تقليل مقدار الصداع بشكل كبير بسبب نقص المعلومات ذات الصلة حول الإصدار الجديد من المكتبة.
نقطة مهمة في الوثائق هي أمثلة الاستخدام. ولكن بالإضافة إلى ذلك ، غالبًا ما يُطلب منك عدم توفير مكتبة ، بل تطبيقًا ينفذ أكثر السيناريوهات القياسية. أوصي بعمل هذه التطبيقات مع رمز مصدر مفتوح ومعلق جيدًا ، والذي سيسمح لك بقتل عصفورين بحجر واحد - توفير تطبيق فعال وتقديم مثال لاستخدام SDK.
الخلاصة
أصبح تطوير SDK مهمة جديدة مثيرة للاهتمام بالنسبة لي ، والتي أثارت العديد من القضايا المعمارية الهامة. الكثير من الأشياء الموصوفة في المقالة هي أشياء واضحة (بالنسبة لي) ، لكني أعتبر أنه من المهم الإعلان حتى عن الأشياء الواضحة من أجل الحصول على صورة كبيرة واضحة.
PS
شكرا للقراءة ، سأكون سعيدا لتعليقاتكم. آمل أن تكون هذه المقالة مفيدة لك.