Hajuja ja sääntöjä OA2005 Huonon suunnittelun oireita Kankeus suunnitelmaa on vaikea muokata. Hauraus suunnitelma on helppo rikkoa. Liikkumattomuus suunnitelmaa on hankala uudelleenkäyttää. Viskositeetti hankalaa tehdä asiat oikein. Tarpeeton kompleksisuus ylisuunniteltu. Tarpeeton toisto hiiren väärinkäyttö. Sameus järjestymätön ilmaisu. Hyvän suunnittelun periaatteet 1. Yksi vastuu (single responsibility, SRP) 2. Avoin-suljettu (open-closed, OCP) 3. Liskovin korvaussääntö (Liskov substitution, LSP) 4. Riippuvuuden kääntäminen (dependency inversion, DIP) 5. Rajapintaerottelu (interface segregation, ISP) Paha haju Paha haju suunnitelmassa on aina oire jostakin suunnitteluongelmasta, esim. kankeus! huonosti huomioitu OCP. Korjataan varmistamalla periaatteen pitävyys suunnitelmassa. vain jos tarvitaan ei parfymointia; siitä on seurauksena vain tarpeeton kompleksisuus
Ohjelmisto mätänee, aina. Alussa kaikki on aina hienosti, sitten tapahtuu se pieni virhe......ja mätäneminen alkaa. Mätänemistä voi estää ja hidastaa, sitä tulee estää ja hidastaa. Mätäneminen näkyy ylläpidon vaikeutena. Ylläpitoa on myös ohjelman kehitys! Mätänemisen syy löytyy......tekijöistä! Mätäneminen alkaa, kun ohjelmisto ei pysty vastaamaan muuttuviin vaatimuksiin. Vaatimukset muuttuvat aina, jos tätä ei ohjelmiston tekijä ota huomioon, on hän yksinkertaisesti huono tekijä. Kankeus Ohjelmistoa on hankala muokata, sillä muokkaus yhdessä kohdassa pakottaa muokkaamaan ohjelmistoa muualtakin. Se olikin paljon monimutkaisempi muutos kuin oletin! Hauraus Yksi muutos saa ohjelmiston hajoamaan useasta eri kohdasta. Jatkuvasti korjattavana olevat osat ohjelmistosta, jotka vain huonontuvat korjaus korjaukselta.
Liikkumattomuus, siirrettävyyden puute Ohjelmisto on hankala purkaa uudelleenkäytettäviin komponentteihin. Aikaa vievää tai kallista, tai ei vain vaivan arvoista. Ohjelmiston viskositeetti Ohjelmistoa voi muuttaa niin, että suunnitelmat pysyvät, tai niin että suunnitelmat pettävät. Jos ensimmäinen on hankalampaa kuin jälkimmäinen, on viskositeetti suuri; on helppoa tehdä vääriä ratkaisuja. Ohjelmisto tulisi suunnitella niin, että suunnitelman säilyttävät muokkaukset olisivat helppoja ja houkuttelevampia kuin suunnitelmat rikkovat muokkaukset. Ympäristön viskositeetti Jos kehitysympäristö on hidas ja heikkotehoinen, ohjelmiston tekijät alkavat suosia ratkaisuja, joiden toteuttaminen ei vaadi liikaa ympäristöltä, esim. ei suuria uudelleenkäännöksiä. Jälleen ohjelmiston suunnitelma ei säily, se pyrkii muuttumaan heikon kehitysympäristön ehdoilla. Tarpeeton kompleksisuus Valmistaudutaan tuleviin tarpeisiin tai vaatimuksiin etukäteen. Tuottaa paljon tarpeetonta, käyttämätöntä suunnitelmaa. Hankaloittaa ylläpitoa ja ymmärtämistä.
Tarpeeton toisto Jaskan täytyy toteuttaa hörpätin. Hän kaivaa suunnitelmasta esille palasen, joka muistuttaa hörpätintä ja kopioi tästä toteutuksen. Jaskan käyttämän palasen on tehnyt Ere, joka on löytänyt sen Penan tekemästä palasesta. Pena taas on ottanut sen kopioimalla ja muokkaamalla riplakkeen toteuttavan pätkän. Korjaaminen työlästä, mutta kannattavaa. Valitettavasti yksi korjaus ei enää riitä. Sameus Kun ohjelmiston osaa muokataan ja kehitetään, se samenee. Sameneminen estää osan ymmärtämisen. Uutta osaa tehtäessä ollaan sisällä työssä, immersioituneita. Jälkeenpäin osa ei enää näytäkään niin selkeälle. Suunnitelmat pitää tehdä luettaviksi ja ne pitää luetuttaa toisilla tekijöillä. Yhden vastuun periaate Luokalla tulee olla vain yksi syy muuttua. Väärä suunnittelu haisee kankealle ja hauraalle. interface Modem { public void dial(string pno); public void hangup(); public void send(char c); public char receive(); Yhden vastuun periaate interface DataChannel { public void send(char c); public char receive(); interface Connection { public void dial(string pno); public void hangup(); class ModemImplementation implements DataChannel, Connection { //...
Avoin-suljettu periaate Avoin-suljettu periaate Ohjelmiston osien tulee olla avoimia laajennoksille, mutta suljettuja muokkauksilta. Väärä suunnittelu haisee kankealle. Client Client Server «interface» Client interface Server Avoin-suljettu periaate Avoin-suljettu periaate Piirretään ympyröitä (Circle) Piirretään neliöitä (Square) Molemmat ovat muotoja (Shape) Järjestyksellä on väliä enum shape_t { circle, square ; struct shape { shape_t type; ; struct circle { shape_t type; double radius; point center; ; struct square { shape_t type; double side; point top_left ; void draw_square(struct square *); typedef struct shape *shape_p; void draw_all_shapes(shape_p *list, int n) { int i; for (i=0; i<n; i++) { struct shape *s=list[i]; switch (s->type) { case square: draw_square((struct square *)s); break; case circle:...
Avoin-suljettu periaate class shape { public: virtual void draw() const = 0; ; class square : public shape { public: virtual void draw() const; ; void draw_all_shapes(vector<shape*>& list) { vector<shape*>::iterator i; for (i=list.begin(); i!=list.end(); ++i) (*i)->draw(); Järjestyksellä on väliä. " Nykyinen malli ei mahdollista tätä. " Mikään malli ei ole luonnollinen kaikkiin konteksteihin. Mitkä muutokset ovat todennäköisiä? Odotetaan, kunnes muutokset ilmenevät. Stimuloidaan muuttumista. Liskovin vaihdantaperiaate Alityyppien täytyy olla käytettävissä ylityyppeinään. void g(rectangle r) { r.setwidth(5); r.setheight(4); assert(r.area()==20); Liskovin vaihdantaperiaate Liskovin periaate Eristettyä mallia ei voi mielekkäästi validoida. IS-A liittyy käytökseen. Design by contract, sopimukset ohjelmoijatesteihin. Varo aliluokkia, joiden metodit rajoittaa yliluokan metodin toiminnallisuutta. Varo aliluokkia, joiden metodit voivat aiheuttaa poikkeutuksia, joita yliluokan metodit eivät voi.
Riippuvuuden kääntäminen Ylätason moduulien ei tule riippua alatason moduuleista. Molempien riippuvuudet tulisi olla abstraktioihin. Abstraktiot eivät saa riippua yksityiskohdista. Yksityiskohtien tulisi riippua abstraktioista. Policy Layer Mechanism Layer Riippuvuuden kääntäminen Utility Layer Riippuvuuden kääntäminen Rajapintaerottelu Asiakkaita ei tulisi pakottaa riippuvaisiksi metodeista joita ne eivät käytä. Jaa lihava rajapinta useisiin erillisiin rajapintoihin.
Paketointi Uudelleenkäyttö-julkaisu yhteys (the reuse-release principle, REP) Yhteinen uudelleenkäyttö (the common reuse principle, CRP) Yhteinen sulkeuma, (the common-closure principle, CCP) Syklittömät riippuvuudet (the acyclic-dependencies principle, ADP) Vakaat riippuvuudet (the stable-dependencies principle, SDP) Vakaat abstraktiot (the stable-abstractions principle, SAP) Uudelleenkäyttöjulkaisu yhteys Uudelleenkäytön osanen on myös julkaisun osanen. (granule) käytetyn kirjaston toivoisi olevan mieluusti ylläpidetyn, ja siirtymisen versiosta toiseen asiakkaan päätettävissä (vanhaa versiota tuettava) täytyy löytyä uudelleenkäytettävä paketti jos joku paketin luokista on uudelleenkäytettävissä, kaikkien on oltava paketin luokkien on oltava saman tahon uudelleenkäyttämiä (ei sotketa esim. toimialaluokkia ja yleiskäyttöisiä säilöluokkia samaan pakettiin) Yhteinen uudelleenkäyttö Paketin luokkia uudelleenkäytetään yhdessä. Jos yhtä luokkaa uudelleenkäytetään, käytetään kaikkia. mitä luokkia laitetaan samaan pakettiin mitkä luokat jätetään paketista pois Yhteinen sulkeuma Luokat paketissa ovat suljettuja samankaltaisten muutosten suhteen. Muutos, joka vaikuttaa pakettiin, vaikuttaa kaikkiin sen luokkiin, muttei muihin paketteihin. Vertaa yksi vastuu (SRP), muista myös avoin-suljettu (OCP).
Syklittömät riippuvuudet Ei syklejä pakettigraafeihin. Korjausehdotuksia riippuvuuden kääntäminen luo uusi paketti, siirrä osalliset sinne Vakaat riippuvuudet Riippuvuudet kohti stabiiliutta. C a (afferent couplings): ulkopuolisten, paketista riippuvien luokkien määrä C e (efferent couplings): sisäpuolisten, muista paketeista riippuvien luokkien määrä Ce I: epästabiilius I = Ca + Ce Vakaat abstraktiot A-I graafi Paketin tulee olla yhtä abstrakti kuin se on stabiili. N c : Luokkia paketissa N a : Abstrakteja luokkia paketissa A: abstraktius A = Na Nc (0,1) Abstraktius Kipualue Epästabilius Tarpeettomat (1,0)