ABONAMENTE VIDEO REDACȚIA
RO
EN
NOU
Numărul 148
Numărul 147 Numărul 146 Numărul 145 Numărul 144 Numărul 143 Numărul 142 Numărul 141 Numărul 140 Numărul 139 Numărul 138 Numărul 137 Numărul 136 Numărul 135 Numărul 134 Numărul 133 Numărul 132 Numărul 131 Numărul 130 Numărul 129 Numărul 128 Numărul 127 Numărul 126 Numărul 125 Numărul 124 Numărul 123 Numărul 122 Numărul 121 Numărul 120 Numărul 119 Numărul 118 Numărul 117 Numărul 116 Numărul 115 Numărul 114 Numărul 113 Numărul 112 Numărul 111 Numărul 110 Numărul 109 Numărul 108 Numărul 107 Numărul 106 Numărul 105 Numărul 104 Numărul 103 Numărul 102 Numărul 101 Numărul 100 Numărul 99 Numărul 98 Numărul 97 Numărul 96 Numărul 95 Numărul 94 Numărul 93 Numărul 92 Numărul 91 Numărul 90 Numărul 89 Numărul 88 Numărul 87 Numărul 86 Numărul 85 Numărul 84 Numărul 83 Numărul 82 Numărul 81 Numărul 80 Numărul 79 Numărul 78 Numărul 77 Numărul 76 Numărul 75 Numărul 74 Numărul 73 Numărul 72 Numărul 71 Numărul 70 Numărul 69 Numărul 68 Numărul 67 Numărul 66 Numărul 65 Numărul 64 Numărul 63 Numărul 62 Numărul 61 Numărul 60 Numărul 59 Numărul 58 Numărul 57 Numărul 56 Numărul 55 Numărul 54 Numărul 53 Numărul 52 Numărul 51 Numărul 50 Numărul 49 Numărul 48 Numărul 47 Numărul 46 Numărul 45 Numărul 44 Numărul 43 Numărul 42 Numărul 41 Numărul 40 Numărul 39 Numărul 38 Numărul 37 Numărul 36 Numărul 35 Numărul 34 Numărul 33 Numărul 32 Numărul 31 Numărul 30 Numărul 29 Numărul 28 Numărul 27 Numărul 26 Numărul 25 Numărul 24 Numărul 23 Numărul 22 Numărul 21 Numărul 20 Numărul 19 Numărul 18 Numărul 17 Numărul 16 Numărul 15 Numărul 14 Numărul 13 Numărul 12 Numărul 11 Numărul 10 Numărul 9 Numărul 8 Numărul 7 Numărul 6 Numărul 5 Numărul 4 Numărul 3 Numărul 2 Numărul 1
×
▼ LISTĂ EDIȚII ▼
Numărul 39
Abonament PDF

Designul de API - studiu de caz

Andrada Demian
Developer @ Betfair



PROGRAMARE


În zilele noastre este din ce în ce mai greu ca un serviciu sau produs să devină un succes. Expunerea unui API, acronim pentru Application Programming Interface, poate reprezenta condiția de bază care să asigure acest succes.
Un API definește în mod clar cum interacționează un sistem software sau o componentă cu multitudinea de sisteme existente. Printre avantajele unui API se numără scalabilitatea, flexibilitatea și inovația. Marile companii printre care se numără Microsoft, Google, Facebook sau Twitter nu s-ar afla în momentul de față la acest nivel dacă nu ar fi beneficiat de pe urma expunerii propriilor API-uri.

De ce este dificilă definirea unui API?

Designul de API este unul din lucrurile care pot contribui semnificativ la creșterea valorii unui serviciu. Cu toate acestea, definirea unei noi interfețe reușite este o muncă dificilă. Orice dezvoltator software știe cât de ușor poate codul unui proiect să evolueze într-un cod "spaghetti". API-urile nu sunt nici ele ferite de această degradare. Un API* bine definit trebuie să reflecte obiectivele businessului din care face parte, dar totodată să țină cont și de punctele forte și de limitările organizației cu privire la buget, competențe personale și infrastructură tehnică. Cheia întregului proces este identificarea problemei pe care o rezolvă această nouă interfața. Mai sunt și alte aspecte care trebuie luate în calcul pentru definirea unui API reușit. Un API trebuie să fie:

Folosirea recomandărilor de mai sus asigură înțelegerea API-ului de către consumatorii săi. În consecință integrarea și folosirea lui vor deveni foarte ușoare. Cu cât un API este mai ușor de consumat, cu atât rata de adopție va deveni mai mare și costul dedicat integrării sale mai mic.

Puterea exemplului

 În rândurile următoare vom expune un exemplu concret de API insistând asupra provocărilor de care am avut parte de-a lungul întregului proces de design al API-ului. Următoarele exemple sunt luate dintr-un serviciu web al cărui scop este acela de a administra promoțiile vizibile pe website-ul nostru. Aceste promoții cer clientului să efectueze diverse acțiuni pe site- cum ar fi să se înregistreze, să pună pariuri, să se joace jocuri de tip arcade- toate acestea pentru a putea primi premii preconfigurate.

În organizația noastră serviciile web comunică unele cu altele folosind un protocol RPC. Pentru a putea defini operațiile suportate de fiecare serviciu în parte se folosește o schemă XML numita BSIDL (acronim pentru Betfair Service Interface Definition Language). Specificațiile unui BSIDL descriu operațiile suportate(sau metodele) pe care serviciile le expun plus tipurile de date suportate. Mai jos este un exemplu al unei operații folosite de unul dintre clienții API-ului ( o aplicația internă) pentru a crea o promoție.

<operation name="create">
      <description>Creates a new promotion.</description>
      <parameters>
          <request>
              <parameter name="promotion" type="Promotion" mandatory="true">
                  <description>The promotion to create.</description>
              </parameter>
          </request>
          <response type="ResponseStatus">
              <description>Return ok if it was a successful call and fail otherwise, together with an error code.
        </description>
          </response>
      </parameters>
</operation>  

După cum putem observa în exemplul de mai sus, numele operației este foarte sugestiv, descriind practic ceea ce operația trebuie să facă. De asemenea, este foarte greu de folosit această operație într-un mod incorect, având un singur parametru al cărui nume promoție ( promotion) este destul de sugestiv pentru că exprimă ceea ce vrem sa creăm folosind această operație. Până în acest punct operația este foarte intuitivă.

Principala îngrijorare cu privire la noua interfață a fost cum să modelăm o promoție astfel încât să satisfacă cerințele și în același timp să fie suficient de generică pentru a putea oferi flexibilitate. Cea mai simplă si ușoară soluție ar fi fost să creăm un nou tip pentru fiecare promoție. Această alegere ar fi avut multe dezavantaje printre care se numără și codul duplicat - promoțiile au în comun mai multe caracteristici cum ar fi nume, descriere; rezultatul final ar fi conținut o multitudine de tipuri de promoții pentru fiecare tip nou de promoție care ar fi trebuit adăugat. Nu am fost pe deplin încântați de această variantă așa că după câteva sesiuni de meditat la alte soluții am venit cu ideea de a avea o promoție care are toate câmpurile necesare descrierii unei promoții plus un câmp special numit fulfillmentCriteria. Un fragment reprezentând promoția modelată poate fi văzut mai jos:

   <dataType name="Promotion">
      <description>Encapsulates the promotion entity fields.</description>
      <parameter name="name" type="string">
          <description>The name of the promotion.</description>
      </parameter>
      <parameter name="rank" type="i32">
        <description>Represents the promotion ranking number which is an integer on range[1,1000].
        </description>
      <parameter name="product" type="set(Product)">
          <description>
              Indicates the products for which the promotion is available.
          </description>
      </parameter>
      <parameter name="fulfillmentCriteria" type="FulfillmentCriteria">
         <description>What does the user need to accomplish in order to get the reward.
         </description>
    </parameter>
  </dataType>     

Soluția găsită cu privire la suportarea mai multor tipuri de promoții a fost să folosim compoziția pentru a defini API-ul. Așadar, în loc să creăm un nou tip pentru promoțiile care implică un depozit(ex. depozitează 10 EUR ca să primești un pariu gratis) am creat un nou criteriu numit DepositCriteria care cuprinde cerințele necesare depozitului sumei de 10 EURO. Acest lucru face ca API-ul să fie unul foarte ușor de extins fără să existe schimbări incompatibile cu versiunea precedentă, beneficiind totodată de un mare avantaj, acela de a avea doar un singur tip de promoție.

<dataType name="FulfillmentCriteria">
    <parameter name="compoundCriteria" type="CompoundCriteria"/>
    <parameter name="depositCriteria" type="DepositCriteria"/>
    <parameter name="placeBetCriteria" type="PlaceBetCriteria"/>
    <parameter name="registerCriteria" type="RegisterCriteria"/>
</dataType>

Adăugarea tipului CompoundCriteria a fost necesară pentru cazurile în care o promoție este configurată să suporte mai multe criterii în același timp folosind operatori de tip ȘI,SAU având rolul de a descrie ceea ce un client Betfair trebuie să facă. Mai jos avem un exemplu de arbore de criterii pentru o promoție cu următoarele cerințe.

Înregistrează-te și pune un pariu de 5 EUR pe jocurile de Arcade sau pune un pariu de 5 EUR pe România vs Ungaria pentru a câștiga un pariu gratis.

În ceea ce privește tratarea erorilor se poate observa din primul exemplu faptul că operația de creare a promoției returnează un tip de date numit ResponseStatus în loc să arunce o excepție. Promoția este validată la creare și toate inconsistențele sunt tratate ca erori de business astfel încât clientul este capabil să ia decizii bazate pe aceste erori de business. Am abordat această soluție deoarece ne-am gândit că este mai adecvată pentru consumatorul API-ului. Sugestivă în acest sens este și afirmația lui Martin Fowler: Dacă o eroare este un comportament așteptat, atunci nu ar trebui folosite excepții.

 <dataType name="FulfillmentCriteria">
    <parameter name="compoundCriteria" type="CompoundCriteria"/>
    <parameter name="depositCriteria" type="DepositCriteria"/>
    <parameter name="placeBetCriteria" type="PlaceBetCriteria"/>
    <parameter name="registerCriteria" type="RegisterCriteria"/>
</dataType>

Urmarea bunelor practici prezentate mai sus nu garantează lipsa greșelilor. Noile cerințe apărute au cauzat adăugarea de noi atribute necesare descrierii unei promoții.

 Promotion
  getPromotionName()
  getRank()
  getProduct()
  getDisplayAttributes()
  getJurisdiction()
  getVisibleForGuest()
  getTermsAndConditions()  

Unele atribute au fost grupate în noi tipuri de date cu nume sugestive:

DisplayAttributes
  getTheme()
  getBannerUrl()
  getImageUrl()  

Alte atribute au fost adăugate direct fără să fie grupate pentru că la momentul respectiv nu am găsit un grup potrivit iar adăugarea unui singur atribut într-un grup nu ar fi avut sens. În acest moment există foarte multe atribute în tipul promoție (promotion) și chiar dacă le-am putea introduce într-un grup potrivit- am putea grupa rank și product într-un grup similar cu cel pentru DisplayAttributes- , unul dintre clienții API-ului folosește deja versiunea cu atributele negrupate făcând astfel dificil procesul adăugării unor modificări incompatibile cu versiunea anterioară.

Concluzii

Definirea unui API este o activitate captivantă. Ce am învățat noi din aceasta experiență este că, deși nu toate schimbările de cerință pot fi anticipate din timp, este bine să încerci să prevezi ceea ce va urma, pentru că în acest fel API-ul va deveni mult mai ușor de extins și vor fi și mai puține modificări incompatibile cu versiunea anterioară. 

Conferință TSM

NUMĂRUL 147 - Automotive

Sponsori

  • Accenture
  • BT Code Crafters
  • Accesa
  • Bosch
  • Betfair
  • MHP
  • BoatyardX
  • .msg systems
  • P3 group
  • Ing Hubs
  • Cognizant Softvision
  • Colors in projects