الكود حي ومات. الجزء الأول الكائنات

الكود هو الفكر. تظهر مهمة ، ويفكر المطور في كيفية حلها ، وكيفية التعبير عن المتطلبات في الوظائف والفئات ، وكيفية تكوين صداقات لهم ، وكيفية تحقيق الصرامة والدقة ، وكيفية الحصول على الأعمال التجارية بشكل صحيح. الممارسات والتقنيات والمبادئ والأنماط والمناهج - يجب مراعاة كل شيء وكل شيء يجب أن يتم تذكره.


وإلى جانب ذلك ، نرى وباءًا واسعًا من المديرين والمساعدين والخدمات والمراقبين والمُحكمين والمحولات والأطيان والمستوطنين وغيرهم من الأرواح الشريرة: كل هذا رمز ميت. انه الأغبياء والتكتلات.


أقترح القتال بهذه الطريقة: عليك تقديم البرامج كنص بلغة طبيعية وتقييمها وفقًا لذلك. كيف هذا وما يحدث - في المقال.


جدول دورة المحتويات


  1. الكائنات
  2. الإجراءات والخصائص
  3. الرمز كنص

فاتحة


تجربتي متواضعة (حوالي أربع سنوات) ، لكن كلما عملت أكثر ، كلما فهمت أكثر: إذا كان البرنامج غير قابل للقراءة ، فليس هناك معنى له. من المعروف منذ فترة طويلة أنه تم تذكيره وضربه - فالكود لا يحل بعض المشكلات الآن فحسب ، بل وأيضًا أيضًا: يتم دعمه وتوسيعه وتصحيحه. علاوة على ذلك ، فهو دائمًا: يقرأ.


بعد كل شيء ، هذا هو النص.


تعتبر جماليات الكود كنص موضوعًا رئيسيًا في الدورة. الجماليات هنا هي كأس ننظر من خلاله إلى الأشياء ونقول ، نعم ، إنه جيد ، نعم ، إنه جميل.


في مسائل الجمال والشمولية ، تكون للكلمات أهمية كبيرة. ليقول: "في الوقت الحالي ، تصوراتي في وضع ممل بسبب ارتفاع مستوى الإيثانول في الدم" ليست على الإطلاق مثل: "لقد شربت" .


نحن محظوظون تقريبا برامج تتكون بالكامل من الكلمات.


دعنا نفترض أنك بحاجة إلى تكوين "شخصية تتمتع بالصحة والمانا ، وهو يمشي ، ويهاجم ، ويستخدم نوبات" ، ويمكنك أن ترى على الفور: هناك كائنات (شخصية ، صحة ، مانا ، تهجئة) ، أعمال (المشي ، الهجوم ، الاستخدام) والخصائص ( تتميز الشخصية بالصحة ، mana ، سرعة تعويذات الرهان) - كل هذه ستكون أسماء: فصول ، وظائف ، طرق ، متغيرات ، خصائص وحقول ، في كلمة ، كل ما تنقسم إليه لغة البرمجة.


لكنني لن أميز الفئات عن الهياكل والحقول من الخصائص والأساليب من الدوال: لا تعتمد الشخصية كجزء من سرد على التفاصيل الفنية (يمكن تمثيلها كمرجع أو كنوع مهم). شيء مختلف جوهريًا: أن هذه شخصية وقد أطلقوا عليها Hero (أو Character ) ، وليس HeroData أو HeroUtils .


الآن سآخذ كأس الجماليات وأظهر كيف يتم كتابة بعض الرموز اليوم ولماذا لا تكون مثالية.


الكائنات


في C # (وليس فقط) ، الكائنات - مثيلات الفئات الموضوعة على الكومة ، تعيش هناك لفترة من الوقت ، ثم يقوم جامع البيانات المهملة بإزالتها. يمكن أيضًا إنشاء هياكل على المصفوفة أو المصفوفات الترابطية أو أي شيء آخر. بالنسبة لنا هم: أسماء الفئات ، الأسماء.


الأسماء في التعليمات البرمجية ، مثل الأسماء بشكل عام ، يمكن أن تكون مربكة. نعم ، ونادراً ما ترى اسمًا قبيحًا ، لكنه كائن جميل. خاصة إذا كان Manager .


مدير بدلا من كائن


UserService ، AccountManager ، DamageUtils ، DamageUtils ، GraphicsManager ، GameManager ، VectorUtil .


ليست الدقة والملموسة هي التي تهيمن هنا ، بل شيء غامض ، تاركًا مكانًا ما في الضباب. لمثل هذه الأسماء ، الكثير مسموح.


على سبيل المثال ، في أي GameManager يمكنك إضافة أي شيء يتعلق باللعبة ومنطق اللعبة . بعد ستة أشهر ، سيأتي التفرد التكنولوجي.


أو ، يحدث ذلك ، تحتاج إلى العمل مع facebook. لماذا لا تضع كل الشفرة في مكان واحد: FacebookManager أو FacebookService ؟ يبدو الأمر بسيطًا بشكل مغر ، لكن مثل هذه النية الغامضة تخلق قرارًا غامضًا بنفس القدر. في الوقت نفسه ، نعلم أن هناك مستخدمين أو أصدقاء أو رسائل أو مجموعات أو موسيقى أو اهتمامات وما إلى ذلك على Facebook. ما يكفي من الكلمات!


لا توجد كلمات كافية فقط: لا نزال نستخدمها. فقط في الكلام العادي ، وليس بين البرامج.


وليس GitUtils ، ولكن IRepository ، ICommit ، IBranch ؛ لا ExcelHelper ، ولكن ExcelDocument ، ExcelSheet ؛ ليس GoogleDocsService ، ولكن GoogleDocs .


تمتلئ كل منطقة موضوع مع الكائنات. "تميزت الأجسام بفراغات ضخمة" ، "كان القلب ينبض بشراسة" ، "كان المنزل واقفًا" - الأشياء تتحرك ، ويشعرون ، يسهل تخيلها ؛ هم في مكان ما هنا ، ملموسة وكثيفة.


في الوقت نفسه ، تشاهد هذا في بعض الأحيان: في مستودع Microsoft/calculator - CalculatorManager باستخدام الطرق: SetPrimaryDisplay و MaxDigitsReached و SetParentDisplayText و OnHistoryItemAdded ...


(ومع ذلك ، أتذكر مرة رأيت UtilsManager ...)


يحدث ذلك بهذه الطريقة: أريد توسيع نوع List<> بسلوك جديد ، ولا ListUtils أو ListHelper . في هذه الحالة ، من الأفضل والأكثر دقة استخدام طرق التمديد فقط - ListExtensions : فهي جزء من المفهوم ، وليس ListExtensions من الإجراءات.


أحد الاستثناءات القليلة OfficeManager .


بالنسبة للباقي ... لا ينبغي تجميع البرامج إذا كانت تحتوي على مثل هذه الكلمات.


العمل بدلا من الكائن


IProcessor ، ILoader ، ISelector ، IFilter ، IProvider ، ISetter ، ICreator ، IOpener ، IHandler ؛ IEnableable ، IInitializable ، IUpdatable ، ICloneable ، IDrawable ، ILoadable ، IOpenable ، ISettable ، IConvertible .


هنا ، جوهر الجوهر هو إجراء ، وليس مفهومًا ، ويفقد الرمز مرة أخرى صورته وقابليته للقراءة ، ويتم استبدال الكلمة المعتادة بأخرى مصطنعة.


كثير ISequence هو ISequence ، وليس لا ISequence . IBlueprint ، وليس ICreator ؛ IButton ، وليس IButtonPainter ؛ IPredicate ، وليس IFilter ؛ IGate ، وليس IOpeneable ؛ IToggle ، وليس IEnableable .


تحكي قصة جيدة عن الشخصيات وتطورها ، وليس عن كيفية إنشاء المبدع ، وبناء البناية ورسم الرسام. لا يمكن أن يمثل الإجراء كائنًا بالكامل. ListSorter ليس SortedList .


خذ DirectoryCleaner ، على سبيل المثال ، كائن يقوم بتنظيف المجلدات على نظام الملفات. هل هي أنيقة؟ لكننا لا نقول أبدًا: "اطلب من منظف المجلد تنظيف D: / Test" ، ودائمًا: "Clean D: / Test" ، لذلك يبدو " Directory باستخدام الطريقة" Clean أكثر طبيعية وأقرب.


حالة أكثر حيوية هي أكثر إثارة للاهتمام: FileSystemWatcher من .NET هو مراقب نظام الملفات الإبلاغ عن التغييرات. ولكن لماذا المراقب بأكمله ، إذا كانت التغييرات نفسها يمكن أن تبلغ أنها حدثت؟ علاوة على ذلك ، يجب أن تكون مرتبطة بشكل لا ينفصم بالملف أو المجلد ، لذلك يجب أيضًا وضعها في Directory أو File (باستخدام خاصية Changes مع القدرة على استدعاء file.Changes.OnNext(action) ).


يبدو أن مثل هذه الأسماء اللفظية تبرر نمط تصميم Strategy ، حيث تصدر تعليمات "بتغليف عائلة الخوارزميات" . ولكن إذا وجدنا بدلاً من " مجموعة من الخوارزميات" كائنًا أصيلًا موجودًا في القصة ، فسنرى أن الاستراتيجية هي مجرد تعميم.


لشرح هذه الأخطاء وغيرها الكثير ، ننتقل إلى الفلسفة.


الوجود يسبق الجوهر


MethodInfo ، ItemData ، AttackOutput ، CreationStrategy ، StringBuilder ، SomethingWrapper ، LogBehaviour .


يتم توحيد هذه الأسماء من خلال شيء واحد: يعتمد وجودهم على التفاصيل.


يحدث أن يتداخل شيء ما بسرعة مع مهمة: شيء مفقود أو مفقود ، لكن ليس شيئًا ما. ثم تظن: "الشيء الذي يمكن أن يفعله X الآن سيساعدني" - هكذا يكمن الوجود . ثم ، إلى "فعل" X ، تتم كتابة XImpl - هكذا يظهر الكيان .


لذلك ، بدلاً من IArrayItem أو IIndexedItem أو IItemWithIndex أكثر شيوعًا ، أو ، على سبيل المثال ، في واجهة برمجة تطبيقات Reflection ، بدلاً من الطريقة ( Method ) ، لا نرى سوى المعلومات عنها ( MethodInfo ).


طريقة أكثر صدقًا: في مواجهة الحاجة إلى الوجود ، ابحث عن كيان يقوم بتنفيذ ذلك ، وبما أن هذه هي طبيعتها ، فهناك أشخاص آخرون.


على سبيل المثال ، أرادوا تغيير قيمة string الكتابة دون إنشاء مثيلات وسيطة - اتضح أن الحل المباشر في شكل StringBuilder ، بينما ، في رأيي ، هو الأنسب - MutableString .


استرجع نظام الملفات: ليست هناك حاجة إلى DirectoryRenamer لإعادة تسمية المجلدات ، لأنه بمجرد موافقتك على وجود كائن Directory ، يكون الإجراء موجودًا بالفعل ، لم تجد الطريقة المقابلة في الكود.


إذا كنت ترغب في وصف كيفية أخذ القفل ، فليس من الضروري توضيح أن هذا هو ILockBehaviour أو ILockStrategy ، وهو أسهل بكثير - ILock (مع طريقة Acquire التي تُرجع IDisposable ) أو ICriticalSection (مع Enter ).


يتضمن هذا أيضًا جميع أنواع Data Args Output Input Args Params (في كثير من الأحيان State ) - الكائنات التي تخلو تمامًا من السلوك ، لأنها تعتبر من جانب واحد.


عندما يكون الوجود أساسيًا ، يتم خلط الحاصل مع العام ، وتكون أسماء الكائنات مربكة - يجب عليك قراءة كل سطر ومعرفة أين ذهب الحرف ولماذا توجد بياناته فقط.


تصنيف غريب


CalculatorImpl AbstractHero ، AbstractHero ، ConcreteThing ، CharacterBase .


جميعًا للأسباب نفسها الموضحة أعلاه ، نرى في بعض الأحيان كائنات يتم تحديد مكان لها في التسلسل الهرمي بدقة. مرة أخرى ، يندفع الوجود إلى الأمام ، ونرى مرة أخرى كيف تم إسراع الحاجة العاجلة إلى الكود ، دون النظر في العواقب.


بعد كل شيء ، هل هناك حقا شخص ( Human ) - وريث الشخص الأساسي ( HumanBase )؟ لكن كيف يتم ذلك عندما يرث Item AbstractItem ؟


في بعض الأحيان يريدون إظهار أنه لا يوجد Character ، ولكن هناك نوعًا من الشبه "الخام" - CharacterRaw .


Impl ، Abstract ، Custom ، Base ، Concrete ، Internal ، Raw - علامة على عدم الاستقرار ، غموض الهندسة المعمارية ، والتي ، مثل البندقية من المشهد الأول ، ستطلق النار لاحقًا.


تكرار


مع الأنواع المتداخلة ، يحدث هذا: RepositoryItem في Repository ، WindowState في Window ، HeroBuilder في Hero .


التكرار يخترق المعنى ، ويؤدي إلى تفاقم العيوب ، ويساهم فقط في تعقيد النص.


أجزاء زائدة عن الحاجة


لمزامنة مؤشرات الترابط ، غالبًا ما يتم استخدام ManualResetEvent مع واجهة برمجة التطبيقات التالية:


 public class ManualResetEvent { //   —  `EventWaitHandle`. void Set(); void Reset(); bool WaitOne(); } 

في كل مرة ، شخصياً ، يجب أن أتذكر كيف يختلف Set عن Reset (قواعد غير مريحة) وما "حدث إعادة Reset يدويًا" بشكل عام في سياق العمل مع التدفقات.


في مثل هذه الحالات ، يكون من الأسهل استخدام الاستعارات بعيدًا عن البرمجة (ولكن بالقرب من الحياة اليومية):


 public class ThreadGate { void Open(); void Close(); bool WaitForOpen(); } 

بالتأكيد لا يوجد شيء يجب الخلط!


في بعض الأحيان يتعلق الأمر ItemsList : حدد أن العناصر ليست مجرد Items ، ولكن بالضرورة ItemsList أو ItemsDictionary !


ومع ذلك ، إذا لم تكن "قائمة ItemsList مضحكة ، فستكون " AbstractInterceptorDrivenBeanDefinitionDecorator ItemsList من Spring على ما ItemsList . الكلمات في هذا الاسم هي الخرق التي يخيط بها وحش عملاق. على الرغم من ... إذا كان هذا وحشًا ، فما هو إذن HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor ؟ أمل إرث .


بالإضافة إلى أسماء الطبقات والواجهة ، غالبًا ما يواجه المرء التكرار في المتغيرات أو الحقول.


على سبيل المثال ، يسمى حقل من النوع IOrdersRepository _ordersRepository . ولكن ما مدى أهمية الإبلاغ عن تقديم الطلبات بواسطة المستودع؟ بعد كل شيء ، أسهل بكثير - _orders .


يحدث أيضًا أنه في استعلامات LINQ ، يكتبون أسماء الوسائط الكاملة لتعبيرات lambda ، على سبيل المثال ، Player.Items.Where(item => item.IsWeapon) ، على الرغم من أننا نفهم بالفعل هذا العنصر من خلال النظر في Player.Items . في مثل هذه الحالات ، أود دائمًا استخدام نفس الحرف - x : Player.Items.Where(x => x.IsWeapon) (مع الاستمرار في y ، z إذا كانت هذه وظائف داخل وظائف).


في المجموع


أعترف ، مع هذه البداية ، لن يكون من السهل العثور على الحقيقة الموضوعية. شخص ما ، على سبيل المثال ، سيقول: كتابة Service أو عدم الكتابة هي نقطة خلافية ، ضئيلة ، وذوق جيد ، وما الفرق الذي يحدثه إذا نجحت؟


ولكن يمكنك شرب من أكواب المتاح!


أنا مقتنع بأن المسار إلى المحتوى يكمن في النموذج ، وإذا لم ينظر المرء إلى الفكرة ، يبدو أنه قد انتهى. في نص البرنامج ، كل شيء يعمل بالطريقة نفسها: الأسلوب والجو والإيقاع يساعدان على التعبير عن أنفسهم غير مرتبكين ، ولكن بشكل مفهوم ومتفهم.


اسم الكائن ليس فقط وجهه ، بل هو نفسه أيضًا. إنه يحدد ما إذا كان سيكون أثيريًا أو مشبعًا ، أو مجردة أو حقيقي ، جاف أو متحرك. الاسم يتغير - المحتوى يتغير.


في المقال التالي سنتحدث عن هذا المحتوى بالذات وما يحدث.

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


All Articles