لقد كتبنا الكود الأكثر فائدة في حياتنا ، لكننا ألقينا به في سلة المهملات. معنا



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

لقد أضفت مؤخرًا ملاحظة إلى الكمثرى: "الأنواع صعبة وغير ضرورية". في هذه اللحظة ، أصبت بقوة لدرجة أن يدي تنكسر تقريبًا. لأن ما يكفي مني. منذ شهرين ، عشت واحدة من أكثر الحالات فظيعة في حياتي المهنية.

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

1


- (Antokha rcanedu ) تم تكليفي بتطوير أداة نظام أساسي داخلي - مكتبة للتعبير عن كيانات البرامج في شكل نماذج موجهة للكائنات وللعمل الموحد مع خدمات API. أي أداة للتفاعل مع البيانات التي تنتقل من المصدر إلى الشاشة والعكس.

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

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

عند إنشاء واجهة ، هناك مصدران للمشاكل - المستخدم والواجهة الخلفية. كل شيء بسيط مع المستخدم - هناك العديد من المكتبات والأطر المناسبة التي تستخلص من I / O المستخدم (رد الفعل ، الزاوي ، vue وغيرها).

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

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

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

في المقدمة ، لم نقرر أفضل طريقة للقيام بذلك - نحن نبحث ونحاول ونكتب مقالات سخيفة ، ثم ندحض كل شيء ، ونبدأ من جديد وما زلنا لم نتوصل إلى قرار واحد.

- (Antoha) كان كل ما كتبته من قبل مشكلة كبيرة واحدة - التخصص الضيق. في كل مرة يتم تطوير المكتبة من نقطة الصفر وفي كل مرة يتم شحذها لنوع واحد من التفاعل بين خادم العميل. كل هذا يحدث بسبب عدم وجود الكتابة المناسبة.

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

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

- (Phil) نحتاج إلى lib ستمكننا من تقديم وصف مفصل والتحكم في كل كيان ، للحصول على بيانات لهذا الكيان من موارد مختلفة مع واجهة مختلفة ، من REST API و json-rpc إلى graphQL و NQL. والتي سوف تسمح للحفاظ على قاعدة رمز المتنامية وهيكل في الدقة والنظام. بسيطة وبديهية للاستخدام. تقديم وصف كامل ودقيق لحالة الكيانات في أي وقت. نريد أن نستخلص وحدات مستخدمينا من طبقة البيانات قدر الإمكان.

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

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

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



2


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

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

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

لقد فهمت أن جافا سكريبت لن تعمل هنا بأي شكل من الأشكال. كنت بحاجة إلى PL مع نموذج طباعة قوي وتفاعل ممتاز مع جافا سكريبت ولديها مجتمع كبير ونظام بيئي خطير.

- (فيل) لقد كنت أنتظر منذ فترة طويلة لأنوحه لفهم سحر typeScript.

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

- (فيل) لأول مرة في حياتنا ، التقينا وبدأنا شيئًا ما.

الخطوة الأولى هي أن يصف المستخدم مخطط البيانات. نحن نتساءل كيف يبدو. شيء مثل هذا:

type CustomerSchema = { 
  id: number;
  name: string;
}
const Customer = new Model<CustomerSchema>(‘Customer’);

, , . id, , , .
, . , , -. , , .

, . — - , . , , . : , , . . :

 /**
   name: String
   String -   js -: StringConstructor
              
        
*/
const customerSchema = Schema.create({
  id: Number,
  name: String,
});

. , , . , Number String . : , . :

const customerSchema = Schema.create({
  id: 1,
  name: 2,
});

. `Schema.create` , . `if (!(property instanceof String)) throw new Error(« , »)`. .

-, , -, . , . , , .

. , Schema.create.

:

//      
type Map<T> = {
  [key: string]: T | Map<T>; 
};

/**
      ,
      ,
     .
*/
type NumberType = Template<NumberConstructor, number, 'number'>;
type StringType = Template<StringConstructor, string, 'string'>;
type SymbolType = Template<SymbolConstructor, symbol, 'symbol'>;
type BooleanType = Template<BooleanConstructor, boolean, 'boolean'>;
type DateType = Template<DateConstructor, Date, 'date'>;

interface ArrayType extends Array<ExtractTypeValues<Types>> {};

type Types = {
  Number: NumberType;
  String: StringType;
  Symbol: SymbolType;
  Boolean: BooleanType;
  Date: DateType;
  Array: ArrayType;
};
//    
type MapTypes= Map<ApplyTemplate<Types>>;
//     - 
type Declaration = ExtractInputTypes<MapTypes>;
interface Schema<...> {
 //   ,   .
 create: <T extends Declaration>(
    declaration: ConvertInstanceTypesToConstructorTypes<T>
  ) => Schema<T>;
};

, . , , , , .

,

type CustomerSchema = {
  id: number;
  name: string;
};
const customerSchema: CustomerSchema = Schema.create({
  id: Number,
  name: String,
});

. , , .

. any. — any, 100%, , .

, , , . . `Schema.create` . 99% , . , . — ! , .

. , , , . . :

const customerSchema = Schema.create({
 id: Number,
 name: String,
});

//   vscode  : id, name 
Schema.raw(customerSchema). 

//   
//    .
Schema.raw(customerSchema).id;

//        .
Schema.raw(customerSchema).neId;

. :
const customerSchema = Schema.create({
 id: Number,
 name: String,
});

if (true) {
  customerSchema.add({gender: String});
} 

//        ,
//      gender.
//  ,           
// .
Schema.raw(customerSchema).

, , , . gender, , (, , this !). - . , , .

, . , , . , . .

:

const customerSchema = Schema.create({
 id: Number,
 name: String,
});

// customerSchema.add({gender: String});
//      ,    .
//  :
const customerWithGenderSchema = customerSchema.add({gender: String});

//   .
// :
Schema.raw(customerWithGenderSchema).
//  id, name, gender

// 
Schema.raw(customerSchema).
//  id, name

, , . , .

:

const customerSchema = Schema.create({
 id: Number,
 name: String,
});

const repository = RepositoryManager.create(openApiDriver, { 
 // config
});
const Customer = Model.create(repository, customerSchema);

Customer.getAll().first().
//   ide  ,       id, name  gender.
//    ,   
Customer.getAll().first().age;
//   .    ,     , 
//   .

getAll .
:

type MapSchemaToDriver<S extends Schema, D extends Driver> = 
  InferSchemaDeclaration<S> extends SchemaDeclaration
    ? InferDriverMethods<D> extends DriverTemplate<IMRReader, IMRWriter>
      ? Repository<InferSchemaDeclaration<S>, InferDriverMethods<D>>
      : never
    : never;

interface Repository<D extends Driver, S extends Schema> {
  get: <T extends DSLTerm>(dsl: ParseDSLTerm<T>) => MapSchemaToDriver<S, D> extends RepositoryTemplate ? ApplyDSLTerm<MapSchemaToDriver<S, D>, T> : Error<’type’, ‘Type error’>;
}

, :

«, B, A, , , , A. . - ».

. .

«» , , . , .

. , . :

« , *--.*, . , id . - , , ».

.



2.5


, , , . .

, — , , , . . , , .

, . , , , , . , , .

ODM ORM — IMR (Isomorphic Model Representation)


, , API . , . , select-where , .

— , , .

. . . , , , . , , , , .

, — , — , - .

.



3


— () , , . , , , . . , , , .

- , , « ». , . , — . , , ,

, .

. , , . , , , . . . , . , , , , .

— () , , . . , , , .

, , . . , .

— () , . , , . . , . - , , , , .

, - . , . , .

, , . , . .



4


— () , — . ! ?! , , , , , ODM/ORM - , . , . , , «- , ».

, , . . , , . .

, , - , . — , .

, . -:

/*
     .
    — .
       .
     
*/

import { View } from '@view';
import { Logger } from '@utils';

//   —  ,    .
//         .
import { Robot } from '@domain/models';

// ,       
//   
function foo() {
 Robot.fetch({
   location: {
     area: 2,
     free: true,
     key: 'f49a6712', //    - compile-time checked
   }
 })
 .then(View.Grid.display)
 .catch(Logger.error);
}

, . , — js/ts . , . - - , , , — Result .

. - Logger.Error, .

/*
   :
       ,
         -  .
     - 
             .
     :
*/
import { Schema, Model } from 'imr';
import { Logger } from '@utils';
import { View } from '@view';
import { robotSchema } from '@domain/schemas';
import { batteryStationService } from '@domain/infrastructure/services/batteryStation';
import { Robot } from '@domain/models';
import { batteryNode } from '../services/nodeNames';

//       
// ,       ,       ,
//  ,        «»
const robotSchemaWithBattery =
  robotSchema
    .add('battery', Schema.union('li-ion', 'silicon'))
    .remove('speed');

// ,       
//     :
function foo(nodeName) {

 //   -:   -,      
 if (nodeName === batteryNode) {
   //   ,      
   const CustomerRobot = Model.create(robotSchemaWithBattery, batteryStationService);

   CustomerRobot
     //        .
     // , , 'li-notIon'  
     .fetch({ filter: { battery: 'li-ion' } })
    
     //   .
     //   ,      ,     ,   .
     //  ,      ,
     //      ,      .
     .then(View.Grid.display)
     .catch(Logger.error)

 } else {
   Robot
     .fetch()
     .then(View.Grid.display)
     .catch(Logger.error)
 }
}



5


— () , , , - , . , - , , .

.

, , — . . , — , , . . , , — , .

, : . . .

— . , .
: rcanedu, arttom

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


All Articles