![]() |
Second Opinion
Folosind serviciul second opinion ne puteți trimite RMN-uri, CT -uri, angiografii, fișiere .pdf, documente medicale. Astfel vă vom putea da o opinie neurochirurgicală, fără ca aceasta să poată înlocui un consult de specialitate. Răspunsurile vor fi date prin e-mail în cel mai scurt timp posibil (de obicei în mai putin de 24 de ore, dar nu mai mult de 48 de ore). Second opinion – Neurohope este un serviciu gratuit. www.neurohope.ro |
Baze de date embedded – exercitiu practic (pentru programatori mid-level)

#37
Posted 17 September 2018 - 19:08

Am înțeles. Se poate spune și că excepțiile pe care le prindeam in main.cpp făceau un leak în privința modului în care funcționează storagePlugin? La urma urmei, el putea să fie orice altceva decât o bază de date embedded (spre exemplu un STL container).
Concret, responsabilitatea lui core domain este de a se asigura că plugin-ul respectiv rulează, fără să-l intereseze motivele? |
#38
Posted 17 September 2018 - 19:27

#39
Posted 17 September 2018 - 19:55

Am înțeles. Se poate spune și că excepțiile pe care le prindeam in main.cpp făceau un leak în privința modului în care funcționează storagePlugin? La urma urmei, el putea să fie orice altceva decât o bază de date embedded (spre exemplu un STL container).
Concret, responsabilitatea lui core domain este de a se asigura că plugin-ul respectiv rulează, fără să-l intereseze motivele? Pana acum in discutiile noastre am simplificat putin lucrurile pentru directorul src/phonebook/ si la un moment viitor urmeaza sa faci refactoring conform cu ce voi scrie mai jos: Momentan in src/phonebook/ ai doua componente cu o relatie simbiotica intre ele. La nivel conceptual ele sunt diferite, insa momentan ai acolo un amestec greu de distins la nivel de cod. 1. cod de infrastructura 2. domain model Codul de infrastructura sunt clase precum Application. Acele clase care pot fi reutilizate intr-o arhitectura similara pentru o alta aplicatie Domain model este reprezentarea programatica, formala, a regulilor de business. Bine, in aplicatia de fata ai un domain model anemic (chiar titlul proiectului zice ca e o simpla aplicatie crud), dar cred ca intelegi unde bat: exersezi pentru proiecte mai complicate ca acest "crud app - phone book". In domain model scopul tau e sa scrii cod atat de expresiv, incat chiar si product owner (clientul care plateste pentru program) poate intelege ce se intampla, ce face codul, fara cunostinte de programare. Nu e SF, tipic pentru acesti oameni e gandirea analitica, deci inteleg codul. Personal touch: discutiile cu PO pe cod sunt discutiile mele favorite. Pe langa faptul ca sunt amuzante si creative, ii si da lui PO increderea ca stii ceea ce faci, caci si el insusi se simte in controlul proiectului. Asta iti aduce si tie beneficii profesionale. Alt avantaj al unui domain model expresiv e ca reguli de business noi devin emergente. Exemplu: PO vrea un nou feature, si e mult mai evident si mai clar la nivel de cod concret unde si cum e cel mai bine sa integrezi acel cod in cadrul src/phonebook/ (in cazul nostru). De ce? Deoarece codul nu mai e incarcat cu un numar mare de linii de cod ce tin de fie baza de date, fie ui, fie logging, caching, cu ceva algoritm relevant pentru business rules presarat pe ici pe colo, printre infinitul de linii irelevante. Tot din acelasi rationament: cand creezi un nou feature, observi mult mai usor patterns si le poti extrage in abstractii (clase, componente) comune, reutilizabile. Uneori in astfel de situatii se intampla chiar sa te faca sa vii cu idei de solutii noi la probleme, deoarece codul insusi iti sopteste ce se intampla de fapt. Cand esti in mijlocul discutiei PO si spui abordari la care PO nu s-a gandit, iti creste valoarea. Deci, da, responsabilitatea lui 1. cod de infrastructura este sa se asigure ca pluginurile ruleaza, sau daca esueaza, ca aplicatia esueaza in mod corect (true positive si true negative). Responsabilitatea lui 2 e sa modeleze business rules, algoritmii, etc.
Termenul mă duce cu gândul la Dependency Injection. Gandeste-te concret la proiectul nostru: plugins primesc ca parametru alte plugins ca dependinte, si isi extrag din ele alte componente mai granulare (ex: ReadModel mentionat intr-o postare anterioara), si le paseaza in adancime altor componente din sie insasi (=acelasi plugin). Concret: nu stiu ce dialog primeste ca parametru doar ce are el nevoie: obiect ReadModel). DI*** in action e acea metoda Plugin::init, sau MyDialog::MyDialog(ReadModel...). Nimic complicat, fancy sau mai stiu eu ce, ci solutii simple la probleme simple. *** DI poate insemna dependency injection sau dependency inversion. Spunem ca: MyDialog respecta dependency inversion, iar apelantul sau injecteaza dependintele (dependency injection). Cele doua semnificatii ale lui "DI" sunt deci simbiotice. Edited by OriginalCopy, 17 September 2018 - 19:57. |
#40
Posted 17 September 2018 - 20:55

OK, am revenit cu un update referitor la tratarea excepțiilor, acestea nu mai interacționează cu codul specific aplicației.
|
#41
Posted 17 September 2018 - 20:59

OK, am revenit cu un update referitor la tratarea excepțiilor, acestea nu mai interacționează cu codul specific aplicației. ![]() |
#42
Posted 17 September 2018 - 21:13

Deci, da, responsabilitatea lui 1. cod de infrastructura este sa se asigure ca pluginurile ruleaza, sau daca esueaza, ca aplicatia esueaza in mod corect (true positive si true negative). Responsabilitatea lui 2 e sa modeleze business rules, algoritmii, etc. Business rules s-ar putea referi la:
Daca privesti critic codul cum e el, ce alt refactoring ai face in pasul urmator? Cod specific C++? |
#43
Posted 17 September 2018 - 21:51

Da, aia e esenta lui "domain model". Nu inseamna ca ai strict doar liniile de cod gen "if(reservation.getSeats() > 5) return false", poti avea multe clase care fac lucruri diferite, poti folosi actor model ca arhitectura interna a lui domain model, sau "event-based model", s.a.m.d. Dar codul din src/phonebook/ nu e legat de niciun vendor, e doar cod C++ "curat", indiferent de abordari.
Da, fara schimbari arhitecturale deocamdata, doar "clean-ups". Curatenia la care ma astept nu e specifica C++. Eu am cateva lucruri in minte, dar nu ma astept sa zici exact ce vreau eu. Vreau doar sa exersezi "identificarea de pasi de urmat" si sa ii prioritizezi in mod rezonabil, daca ai mai multi pasi. |
#44
Posted 17 September 2018 - 21:58

Nu-mi place bucata asta:
void UiMainWidget::init(std::vector<IPlugin*> const& dependencies) { if (typeid(dependencies.front()) != typeid(_dependencies.front())) throw NonMatchingDependencyTypeException( "The provided plugin is not the needed one."); ui.setupUi(this); _storagePlugin = dynamic_cast<InMemorySQLiteStoragePlugin*>(dependencies.front()); ui.tableView->setModel(_storagePlugin->getModel()); } Am trișat prin faptul că știu că Ui depinde doar de un plugin. Trebuia să vin cu o soluție mai generalistă. |
#45
Posted 17 September 2018 - 22:08

Nu-mi place bucata asta: void UiMainWidget::init(std::vector<IPlugin*> const& dependencies) { if (typeid(dependencies.front()) != typeid(_dependencies.front())) throw NonMatchingDependencyTypeException( "The provided plugin is not the needed one."); ui.setupUi(this); _storagePlugin = dynamic_cast<InMemorySQLiteStoragePlugin*>(dependencies.front()); ui.tableView->setModel(_storagePlugin->getModel()); } Am trișat prin faptul că știu că Ui depinde doar de un plugin. Trebuia să vin cu o soluție mai generalistă. Problema e ca nu faci ce am zis intr-o postare anterioara: nu destructurezi dependintele in UiPlugin. Bine ar fi sa ai _widget.init(this->_readModel); in UiPlugin si in UiPlugin::init sa iti extragi _readModel din DB plugin. Sau altfel spus, dynamic_cast mutat cu un layer mai sus, din widgetul concret in plugin. De ce? Pai mai multi widgets vor avea nevoie de read model, nu e o chestiune limitata la acel widget. Altceva? Enumera cativa pasi, si ordinea lor. Edited by OriginalCopy, 17 September 2018 - 22:12. |
#46
Posted 17 September 2018 - 22:36

1. Mut vector<IPlugin*> _dependencies, respectiv InMemorySQLiteStoragePlugin _storagePlugin din widget în UiPlugin.
2. Reimplementez metodele init() in clasele respective. |
|
#47
Posted 17 September 2018 - 22:47

1. Mut vector<IPlugin*> _dependencies, respectiv InMemorySQLiteStoragePlugin _storagePlugin din widget în UiPlugin. 2. Reimplementez metodele init() in clasele respective. Dar chiar ai nevoie de storage plugin salvata in ui plugin? Nu e suficient sa extragi ce ai nevoie din storage plugin in init(), si sa salvezi doar acele servicii oferite de storage in ui? Cu storage plugin in ui plugin nu faci decat sa creezi tentatii, dar nu rezolvi o problema concreta. |
#48
Posted 18 September 2018 - 11:46

Done.
Am avut o singură problemă, pe care am rezolvat-o mutând QSqlQueryModel din StoragePlugin în InMemorySQLiteDatabase. Încă mă gândesc dacă se putea mai bine. |
#49
Posted 18 September 2018 - 11:57

Momentan layerele de sub plugin (detaliile/arhitectura fiecarui plugin) au intortocheri de parca ar fi pomul de craciun.
Dar inainte sa ne uitam la ele, vezi aici: https://github.com/I...tree/master/src ceva de reparat? |
#50
Posted 18 September 2018 - 12:00

|
#51
Posted 18 September 2018 - 13:03

Încă mă gândesc dacă se putea mai bine. Nu stiu daca si in ce masura urmatoarele principii te vor ajuta sau daca sunt aplicabile chiar acum in situatia ta, dar sunt demne de tinut minte in general:
|
|
#52
Posted 18 September 2018 - 17:48

Ok, implementeaza cand ai o solutie, sau vino cu posibile abordari si avantajele/dezavantajele fiecareia, daca ai mai multe si nu stii ce sa alegi. A doua abordare ar fi să mut QSqlQueryModel în SQLiteDatabase (clasa părinte), iar InMemorySQLiteDatabase să-l moștenească. Nici acest approach nu mi se pare cel mai bun. Mă mai gândesc.
in exterior nu ai voie sa expui detalii de implementare class InMemorySQLiteStoragePlugin : public IPlugin { public: // std::vector<IPlugin*> getDependencies() const; void init() override; int run() override; void shutDown() override; InMemorySQLiteDatabase _database; private: void init(std::vector<IPlugin*> const& dependencies) override{}; }; Plugin-ul pune la dispoziție metode (prin intermediul lui InMemorySQLiteDatabase) care i-ar putea corupe state-ul (așa cum ai menționat la punctul 2). Mda, cred că întrebarea mea devine retorică.
evita setterii Edited by jegmihai, 18 September 2018 - 17:50. |
#53
Posted 18 September 2018 - 18:20

#54
Posted 18 September 2018 - 18:23

Cateva observatii, pe partea specifica C++:
Edited by dani.user, 18 September 2018 - 20:15. |
Anunturi
▶ 0 user(s) are reading this topic
0 members, 0 guests, 0 anonymous users