aidosti modulaarisen koodin luominen ilman riippuvuuksia

ohjelmistojen kehittäminen on hienoa, mutta … uskon, että voimme kaikki olla samaa mieltä siitä, että se voi olla hieman tunteiden vuoristorataa. Alussa kaikki on hyvin. Voit lisätä uusia ominaisuuksia yksi toisensa jälkeen asioissa päivää ellei tuntia. Olet vauhdissa!

Kelaa eteenpäin muutama kuukausi, ja kehitysnopeutesi laskee. Johtuuko se siitä, ettet työskentele yhtä ahkerasti kuin ennen? En oikeastaan. Kelataan eteenpäin vielä muutama kuukausi, niin kehitysnopeus laskee entisestään. Tämän projektin parissa työskentely ei ole enää hauskaa ja siitä on tullut tylsää.

se pahenee. Alat löytää useita bugeja sovelluksessasi. Usein yhden virheen ratkaiseminen luo kaksi uutta. Tässä vaiheessa voit aloittaa laulamisen:

99 pieniä vikoja koodissa.99 pientä ötökkää.Ottakaa yksi alas, paikatkaa se,

… 127 pientä vikaa koodissa.

miltä tuntuu työskennellä tämän projektin parissa nyt? Jos olet kuten minä, alat luultavasti menettää motivaatiosi. Sovelluksen kehittäminen on vain tuskaa, sillä jokaisella olemassa olevan koodin muutoksella voi olla arvaamattomia seurauksia.

tämä kokemus on yleinen ohjelmistomaailmassa ja voi selittää, miksi niin monet ohjelmoijat haluavat heittää lähdekoodinsa pois ja kirjoittaa kaiken uusiksi.

syitä, miksi ohjelmistokehitys hidastuu ajan myötä

joten mikä on tämän ongelman syy?

pääsyy on kompleksisuuden lisääntyminen. Kokemukseni mukaan suurin kokonaiskompleksisuutta lisäävä tekijä on se, että suurimmassa osassa ohjelmistoprojekteja kaikki on yhteydessä toisiinsa. Koska riippuvuudet, että jokainen luokka on, jos muutat joitakin koodia luokassa, joka lähettää sähköposteja, käyttäjät yhtäkkiä voi rekisteröityä. Miksi? Koska rekisteröintikoodisi riippuu koodista, joka lähettää sähköposteja. Nyt et voi muuttaa mitään tuomatta vikoja. Ei ole mahdollista jäljittää kaikkia riippuvuuksia.

joten siinä se on; ongelmiemme todellinen syy on monimutkaisuuden lisääminen, joka tulee kaikista riippuvuuksista, joita koodillamme on.

Iso Mutapallo ja miten sitä voi vähentää

hauska juttu on, että tämä asia on ollut tiedossa jo vuosia. Se on yleinen vastakuvio, jota kutsutaan “isoksi mutapalloksi”.”Olen nähnyt tämän tyyppistä arkkitehtuuria lähes kaikissa projekteissa, joita olen työstänyt vuosien varrella useissa eri yrityksissä.

joten mikä tämä anti-kuvio oikein on? Yksinkertaisesti sanottuna, saat iso pallo mutaa, kun jokainen elementti on riippuvainen muista elementeistä. Alla näet graafin tunnetun avoimen lähdekoodin projektin Apache Hadoop riippuvuuksista. Suuren mutapallon (tai paremminkin suuren lankapallon) visualisoimiseksi piirretään ympyrä ja asetetaan luokat projektista tasaisesti sille. Piirrä vain viiva kunkin parin luokkiin, jotka riippuvat toisistaan. Nyt voit nähdä, mistä ongelmasi johtuvat.

visualisointi Apache Hadoopin suuresta mutapallosta, jossa on muutamia kymmeniä solmuja ja satoja viivoja, jotka yhdistävät ne toisiinsa.

Apache Hadoopin “big ball of mud”

ratkaisu modulaarisella koodilla

joten kysyin itseltäni kysymyksen: olisiko mahdollista vähentää monimutkaisuutta ja silti pitää hauskaa kuten projektin alussa? Totta puhuen kaikkea monimutkaisuutta ei voi poistaa. Jos haluat lisätä uusia ominaisuuksia, sinun on aina nostettava koodin monimutkaisuutta. Kompleksisuutta voi kuitenkin siirtää ja erottaa toisistaan.

miten muut toimialat ratkaisevat tämän ongelman

ajattelevat mekaanisesta teollisuudesta. Kun jokin pieni konepaja tekee koneita, he ostavat joukon vakioelementtejä, luovat muutaman mukautetun ja kokoavat ne yhteen. He voivat tehdä nämä komponentit täysin erikseen ja koota kaiken lopussa, tehden vain muutaman hienosäädön. Miten tämä on mahdollista? He tietävät, miten kukin elementti sopii yhteen asettaa alan standardeja, kuten pultit koot, ja edessä päätöksiä, kuten koko asennusreikien ja etäisyys niiden välillä.

tekninen kaavio fyysisestä mekanismista ja siitä, miten sen osat sopivat yhteen. Kappaleet on numeroitu järjestyksessä, joka liitetään seuraavaksi, mutta että järjestyksessä vasemmalta oikealle menee 5, 3, 4, 1, 2.

jokaisen edellä olevan kokoonpanon elementin voi toimittaa erillinen yritys, jolla ei ole minkäänlaista tietoa lopputuotteesta tai sen muista kappaleista. Niin kauan kuin jokainen modulaarinen elementti on valmistettu spesifikaatioiden mukaan, voit luoda lopullisen laitteen suunnitellusti.

Voimmeko toistaa sen ohjelmistoteollisuudessa?

toki voimme! Käyttämällä rajapintoja ja käänteisohjaus periaate; parasta on se, että tätä lähestymistapaa voidaan käyttää missä tahansa olio-orientoitunut kieli: Java, C#, Swift, TypeScript, JavaScript, PHP—lista jatkuu ja jatkuu. Et tarvitse mitään fancy puitteet soveltaa tätä menetelmää. Sinun tarvitsee vain pitää kiinni muutamasta yksinkertaisesta säännöstä ja pysyä kurinalaisena.

inversio kontrollista on ystäväsi

kun kuulin ensi kertaa kontrollin inversiosta, tajusin heti löytäneeni ratkaisun. Se on käsite ottaa olemassa riippuvuudet ja kääntää ne rajapintojen avulla. Rajapinnat ovat yksinkertaisia menetelmiä koskevia ilmoituksia. Ne eivät tarjoa mitään konkreettista toteutusta. Tämän seurauksena niitä voidaan käyttää kahden elementin välisenä sopimuksena siitä, miten ne liitetään toisiinsa. Niitä voidaan käyttää modulaarinen liittimet, jos haluat. Niin kauan kuin yksi elementti tarjoaa käyttöliittymän ja toinen elementti tarjoaa sen toteuttamisen, ne voivat työskennellä yhdessä tietämättä mitään toisistaan. Se on nerokas.

katsotaanpa yksinkertaisessa esimerkissä, miten voimme irrottaa järjestelmämme modulaarisen koodin luomiseksi. Alla olevat kaaviot on toteutettu yksinkertaisina Java-sovelluksina. Löydät ne tästä GitHub-arkistosta.

ongelma

oletetaan, että meillä on hyvin yksinkertainen sovellus, joka koostuu vain Main luokasta, kolmesta palvelusta ja yhdestä Util luokasta. Nämä elementit riippuvat toisistaan monin tavoin. Alla näet toteutuksen, jossa käytetään” big ball of mud ” – lähestymistapaa. Luokat vain soittelevat toisilleen. Ne ovat tiiviisti kytkettyinä toisiinsa,eikä yhtä elementtiä voi vain poistaa koskematta muihin. Tällä tyylillä luotujen sovellusten avulla voit aluksi kasvaa nopeasti. Uskon, että tämä tyyli sopii proof-of-concept-projekteihin, sillä asioiden kanssa voi leikkiä helposti. Se ei kuitenkaan sovi tuotantovalmiisiin ratkaisuihin, koska huoltokin voi olla vaarallista ja mikä tahansa yksittäinen muutos voi aiheuttaa arvaamattomia vikoja. Alla olevassa kaaviossa näkyy tämä iso muta-arkkitehtuuria edustava pallo.

Main käyttää Palveluita A, B ja C, joita kukin käyttää Util. Palvelu C käyttää myös palvelua A.

miksi dependence Injection sai kaiken väärin

etsiessään parempaa lähestymistapaa, Voimme käyttää tekniikkaa nimeltä dependence injection. Tässä menetelmässä oletetaan, että kaikkia komponentteja käytetään rajapintojen kautta. Olen lukenut väitteitä, että se erottaa elementit toisistaan, mutta onko se todella? Ei. Katso alla oleva kaavio.

edellinen arkkitehtuuri, mutta riippuvuus injektio. Nyt Main käyttää Käyttöliittymäpalveluja A, B ja C, joita vastaavat palvelut toteuttavat. Palvelut A ja C käyttävät sekä Rajapintapalvelua B että Rajapintapalvelua Util, jonka toteuttaa Util. Palvelu C käyttää myös Rajapintapalvelua A. jokaista palvelua yhdessä rajapintansa kanssa pidetään elementtinä.

ainoa ero nykytilanteen ja Ison mutapallon välillä on se, että nyt ei soiteta luokkiin suoraan, vaan soitetaan niiden liittymien kautta. Se parantaa hieman elementtien erottamista toisistaan. Jos esimerkiksi haluat käyttää Service A uudelleen toisessa projektissa, voit tehdä sen ottamalla Service A itse, yhdessä Interface A: n kanssa sekä Interface B ja Interface Util. Kuten näette, Service A riippuu edelleen muista elementeistä. Tämän seurauksena meillä on edelleen ongelmia muuttaa koodia yhdessä paikassa ja sotkea käyttäytymistä toisessa. Se luo edelleen ongelman, että jos muokkaat Service B ja Interface B, sinun täytyy muuttaa kaikkia siitä riippuvia elementtejä. Tämä lähestymistapa ei ratkaise mitään; mielestäni, se vain lisää kerroksen käyttöliittymän päälle elementtejä. Sinun ei pitäisi koskaan pistää mitään riippuvuuksia, vaan sinun pitäisi päästä eroon niistä lopullisesti. Eläköön itsenäisyys!

ratkaisu modulaariselle koodille

lähestymistapa, jonka uskon ratkaisevan kaikki riippuvuuksien päänvaivat, tekee sen siten, että riippuvuuksia ei käytetä lainkaan. Luot komponentin ja sen kuuntelijan. Kuuntelija on yksinkertainen käyttöliittymä. Aina kun sinun täytyy soittaa menetelmä ulkopuolelta nykyisen elementin, voit yksinkertaisesti lisätä menetelmä kuuntelija ja soittaa sen sijaan. Elementti saa käyttää vain tiedostoja, kutsumenetelmiä paketissaan ja käyttää pääkehyksen tai muiden käytettyjen kirjastojen tarjoamia luokkia. Alla näet kaavion sovelluksesta, joka on muokattu käyttämään element-arkkitehtuuria.

sovelluksen kaavio, joka on muokattu käyttämään elementtiarkkitehtuuria. Main käyttää Util-palvelua ja kaikkia kolmea palvelua. Main myös toteuttaa jokaiselle palvelulle kuuntelijan, jota kyseinen palvelu käyttää. Kuulija ja palvelu yhdessä koetaan elementiksi.

huomaa, että tässä arkkitehtuurissa vain Main – luokalla on useita riippuvuuksia. Se johdattaa kaikki elementit yhteen ja kiteyttää sovelluksen liiketoimintalogiikan.

palvelut sen sijaan ovat täysin itsenäisiä elementtejä. Nyt, voit ottaa jokaisen palvelun pois tästä sovelluksesta ja uudelleenkäyttää ne jossain muualla. He eivät ole riippuvaisia mistään muusta. Mutta odota, se paranee: sinun ei tarvitse muokata näitä palveluja enää koskaan, kunhan et muuta niiden käyttäytymistä. Niin kauan kuin nämä palvelut tekevät, mitä niiden pitäisi tehdä, ne voidaan jättää koskemattomiksi aikojen loppuun asti. Ne voi luoda ammattimainen ohjelmistoinsinööri, tai ensikertalainen koodari tinkiä huonoimmasta spagettikoodista, jota kukaan on koskaan keittänyt goto lauseet sekoitettuna. Sillä ei ole väliä, koska heidän logiikkansa on kapseloitu. Niin kamalaa kuin se onkin, se ei koskaan leviä muille luokille. Tämä antaa sinulle myös vallan jakaa työtä projektissa useiden kehittäjien kesken, jossa jokainen kehittäjä voi työskennellä omalla komponentillaan itsenäisesti ilman tarvetta keskeyttää toista tai edes tietää muiden kehittäjien olemassaolosta.

lopuksi voit aloittaa independant-koodin kirjoittamisen vielä kerran, aivan kuten edellisen projektisi alussa.

Elementtikuvio

määritellään rakenteellinen elementtikuvio niin, että pystymme luomaan sen toistettavalla tavalla.

alkuaineen yksinkertaisin versio koostuu kahdesta asiasta: Pääelementtiluokka ja kuuntelija. Jos haluat käyttää elementtiä, sinun täytyy toteuttaa kuuntelija ja soittaa puheluita pääluokalle. Tässä on kaavio yksinkertaisin kokoonpano:

kaavio yhdestä elementistä ja sen kuuntelijasta sovelluksessa. Kuten aiemminkin, sovellus käyttää kuuntelijaansa käyttävää elementtiä, jonka sovellus toteuttaa.

ilmeisesti, sinun täytyy lisätä monimutkaisuutta osaksi Elementti lopulta, mutta voit tehdä niin helposti. Varmista vain, että mikään logiikkaluokistasi ei riipu projektin muista tiedostoista. Ne voivat käyttää vain pääkehystä, tuotuja kirjastoja ja muita tiedostoja tässä elementissä. Kun se tulee omaisuuden tiedostoja, kuten kuvia, näkymät, äänet, jne. ne olisi myös kapseloitava elementteihin, jotta niitä olisi tulevaisuudessa helppo käyttää uudelleen. Voit kopioida koko kansion toiseen projektiin ja siinä se on!

alla on esimerkkikaavio, jossa näkyy kehittyneempi Elementti. Huomaa, että se koostuu näkymästä, jota se käyttää, eikä se riipu muista sovellustiedostoista. Jos haluat tietää yksinkertainen tapa tarkistaa riippuvuudet, vain katsoa tuonti osio. Onko tiedostoja nykyisen elementin ulkopuolelta? Jos näin on, sinun täytyy poistaa nämä riippuvuudet joko siirtämällä ne elementtiin tai lisäämällä sopiva puhelu kuulijalle.

yksinkertainen kaavio monimutkaisemmasta elementistä. Tässä sanan "Elementti" laajempi merkitys koostuu kuudesta osasta: näkymä; logiikat A, B ja C; Elementti; ja elementti kuuntelija. Kahden jälkimmäisen ja sovelluksen väliset suhteet ovat samat kuin ennenkin, mutta sisempi Elementti käyttää myös logiikkaa A ja C. logiikka C käyttää logiikkaa A ja B. logiikka a käyttää logiikkaa B ja näkymää.

Katsotaanpa myös tarkastella yksinkertainen “Hello World” esimerkki luotu Java.

public class Main { interface ElementListener { void printOutput(String message); } static class Element { private ElementListener listener; public Element(ElementListener listener) { this.listener = listener; } public void sayHello() { String message = "Hello World of Elements!"; this.listener.printOutput(message); } } static class App { public App() { } public void start() { // Build listener ElementListener elementListener = message -> System.out.println(message); // Assemble element Element element = new Element(elementListener); element.sayHello(); } } public static void main(String args) { App app = new App(); app.start(); }}

aluksi määrittelemme ElementListener, millä menetelmällä tuloste tulostetaan. Itse alkuaine on määritelty alla. Kutsuessaan sayHello elementtiin se yksinkertaisesti tulostaa viestin käyttäen ElementListener. Huomaa, että elementti on täysin riippumaton printOutput – menetelmän toteuttamisesta. Se voidaan tulostaa konsoliin, fyysiseen tulostimeen tai hienoon käyttöliittymään. Elementti ei riipu siitä toteutuksesta. Koska tämä abstraktio, tämä elementti voidaan käyttää uudelleen eri sovelluksissa helposti.

Katso nyt pääluokka App. Se toteuttaa kuulijan ja kokoaa elementin yhteen konkreettisen toteutuksen kanssa. Nyt voimme alkaa käyttää sitä.

voit ajaa tämän esimerkin Javascriptissä myös täältä

Elementtiarkkitehtuuri

katsotaanpa elementtikuvion käyttöä laajamittaisissa sovelluksissa. On eri asia näyttää se pienessä projektissa kuin soveltaa sitä todelliseen maailmaan.

tykkäämäni full-stack web-sovelluksen rakenne näyttää seuraavanlaiselta:

src├── client│ ├── app│ └── elements│ └── server ├── app └── elements

lähdekoodikansiossa aluksi jaoimme asiakas-ja palvelintiedostot. Se on järkevää, sillä ne toimivat kahdessa eri ympäristössä: selaimessa ja taustapalvelimessa.

sen jälkeen jaetaan kunkin kerroksen koodi kansioihin, joita kutsutaan app: ksi ja elementeiksi. Elementit koostuu kansioista, joissa on itsenäisiä komponentteja, kun taas sovellus kansio johdot kaikki elementit yhdessä ja tallentaa kaikki liiketoiminnan logiikka.

näin elementtejä voidaan käyttää uudelleen eri projektien välillä, kun taas kaikki sovelluskohtainen monimutkaisuus on kapseloitu yhteen kansioon ja melko usein pelkistetty yksinkertaisiin elementtikutsuihin.

käytännön esimerkki

uskoen, että käytäntö aina trump-teoriaa, katsotaanpa Node-kirjassa luotua tosielämän esimerkkiä.js ja konekirjoitus.

tosielämän esimerkki

se on hyvin yksinkertainen verkkosovellus, jota voidaan käyttää lähtökohtana kehittyneemmille ratkaisuille. Se noudattaa elementtiarkkitehtuuria sekä käyttää laajasti rakenteellista elementtikuviota.

kohokohdista näkee, että pääsivu on eroteltu elementiksi. Tämä sivu sisältää oman näkymän. Joten kun esimerkiksi haluat käyttää sitä uudelleen, voit kopioida koko kansion ja pudottaa sen toiseen projektiin. Yhdistä vain kaikki ja olet valmis.

se on perusesimerkki, joka osoittaa, että omaan sovellukseen voi alkaa tuoda elementtejä jo tänään. Voit alkaa erottaa riippumattomia komponentteja ja erottaa niiden logiikka. Sillä ei ole väliä, kuinka sotkuinen koodi, jota parhaillaan työstät, on.

Kehitä Nopeammin, Uusiudu Useammin!

toivon, että tämän uuden työkalusarjan avulla voit helpommin kehittää koodia, joka on paremmin ylläpidettävissä. Ennen kuin hyppäät käyttämään elementtikuviota käytännössä, kerrataan nopeasti kaikki pääkohdat:

  • paljon ongelmia ohjelmisto tapahtuu, koska riippuvuudet useiden komponenttien välillä.

  • tekemällä muutoksen yhdessä paikassa, voit esitellä arvaamatonta käyttäytymistä jossain muualla.

kolme yhteistä arkkitehtuurista lähestymistapaa ovat:

  • iso mutapallo. Se on hyvä nopeaan kehitykseen, mutta ei niin suuri vakaaseen tuotantoon.

  • Riippuvuusruiske. Se on puolivillainen ratkaisu, jota kannattaa välttää.

  • Elementtiarkkitehtuuri. Tämän ratkaisun avulla voit luoda itsenäisiä komponentteja ja käyttää niitä uudelleen muissa projekteissa. Se on ylläpidettävissä ja loistava vakaaseen tuotantoon.

peruselementtikuvio koostuu pääluokasta, jossa on kaikki tärkeimmät menetelmät, sekä kuuntelijasta, joka on yksinkertainen käyttöliittymä, joka mahdollistaa kommunikaation ulkoisen maailman kanssa.

täyden pinon elementtiarkkitehtuurin saavuttamiseksi erotetaan ensin etupää taustakoodista. Sitten luot kansion jokaiseen sovellukseen ja elementteihin. Elements-kansio koostuu kaikista itsenäisistä elementeistä, kun taas app-kansio johdot kaiken yhteen.

nyt voi lähteä luomaan ja jakamaan omia elementtejä. Pitkällä aikavälillä se auttaa luomaan helposti ylläpidettäviä tuotteita. Onnea ja kerro, mitä loit!

myös, jos huomaat optimoivasi koodin ennenaikaisesti, Lue toptaler Kevin Blochin kirjoittama How to Avoid the Curse of Premature Optimization.

Vastaa

Sähköpostiosoitettasi ei julkaista.