TIE-20200 Ohjelmistojen suunnittelu Viimeinen luento: kertaus 1
Ajankohtaista Harjoitustyön dedis 7.12. klo 06:00 Demoilusessiot samalla/seuraavalla viikolla Harjoitustyön neuvontapäivystystä KE 15-16 TE116 (Samuel), muulloinkin sopii tulla jos oon vaan paikalla
Ohjelmassa tänään Lyhyesti CI- & CD-jutuista Pikakertaus kurssin aihealueesta Tentin rakennetta, kysymyksien tyyliä Sananen harjoitustyön arvioinnista jne.
Arvostelukriteeristöä Suunnittelu, rakenne Jako eri osa-alueisiin, korkean tason rakenne Spagetti vs. selkeät vastuualueet Rajapintojen suunnittelu, toiminnallisuuden jako Dokumentaatio Selkeys, luettavuus, tarkoituksenmukaisuus Auttaako dokumentin lukeminen ohjelman ymmärtämisessä vai päinvastoin? Toteutus/koodi Ulkonäkö, luettavuus, funktioiden ja luokkien pituudet, nimeäminen, vakioiden käyttö jne. esi-jälkiehdot, invariantit, jne. esitietokursseilta tuttu asia Yhteneväisyys, kommentit (miten ja mitä kommentoitu vs. määrä) Toiminnallisuus, toimiiko peli (vai kaatuilee), tehtiinkö mitä luvattiin? Muut Versiohallinnan käyttö Testit, bonusta yksikkötestit, omat järkevät testitiedostot tms. yms. Bonusta kiva ulkonäkö, hyvä pelisuunnittelu
Aihealueet Rajapinnat, rajapintojen suunnittelun periaatteita jne. Periytyminen, moniperiytyminen SOLID ja toisaalta huonon suunnittelun oireet Ohjelman jakoa loogisiin kokonaisuuksiin, MVC ja kumppanit Suunnittelumallien perusidea (tehtaat, tarkkailija), tapa kommunikoida toimivaksi havaittuja suunnitteluratkaisuja ja ideioita Lokalisointi Git/versiohallinta ja erilaiset käytännöt, CI/CD-kalut Riippuvuuksien syöttö, dependency injection Kirjastot, dynaaminen vs. staattinen Yksityiskohtia: Templatet, lambdat, QML (idea) (UML) mallintaminen, luokkakaaviot, rajapinnat, sekvenssikaaviot
Luettavaa, kurssimateriaali Olioiden ohjelmointi C++:lla (löytyy IDLEstä) Rajapinnat, sopimussuunnittelu: luku 8 Periytyminen, moniperiytyminen: kirjasta 6.7-6.11 API Design for C++ (nimestään huolimatta paljon yleistä suunnitteluohjetta, ei pelkästään API-suunnittelua) Pääsy TTY:n verkosta, VPN-yhteydellä kotoa Luku 3: pattern-kamaa (älä innostu liikaa singletonista, se ei ole ystävä...) Luku 4: Yleisesti suunnittelusta, SOLID Luku 10: testaamisen suunnittelusta Luku 12: plugin-juttuja SOLIDista ja suunnittelusta http://www.objectmentor.com/resources/articles/principles_and_patterns.pdf http://butunclebob.com/articles.unclebob.principlesofood Singletonin pahuudesta (kirjassa paljon singelton-asiaa, tämä huomioitavana asiana) http://butunclebob.com/articles.unclebob.singletonvsjustcreateone http://www.ibm.com/developerworks/webservices/library/co-single/ http://blog.code-cop.org/2012/01/why-singletons-are-evil.html http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/
Tentin rakenteesta 1 kpl pikkukysymyksiä 0..2 kpl koodia tai kaavioita, joko itse piirtäen tai tutustuminen & vastaaminen kysymyksiin 1 kpl väärin oikein perustele 0..1 kpl esseehtävä kysymys
Huonon suunnittelun tunnusmerkistöä Huonon suunnittelun kriteeristöä Ei siirrettävää koodia, ohjelman rakenne täynnä riippuvuuksia, komponentteja ei voi uudelleen käyttää tai siirtää näiden takia (immobility) Jäykkyys, yksittäinen muutos vaikuttaa moneen muuhun osaan (rigidity) Hauraus, muutos yhteen osaan rikkoo asioita muualla (fragility) STUPID singleton, tight coupling, untestability, premature optimization, indescriptive naming, duplication Boilerplate-koodin määrä (käyttäjä joutuu toistamaan paljon samaa koodia tehdäkseen haluamansa asian rajapinnan avulla)
Ja hyviä periaatteita SOLID Dependency injection Tarkat parametrityypit, ei tolkuttoman pitkiä parametrilistoja, nimeäminen kuvaavaa & johdonmukaista, soveltuu käyttäjälleen (oikea abstraktiotaso), riittävän ilmaisuvoimainen
Single responsibility principle Single responsibility principle (SRP) a class should have only a single responsibility. Vain yksi vastuualue/luokka Pohjautuu reason-to-change ajetelmaan, jokaisella luokalla pitäisi olla vain yksi huolehdittava asia, vain yksi syy, miksi luokan toteutusta pitäisi muuttaa. Jos luokalla kaksi tai useampi muutossyy, voi muutoksella yhden vastuualueen toimiin olla helposti vaikutusta toisen toimintaan (korjataan yhtä, rikotaan toinen) Uudelleenkäyttö ja eriyttäminen vaikeampaa, kun mukana tulee ylimääräistä kuormaa
Open-closed principle Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification You should be able to extend a classes behavior, without modifying it. Moduulit ja luokat: Ovat avoimia laajennuksille, toiminnallisuutta voidaan lisätä, rajapintaa laajentaa uusilla palveluilla Suljettu muutoksilta: moduulin tai luokan toteutusta ei saa muuttaa Koodi testattu, katselmoitu jne, sitä ei enää muuteta Kuulostaa ristiriitaiselta, ideana hyödyntää abstraktioita Voidaan käyttää hyväksi perintää, (abstrakteja) kantaluokkia Ohjelmat, joissa hyödynnetään open-closed periaatetta, muutetaan lisäämällä uutta koodia, ei muuttamalla olemassa olevaa Ei realistisesti mahdollista päästä tilanteeseen, jossa 100% koodista suljettuna muutoksilta pitää tehdä päätöksiä siitä, mihin panostetaan, missä ohjelman osissa tulee todennäköisimmin muutoksia? Abstraktiot, ja osan ohjelmakoodin sulkeminen.
Liskov substitution principle Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program. Derived classes must be substitutable for their base classes Mikä tahansa aliluokan instanssi kelpaa kantaluokkaolion tilalle (ilman että ohjelman toiminta kärsii/muuttuu virheelliseksi) C++-maailmassa: mikä tahansa viitteen tai osoittimen luokkaan ottavan funktion on pystyttävä käyttämään mitä tahansa luokan aliluokkaa ilman että funktion toteutuksessa täytyy tietää todellinen tyyppi (taas vääränlaiset tyyppimuunnokset jne.) Toiminnalliset aliluokat: Toiminnallinen lisävaatimus pelkän syntaksivaatimuksen lisäksi (semantiikka), ei pelkkä syntaktinen yhteensopivuus (samat funktion protyypit jne.)
Interface segregation principle many client-specific interfaces are better than one general-purpose interface. Make fine grained interfaces that are client specific Rajapinnan käyttäjän ei pidä olla riippuussuhteessa palveluihin/funktioihin joita se ei tarvitse/käytä Jaetaan isommat rajapinnat pienemmiksi roolien mukaan, saadaan roolirajapintoja (role interfaces) Isompi ohjelma, jossa paljon keskinäisiä riippuvuuksia ja isoja möhkälerajapintoja pienikin muutos heijastuu joka puolelle muutoksen tekijä joutuu tonkimaan muutettavat asiat muun turhan sälän seasta yksittäiseen asiaan liittyvän toteutuksen vaihtaminen vaatii copy-pastea vanhoista koodeista ja uuden asian lisäämisen lisäksi Anti-versio periaatteesta, yksi iso möhkäleluokka, joka tarjoaa lähes kaikki toiminnot. Vaikea hallita, päivittää, muuttaa, jos rinnakkaisuutta, saadaan suorituskykyongelmat mukaan Lihavat rajapinnat (fat interfaces), rajapintojen saastuminen (interface pollution)
Dependency inversion principle A) High-level modules should not depend on low-level modules. Both should depend on abstractions. B) Abstractions should not depend upon details. Details should depend upon abstractions. http://www.objectmentor.com/resources/articles/dip.pdf Riippuvuudet abstraktioihin, ei konkreettisiin toteutuksiin Huonon suunnittelun kriteeristö vs. Dependency inversion
Suunnittelumalleista Mitä, miksi, mihin käyttöön? Observer Tehtaat MVC ja kumppanit Piirrä sekvenssikaavio, jolla voit kuvata pull-tyylisen MVCmallin toimintaa. Piirrä luokka- ja oliokaavio, jossa on tarkkailtava tapahtumalähde (Observable) nappula ja sille kaksi eri tarkkailijaa (Observer) pääikkuna ja lokiluokka. Katso esiteltyä koodia, mitä suunnittelumallia/ratkaisua siinä on käytetty?
Lambdat, templatet Idea, käyttökohteet, perusrakenne Esimerkkikysymys: Mitä vaatimuksia esitelty koodi asettaa tietotyypille (T)? Mitä esitellyssä koodissa tapahtuu? (mitkä ovat v:n ja summan arvot? std::vector< int > v = { 2, 3, 6, 9 }; int summa = 0; std::for_each(v.begin(), v.end(),[&summa](int a){summa +=++a;});
Moniperintä Käyttökohteet, vaarat, ongelmat, kuten toistuva moniperintä/diamond problem/repeated multiple inheritance Piirrää esimerkki toistuvasta moniperinnästä (diamond problem/repeated multiple inheritance) ja kerro siihen liittyvistä ongelmista. Selitä miten kahdesta eri kantaluokasta/rajapinnasta saatavat saman nimiset funktiot voivat olla ongelma.
Yhteenveto Kurssin tärkein opetus: suunnittelun ja ohjelman rakenteen vaikutus koodipuolelle: ohjelman jako osiin vs. koodi Kurssin jälkeen pitäisi olla eväitä olla mukana ohjelmien suunnittelutyössä, ymmärtää paremmin muiden tekemiä suunnitelmia Ymmärtää yleisimpiä suunnitteluratkaisuja, pohjataidot, joiden avulla kyky oppia uusia Tentiin kannattaa lukaista muutakin kun luentokalvot, erityisesti jos luennot & harkat ovat jääneet väliin (luentokalvot on tehty luentoja varten) TIE-20200 Samuel Lahtinen 18