Conectividad débil

NB : Este es un borrador de dos nuevos capítulos de mi libro sobre diseño de API. El texto contiene referencias a los capítulos anteriores.







Fuerte conectividad y problemas relacionados



En las secciones anteriores, intentamos dar reglas y principios teóricos e ilustrarlos con ejemplos prácticos. Sin embargo, comprender los principios para diseñar una API que sea resistente al cambio requiere más práctica que cualquier otra cosa. El conocimiento de dónde "poner la paja" es, en muchos sentidos, "el hijo de errores difíciles". No se puede prever todo, pero se puede desarrollar el nivel necesario de intuición técnica.







Por lo tanto, en esta sección, procederemos de la siguiente manera: tome nuestro modelo de API de la sección anterior y verifique su estabilidad en cada punto posible; realizaremos un "análisis variacional" de nuestras interfaces. Incluso más específicamente, nos acercaremos a cada entidad con la pregunta "¿y si?" - ¿Qué pasa si necesitamos proporcionar a los socios la capacidad de escribir su propia implementación independiente de esta pieza de lógica?







El primer punto importante al que prestar atención: estamos hablando específicamente de las opciones para la implementación de la lógica del producto . No se trata de las opciones para la implementación de la entidad : los cambios en la API se realizan principalmente para permitir hacer algo que no estaba previsto en el diseño original, algo útil. Sus clientes no volverán a implementar interfaces así.







Esta consideración introduce ciertas restricciones que nos permiten no variar ciegamente las interfaces (después de todo, hay un número infinito de tales opciones, y proveer para todas ellas es un trabajo de Sisyphean): necesitamos entender, en primer lugar, por qué ciertas Se necesitan cambios, y a partir de aquí ya entenderemos cómo deben introducirse.







El segundo punto importante es que muchas de las soluciones que permiten esta variación ya están integradas en el diseño de la API. Cubrimos algunos de ellos (por ejemplo, la cuestión de determinar la preparación) con más detalle en los capítulos anteriores, y algunos dieron sin comentarios: es hora de explicar por qué se tomaron estas decisiones.







NB: , ; ad hoc , . API ; , , .







, . ?







  • , «» ;
  • , .


. , ? , «»: , . , :







//   
POST /v1/recipes
{
  "id",
  "product_properties": {
    "name",
    "description",
    "default_value"
    //  , 
    //   
  },
  "execution_properties": {
    //  
    "program_id",
    //   
    "parameters"
  }
}
      
      





, , . , — .







, 11: . :







"product_properties": {
  // "l10n" —  
  //  "localization"
  "l10n" : [{
    "language_code": "en", 
    "country_code": "US", 
    "name", 
    "description" 
  }, /*     */ … ]
]
      
      





default_volume



? , , , . , , , «300 », «10 ». :







  • , ;
  • , .


, API - — , API. , — . .







, , API . — name



description



? , . — /v1/search



, : search



?







— , UI . -, name



description



— , ( ) ( ). , API . , UI ? , , : name



— «-» , . -, , UI; -, . , , «», «» «» « » « ».







— UI ( ) , ( , , ). product_properties



, , .







, — . , , , () ( , ). API « », . , : . .









: , . — , (, , .. API) .







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







l10n.volume.format(value, language_code, country_code)
// l10n.formatVolume('300ml', 'en', 'UK') → '300 ml'
// l10n.formatVolume('300ml', 'en', 'US') → '10 fl oz'
      
      





API , , , . , , :







//    
//   
PUT /formatters/volume/ru
{
  "template": "{volume} "
}
//    
//      «»
PUT /formatters/volume/ru/US
{
  //     
  // ,   
  "value_preparation": {
    "action": "divide",
    "divisor": 30
  },
  "template": "{volume} ."
}
      
      





NB: , , , , , (, , ), (.. ). .







name



description



. , , (, , API) «». name



description



, UI. UI .







GET /v1/layouts/{layout_id}
{
  "id",
  //      ,
  //     
  // 
  "kind": "recipe_search",
  //    ,
  //     
  //   
  "properties": [{
    //    ,  `name`
    //      
    //     —
    //      `seach_title`
    "field": "search_title",
    "view": {
      //   ,
      //    
      "min_length": "5em",
      "max_length": "20em",
      "overflow": "ellipsis"
    }
  }, …],
  //   
  "required": ["search_title", "search_description"]
}
      
      





, , . :







PUT /v1/recipes/{id}/properties/l10n/{lang}
{
  "search_title", "search_description"
}
      
      





:







POST /v1/layouts
{
  "properties"
}
{ "id", "properties" }
      
      





, UI , , .







— , — execution_properties



, , . :







POST /v1/recipes
{ "id" }
{ "id" }
      
      





, «» , . , , -, :







POST /v1/recipe-builder
{
  "id",
  //   
  "product_properties": {
    "default_volume",
    "l10n"
  },
  //  
  "execution_properties"
  //   
  "layouts": [{
    "id", "kind", "properties"
  }],
  //   
  "formatters": {
    "volume": [
      { "language_code", "template" },
      { "language_code", "country_code", "template" }
    ]
  },
  //  ,  
  //    
  //    
}
      
      





, — . , — , , - . , , , , : ( ), , 11.







POST /v1/recipes/custom
{
  //   :
  // ,    
  "namespace": "my-coffee-company",
  //   
  "id_component": "lungo-customato"
}
{
  "id": "my-coffee-company:lungo-customato"
}
      
      





, : , . , "common", . (, , , API .)









, . , API 9 «» « ». , program-matcher



:







GET /v1/recipes/{id}/run-data/{api_type}
{ /*   
       
        
       API */ }
      
      





:







  • API -;
  • API ;
  • API .


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







program_run_id



, . .







, , . API - API. , , -, API. API , - ?







, API : , () . API — , :







//   
// - 
PUT /partners/{id}/coffee-machines
{
  "coffee-machines": [{
    "id",
    "program_api": {
      "program_run_endpoint": {
        /* - 
              */
        "type": "rpc",
        "endpoint": <URL>,
        "format"
      },
      "program_state_endpoint",
      "program_stop_endpoint"
    }
  }, …]
}
      
      





NB: API ( program_run_endpoint



, program_state_endpoint



, .)







API , , API . .







  1. (.. API), : , .
  2. : .


2 , 1. , , — , , . , , program_modify_endpoint



, ( , ). , , ( , ) .







- , . : , API , . , , , modify



API — , . , , , : , - , « ». , , , , , , , , , , , .







, , program_takeout_endpoint



. :







  • program_takeout_endpoint



    , program_modify_endpoint



    ;
  • program_modify_endpoint



    , program_takeout_endpoint



    .


, . , takeout



. - modify



, . , , — API , .







, API , . , , «» , , : , API -, . — , , — , , .







, . API « », .







? : , . ? - :







  • API , ; , : - - , , - ;
  • API , API ; , .


, , , : , . , « ».







:







  • , ;
  • : , .


, , (- ) . SDK :







/*   
       - */
registerProgramRunHandler(apiType, (program) => {
  //   
  //    
  let execution = initExecution(…);
  //   
  //  
  program.context.on('takeout_requested', () => {
    //    ,
    //  
    execution.prepareTakeout(() => {
        //      ,
        //   
        execution.context.emit('takeout_ready');
    });
  });

  return execution.context;
});
      
      





NB: HTTP API , GET /program-run/events



GET /partner/{id}/execution/events



, . , Apache Kafka Amazon SQS.







, , , , :







  • takeout



    takeout_requested



    /takeout_ready



    ;
  • , API , context



    , ;
  • , .


. API , . API : . ? , ; - ( !) , ( ).







, . , :







  • , API — ; , , ;
  • — , , , .


, — , - .







, , (, ) API, , . program



( , , ); execution



( , , API). , execution



- , - API, program



- , .







, . API, , , , . , UI. , SDK.









, , . , — . :







/*   
       - */
registerProgramRunHandler(apiType, (program) => {
  //   
  //    
  let execution = initExection(…);
  //   
  //  
  program.context.on('takeout_requested', () => {
    //    ,
    //  
    execution.prepareTakeout(() => {
      /*      ,
            ,  
             */
      // execution.context.emit('takeout_ready')
      program.context.set('takeout_ready');
      //    :
      // program.setTakeoutReady();
    });
  });
  //       
  //   - 
  // return execution.context;
}
      
      





, . : , . , , , , . .







, , , :







  • , , — ;
  • , , API . API , .


, API API , «» «-».







NB: . , — Redux. Redux :







execution.prepareTakeout(() => {
  //     
  //     ,
  //    
  //      
  dispatch(takeoutReady());
});
      
      





, , — , API, . ( -) , , : , , .







execution.prepareTakeout(() => {
  //     
  //     ,
  //    
  // 
  program.context.dispatch(takeoutReady());
});
      
      





//  program.context.dispatch
ProgramContext.dispatch = (action) => {
  // program.context   
  //  ,   
  // ,    
  globalContext.dispatch(
    //     
    //     
    //    
    // 
    this.generateAction(action);
  )
}
      
      








Este es un borrador de dos nuevos capítulos en la próxima sección de compatibilidad con versiones anteriores de mi libro sobre desarrollo de API. El trabajo se realiza en Github . La versión en inglés del mismo capítulo se publica en medium . Le agradecería que pudiera compartirlo en reddit; yo mismo no puedo de acuerdo con la política de la plataforma.








All Articles