Page 5 of 5 FirstFirst ... 3 4 5
Results 61 to 72 of 72

Thread: Delphi Meetup bij Coolblue: Behind the Scenes Delphi - 29 november

  1. #61
    Quote Originally Posted by jkuiper View Post
    Hoe stabiel is Delphi dan voor grote bedrijven als men geen gebruik kan maken van de standaard oplossing, die geboden wordt?
    Tja, dat is helaas wel vaker het geval. De VCL is wat dat betreft bedroevend qua uitbreidbaarheid en aanpasbaarheid. Het was vooral een heel gepuzzel om 'm toch te kunnen gebruiken. We hadden uiteindelijk ook onze eigen componenten kunnen schrijven, of een 3rd party library kunnen zoeken, maar we hebben in dit geval gekozen voor de standaard componenten, juist omdat de verwachting is dat dit soort kinderziektes en onvolkomendheden waarschijnlijk nog wel gladgestreken worden. Rest zal tenslotte nog wel een poosje blijven, en Embarcadero heeft er alle belang bij om die componenten goed te krijgen en te houden.

    Uiteindelijk was het ook niet heel ingewikkeld. Het probleem is vooral dat Delphi uberhaupt geen nullables kent. Spring heeft die wel, maar dat is intern in feite een record met een IsNull vlaggetje en de daadwerkelijke waarde. De JSON conversie van Delphi snapt niet hoe je een string in een stuk Json moet vertalen naar zo'n record (of andersom), dus dat hebben we moeten hacken. Verder viel het wel mee. Dat soort maatwerk zal je ook altijd wel houden, en ik verwacht niet dat Embarcadero voor alles een standaard oplossing biedt. Het was alleen vervelend dat het niet makkelijk is om dit te doen. Ik zou verwachten dat je gewoon zelf een marshaler voor specifieke typen zou kunnen registreren, maar het was wel iets meer werk dan dat.
    1+1=b

  2. #62
    Quote Originally Posted by EricLang View Post
    Wat ik niet heel goed begrijp aan het concept is waarom je een virtualinterface instantieert met een event. Bepaal je in het event wat er moet gebeuren?
    Waar zit de daadwerkelijke code die doet wat ie moet doen?
    Dat is het inderdaad precies. TVirtualInterface is een class die zo'n beetje elke interface kan implementeren. Elke method die je op de interface aanroept wordt simpelweg doorgegeven aan die handler die je meegeeft. De handler doet dus al het werk, en je schrijft dus in feite alsnog zelf de implementatie van de interface. Wat TVirtualInterface voor je doet, is het vertalen van de call naar de interface naar een generieke aanroep. Een soort catch-all voor method aanroepen. Het is een beetje vergelijkbaar met __call in PHP, voor wie daar weleens wat mee gedaan heeft.

    Het gevolg is dat je de logica in één hander kan stoppen, en daarmee een generieke afhandeling kunt schrijven voor meerdere interfaces.
    1+1=b

  3. #63
    Quote Originally Posted by GolezTrol View Post
    Het probleem is vooral dat Delphi uberhaupt geen nullables kent. Spring heeft die wel, maar dat is intern in feite een record met een IsNull vlaggetje en de daadwerkelijke waarde. De JSON conversie van Delphi snapt niet hoe je een string in een stuk Json moet vertalen naar zo'n record (of andersom), dus dat hebben we moeten hacken. Verder viel het wel mee. Dat soort maatwerk zal je ook altijd wel houden, en ik verwacht niet dat Embarcadero voor alles een standaard oplossing biedt. Het was alleen vervelend dat het niet makkelijk is om dit te doen.
    It is honestly a pity that you have not looked at kbmMW in detail It natively supports supports nullable, not only for its ORM, but for its JSON, YAML, XML, BSON, MessagePack, REST and logging. Another problem that kbmMW solved is the support for timezones for TDateTime, again supported all thru the framework. IMO (Im terribly biased... I know !!! ) kbmMW honestly just makes it so much easier to truely do n-tier solutions. Im eating my own dogfood, and with every new place I go to, implement kbmMW app servers, while learning from their setup what true life issues there are, and implements support for those things in a generic way in kbmMW.
    Im happy that Benno and Luigo enjoys using kbmMW... Im sad that many others havnt had the chance or taken the opportunity to use it.

  4. #64
    Senior Member EricLang's Avatar
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,148
    Code:
    Het gevolg is dat je de logica in één hander kan stoppen, en daarmee een generieke afhandeling kunt schrijven voor meerdere interfaces.
    Oh, niet gek inderdaad als je het gestructureerd doet. Heb je nog wel gestructureerde parameters dan?
    Code:
    case Args[0] of // interface
      Tralala: Zing(Args[1], Args[2]); // ?
      Hoempapa: Blaas(Args[1]); // ?
    end;

  5. #65
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    9,859
    Hoe is TVirtualInterface het anders dan idispatch ? Hetzelfde principe maar dan los van COM ?

  6. #66
    Quote Originally Posted by marcov View Post
    Hoe is TVirtualInterface het anders dan idispatch ? Hetzelfde principe maar dan los van COM ?
    Los van COM ja.Ik denk eerlijk gezegd dat het zwaar leunt op dezelfde gedachte, alleen de technische overeenkomsten weet ik niet precies, want ik heb nooit in zoveel detail naar IDispatch gekeken. Overigens werkt TVirtualInterface volgens mij op basis van RTTI, werkt het ook met interfaces die geen IDispatch zijn. Het is een class die de call naar een willekeurige method in de interface, met al z'n argumenten doorgeeft aan een callback method. Die krijgt de method naam, een array van TValues (argumenten), en een var TValue voor het result. TValue is een soort variant in de Rtti units is gedefinieerd.
    1+1=b

  7. #67
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    9,859
    idispatch is vooral de functionaliteit dat een call naar een method (b.v. eenmethodnaam(param1,parma2,param2) naar een call van een method met method naam en een array van parameters (+ enumeratie van types, COM heeft er niet zoveel) word omgezet. Vervolgens kan je die info gebruiken om met COM introspection (RTTI) die te verwerken.

    Dat is de compiler magic. Ik neem aan dat Tvirtualinterface zoiets ook nodig heeft, maar dan voor de typering RTTI reference passed (zodat er meer types gebruikt kunnen worden).

    Het daadwerkelijk uitlepelen van de RTTI is gewoon RTL werk.

    Een en ander lijkt mij vooral nuttig voor FFI

  8. #68
    Jos gebruiken jullie die virtual interfaces nu vooral voor "cheap" refactoren van jullie grote codebase?

    In de presentatie van Erik kwam bv het klassieke probleem naar voren waarbij elk form (of in ieder geval de meeste) een eigen datamodule heeft en je dus onherroepelijk ook dezelfde businesscode op meer plekken gaat zien. Volgens mij was een van de doelen in jullie services verhaal het samenvoegen van die businesslogica in standaard modules (volgens mij services in jullie context). Is het dat stukje waar je die virtual interfaces gebruikt of hebben jullie daar weer een ander slim iets voor bedacht om dat werkbaar te krijgen?

    Die case met verspreide logica is namelijk iets wat je op heel veel plekken ziet, vooral als onderhoudsvogel die delphi apps nog een poosje in de lucht moet helpen houden.

  9. #69
    Senior Member EricLang's Avatar
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,148
    Code:
    Die case met verspreide logica is namelijk iets wat je op heel veel plekken ziet, vooral als onderhoudsvogel die delphi apps nog een poosje in de lucht moet helpen houden.
    En inherent aan de form <-> datamodule ontwikkeling, wat eigenlijk gewoon niet deugt qua idee. Ook in Visual Studio projecten zie je gelijksoortige problemen.
    Zo vaak zie je duplicering (oh, heb hier nog even een klant-info of lookup-dingetje nodig...).

  10. #70
    Ja, we hebben daar nog steeds heel veel van. Om dat op te lossen, zijn we een tijd geleden al steeds meer losstaande datamodules gaan maken die niet een directe relatie hadden met één schermpje. Dus omdat er bijvoorbeeld vanuit diverse flows geld teruggestort moet worden, krijg je dan een TDtmFinance module met een Refund method erop, bijvoorbeeld. In sommige gevallen instanteerden we die waar nodig, maar in veel gevallen was dat een soort singleton-achtige constructie, met een functie die een instantie teruggeeft (net zoals Clipboard en Printer al jaren in de VCL doen). Handig, maar toch niet handig, want uiteindelijk heb je dan alsnog grote blokken gecentraliseerde functionaliteit in je applicatie rondzwerven.

    De laatste tijd zijn we de code meer aan het voorbereiden geweest op testbaarheid, en meer praten tegen interfaces. Om dat voor elkaar te krijgen heeft een collega een nieuw framework geschreven voor het maken van models. Dat werd kort aangehaald door Mike, maar er zitten wat haken en ogen aan, omdat het een heel nieuwe structuur is, en dus niet goed toegepas kan worden op de vele bestaande schermpjes die we al hebben. Ook qua implementatie schort er nog wel wat aan, maar dat maakt verder niet zoveel uit. We hebben dat vooral achterwegen gelaten omdat het eigenlijk nagenoeg een nieuw framework is, en in die zien green field development wat iedereen van scratch zou kunnen doen.

    We hadden in sommige schermpjes aanpassingen gedaan om inversion of control (IoC) toe te kunnen passen: interfaces mee te geven aan de constructor (of in een property) en op die manier nieuwe functionaliteiten te kunnen toevoegen, zonder dat er direct een (class) afhankelijkheid naar is. Ook dat was nog tamelijk omslachtig, en pas heel recent (na de bekendmaking van het programma van de meetup), heb ik met Mike een oplossing uitgepuzzeld om IoC middels dependency injection op een makkelijke manier breed inzetbaar te maken in het volledige oude framework, zonder dat we daarvoor elk scherm moesten gaan aanpassen. We hebben nu dus nog steeds de class-afhankelijkheid tussen de controller, form en datamodule, maar die worden elk via de Spring4D container geinstantieerd, en kunnen dus geinjecteerd worden met extra functionaliteit.

    Dat laatste stelt ons in staat om makkelijker en op grotere schaal functionaliteiten te gaan losweken, centraliseren, en in een geabstraheerde manier te gebruiken in de applicatie.

    Die functionaliteiten kunnen bijvoorbeeld een stukje logica met een paar database calls zijn, of een call naar een API. Dat maakt niet zoveel uit; het schermpje praat tegen de interface. De voornaamste winst is dat we nu makkelijker logica kunnen scheiden van database-interactie, maar dat is nog steeds grotendeels handwerk, en een minutieus werkje.

    Maar om daarbij te helpen, helpt het wel als je bepaalde delen makkelijker kan herbouwen. De virtualinterface is daar een onderdeel van, en gebruiken we om een generieke implementatie te schrijven rond, bijvoorbeeld een query of een API call. In de manier waarop Mike hem toepaste, zou je het eigenlijk simpelweg kunnen zien als een speciaal soort TDataSet. We hebben een stuk SQL, en we hebben een interface die de velden bevat, en een method op de query te openen. Het verschil is alleen dat een TDataSet een specifieke class is die je niet zomaar overal wilt gebruiken. Of je hebt persistent fields, maar dan moet je bij de individuele field components kunnen, of je hebt de veldnamen als string, met alle kans op fouten.

    Een interface is wat dat betreft wat netter, bijvoorbeeld als je een lookup wilt hebben voor de winkels die we hebben.. Je hebt dan een query

    SELECT shop_id, shop FROM shops

    Dat is zo'n snel lookup dingetje dat we op 100 plaatsen hebben gekopieerd in het verleden, met een simpel datasetje in de datamodules voor order, invoice, complaint, noem maar op.

    Maar om dat los te trekken van TDataSet en de stringrepresentatie van velden, heb je een record of class nodig die zo'n shop kan verbeelden. En een lijst daarvan, als je een lijstje shops wilt hebben. En vervolgens heb je een brok code nodig die je de query gaat uitvoeren en het resultaat in je class of record gaat zetten. En dat dan ook voor die honderden andere queries. En dat is nu allemaal grotendeels in die TVirtualInterface gevat. We hebben nu dus een generiek object dat alle queries uit kan voeren, en het enige dat je hoeft te doen is iets te schrijven als:

    Delphi Code:
    1. type
    2.   [Query('shops.sql')]
    3.   IShopLookup = interface(IVirtualDataset)
    4.     function GetShopId: Integer;
    5.     function GetShopName: String;
    6.   end;
    Of een variatie als:
    Delphi Code:
    1. TShop = record
    2.     ShopId: Integer;
    3.     ShopName: String;
    4.   end;
    5.   [Query('shops.sql')]
    6.   IShopLookup = interface(IVirtualDataset)
    7.     function GetShops: TArray<TShop>;
    8.   end;
    Die interface met z'n attributen (en de SQL zelf) zijn het enige wat nodig is om dit te kunnen gebruiken, en als geinjecteerde interface kan je 'm ook makkelijk mocken of stubben, doorgeven, cachen, als singleton registreren in je container, enz. Natuurlijk is het ook weer niet de heilige graal voor alles, want een TDataSet is weer makkelijker aan een LookupCombobox te hangen dan een TArray<TShop>, maar niettemin is er best veel mee te winnen.
    1+1=b

  11. #71
    Op verzoek van meerdere mensen zijn de threads toch maar gesplitst en heropend.
    1+1=b

  12. #72
    Senior Member EricLang's Avatar
    Join Date
    May 2002
    Location
    Holland
    Posts
    3,148
    duimen op :-)

Page 5 of 5 FirstFirst ... 3 4 5

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •