Ohjelmistokehitys on hienoa, mutta… luulen, että voimme kaikki olla yhtä mieltä siitä, että se voi olla emotionaalinen vuoristorata. Alussa kaikki on hienoa. Lisää uusia ominaisuuksia yksi toisensa jälkeen muutamassa päivässä, ellei tunnissa. Olet onnekas juovassa!
Nopeasti eteenpäin muutama kuukausi, ja kehitysnopeutesi hidastuu. Johtuuko se siitä, ettet työskentele yhtä kovasti kuin ennen? Ei oikeastaan. Nopea eteenpäin muutama kuukausi, ja kehitystasi hidastuu entisestään. Tämän projektin parissa työskenteleminen ei ole enää hauskaa, ja siitä on tullut vetovoima.
Mutta se pahenee. Alat löytää useita virheitä sovelluksessasi. Usein yhden virheen ratkaiseminen luo kaksi uutta. Tässä vaiheessa voit aloittaa laulamisen:
99 pientä vikaa koodissa. 99 pientä virhettä. Ota yksi, laita siihen laastari,
… 127 pientä virhettä koodissa.
Mitä mieltä olet työskennellä tämän projektin parissa nyt? Jos olet kuin minä, alat todennäköisesti menettää motivaatiotasi. Tämän sovelluksen kehittäminen on monimutkaista, koska jokaisella olemassa olevan koodin muutoksella voi olla arvaamattomia seurauksia.
Tämä kokemus on yleistä ohjelmistomaailmassa ja saattaa selittää, miksi niin monet ohjelmoijat haluavat jättää lähdekoodinsa ja kirjoittaa kaiken uudelleen.
Joten mikä on tämän ongelman syy?
Tärkein syy on monimutkaisuus. Kokemukseni mukaan suurin monimutkaisuuden tekijä on se, että suurin osa ohjelmistoprojekteista kaikki on yhteydessä toisiinsa. Kullakin luokalla olevien riippuvuuksien takia, jos muutat mitään luokan koodia, joka lähettää sähköposteja, käyttäjät eivät voi yhtäkkiä rekisteröityä. Miksi niin? Koska rekisteröintikoodisi riippuu koodista, joka lähettää sähköpostit. Nyt et voi muuttaa mitään tekemättä virheitä. Kaikkia riippuvuuksia ei yksinkertaisesti voida jäljittää.
Joten sinulla on se; ongelmiemme todellinen syy on lisätä koodissamme olevien riippuvuuksien monimutkaisuutta.
Hauska on, että tämä ongelma on ollut tiedossa jo vuosia. Se on yleinen antipattern, jota kutsutaan 'suureksi savipalloksi'. Olen nähnyt tällaisen arkkitehtuurin melkein jokaisessa projektissa, jonka parissa olen työskennellyt vuosien varrella useissa eri yrityksissä.
Joten mikä tämä antipattern tarkalleen on? Yksinkertaisesti ottaen saat suuren savipallon, kun jokainen esine on riippuvainen muista esineistä. Alla näet kaavion suositun avoimen lähdekoodin Apache Hadoop -projektin riippuvuuksista. Voit visualisoida suuren savipallon (tai pikemminkin suuren lankapallon) piirtämällä ympyrän ja sijoittamalla projektiluokat tasaisesti siihen. Piirrä vain viiva jokaisen toisistaan riippuvan luokkaparin välille. Nyt näet ongelmiesi lähteen.
Joten kysyin itseltäni kysymyksen: olisiko mahdollista vähentää monimutkaisuutta ja pitää silti hauskaa kuin projektin alussa? Totta puhuen, et voi poistaa kaikki monimutkaisuus. Jos haluat lisätä uusia ominaisuuksia, sinun on aina lisättävä koodisi monimutkaisuutta. Monimutkaisuus voi kuitenkin liikkua ja levitä.
Ajattele mekaanista teollisuutta. Kun pieni konepaja luo koneita, se ostaa joukon vakiotuotteita, luo muutaman mukautetun tuotteen ja yhdistää ne. He voivat tehdä nuo komponentit täysin erikseen ja koota kaiken viimeiseksi tekemällä vain muutaman korjauksen. Kuinka tämä on mahdollista? He tietävät, miten kukin tuote sopii alan standardien, kuten pultin koon, ja alustavien päätösten, kuten asennusreikien koon ja niiden välisen etäisyyden perusteella.
Jokainen yllä olevan sarjan tuote voidaan toimittaa riippumaton yritys, jolla ei ole tietoa lopputuotteesta tai sen muista osista. Niin kauan kuin kukin moduuliosa on valmistettu määrittelyjen mukaisesti, voit luoda lopullisen laitteen suunnitellusti.
Voimmeko toistaa sen ohjelmistoteollisuudessa?
Me voimme varmasti! Käyttämällä rajapintoja ja kääntämällä ohjausperiaatetta; Parasta on se, että tätä lähestymistapaa voidaan käyttää millä tahansa olio-kielellä: Java, C #, Swift, TypeScript, JavaScript, PHP - luetteloa voidaan jatkaa. Sinun ei tarvitse mitään hienoa kehystä tämän menetelmän soveltamiseksi. Sinun tarvitsee vain noudattaa muutamia yksinkertaisia sääntöjä ja pysyä kurinalaisena.
Kun kuulin ensimmäisen kerran hallinnan kääntämisestä, tajusin heti, että olin löytänyt ratkaisun. Se on käsite nykyisten riippuvuuksien ottamisesta ja niiden kääntämisestä käyttöliittymien avulla. Liitännät ovat yksinkertaisia menetelmäilmoituksia. Ne eivät tarjoa mitään konkreettista toteutusta. Tämän seurauksena niitä voidaan käyttää kahden elementin välisenä sopimuksena niiden yhdistämisestä. Niitä voidaan haluttaessa käyttää moduuliliittiminä. Niin kauan kuin yksi elementti tarjoaa käyttöliittymän ja toinen elementti toteuttaa, he voivat työskennellä yhdessä tietämättä mitään toisistaan. Se on loistava.
Katsotaanpa yksinkertaisessa esimerkissä, kuinka voimme erottaa järjestelmämme modulaarisen koodin luomiseksi. Seuraavat kaaviot on toteutettu yksinkertaisina Java-sovelluksina. Löydät ne täältä GitHub-arkisto .
Oletetaan, että meillä on hyvin yksinkertainen sovellus, joka koostuu vain yhdestä luokasta Main
, kolmesta palvelusta ja yhdestä luokasta Util
Nämä elementit riippuvat toisistaan monin tavoin. Alla näet toteutuksen, jossa käytetään 'ison muta pallon' lähestymistapaa. Luokat vain kutsuvat toisiaan. Ne liittyvät läheisesti toisiinsa, et voi vain vetää yhtä tuotetta koskematta muihin. Tässä tyylissä luotujen sovellusten avulla voit aluksi kasvaa nopeasti. Mielestäni tämä tyyli soveltuu todistushankkeisiin, koska voit pelata helposti. Se ei kuitenkaan sovellu tuotantovalmiisiin ratkaisuihin, koska jopa huolto voi olla vaarallista ja kaikki muutokset voivat aiheuttaa arvaamattomia virheitä. Alla oleva kaavio näyttää tämän suuren saviarkkitehtuurin pallon.
Paremman lähestymistavan etsimiseksi voimme käyttää tekniikkaa, jota kutsutaan riippuvuusinjektioksi. Tässä menetelmässä oletetaan, että kaikkia komponentteja on käytettävä rajapintojen yli. Olen lukenut väitteitä siitä, että se purkaa esineitä, mutta onko se todella? Ei. Katso alla olevaa kaaviota.
Ainoa ero tämänhetkisen tilanteen ja suuren mutapallon välillä on se, että nyt sen sijaan, että soittaisimme luokkiin suoraan, soitamme heille niiden rajapintojen kautta. Parantaa hieman erotuselementtejä toisistaan. Jos esimerkiksi haluat käyttää Servicio A
Toisessa projektissa voit tehdä tämän ottamalla Servicio A
, Interfaz A
sekä Interfaz B
ja Interface Útil
. Kuten näette, Servicio A
se riippuu edelleen muista tekijöistä. Tämän seurauksena meillä on edelleen vaikeuksia muuttaa koodia yhdessä paikassa ja sekoittaa käyttäytymistä toisessa. Se aiheuttaa edelleen ongelman, että jos muokkaat Servicio B
e Interfaz B
, sinun on vaihdettava kaikki siitä riippuvat elementit. Tämä lähestymistapa ei ratkaise mitään; mielestäni se vain lisää käyttöliittymäkerroksen elementtien päälle. Sinun ei pitäisi koskaan pistää riippuvuuksia, vaan pikemminkin päästä eroon niistä lopullisesti. Hurraa itsenäisyydelle!
Lähestymistapa, joka mielestäni ratkaisee kaikki suurimmat riippuvuuspäänsäryt, tekee niin olemalla käyttämättä riippuvuuksia lainkaan. Luot komponentin ja sen kuuntelijan. Kuuntelija on yksinkertainen käyttöliittymä. Aina kun haluat kutsua menetelmää nykyisen elementin ulkopuolelta, lisää vain menetelmä kuuntelijaan ja kutsu se sen sijaan. Elementti saa käyttää vain tiedostoja, kutsumenetelmiä paketissaan ja käyttää pääkehyksen tai muiden käytettyjen kirjastojen tarjoamia luokkia. Alla on kaavio sovelluksesta, joka on muokattu käyttämään elementtiarkkitehtuuria.
Huomaa, että tässä arkkitehtuurissa vain luokka Main
sillä on useita riippuvuuksia. Yhdistä kaikki elementit ja kapseloi sovelluksen liiketoimintalogiikka.
Palvelut puolestaan ovat täysin itsenäisiä elementtejä. Nyt voit ottaa jokaisen palvelun pois tästä sovelluksesta ja käyttää sitä uudelleen muualla. Ne eivät ole riippuvaisia mistään muusta. Mutta odota, se paranee: sinun ei tarvitse enää muokata näitä palveluja, kunhan et muuta niiden käyttäytymistä. Niin kauan kuin nuo palvelut tekevät mitä heidän on tarkoitus tehdä, ne voidaan jättää ennalleen ajan loppuun saakka. Ne voidaan luoda a ammatillinen ohjelmistoinsinööri , tai ensimmäistä kertaa kooderi, joka on sitoutunut pahimpaan spagettikoodiin, jota kukaan on koskaan valmistanut goto
sekoitettu. Sillä ei ole merkitystä, koska logiikkasi on koteloitu. Niin kauheaa kuin se onkin, se ei koskaan levitä muihin luokkiin. Tämä antaa sinulle myös voiman jakaa projektin työ useiden kehittäjien kesken, jolloin kukin kehittäjä voi työskennellä oman komponenttinsa suhteen itsenäisesti tarvitsematta keskeyttää toista tai edes tietää muita kehittäjiä.
Lopuksi voit aloittaa itsenäisen koodin kirjoittamisen vielä kerran, aivan kuten edellisen projektin alussa.
Määritetään rakenteellisen elementin kuvio, jotta voimme luoda sen toistettavasti.
Elementin yksinkertaisin versio koostuu kahdesta asiasta: pääelementtiluokasta ja kuuntelijasta. Jos haluat käyttää elementtiä, sinun on toteutettava kuuntelija ja soitettava pääluokalle. Tässä on kaavio yksinkertaisimmasta kokoonpanosta:
On selvää, että sinun on lisättävä elementtiin vielä enemmän monimutkaisuutta, mutta voit tehdä sen helposti. Varmista vain, että mikään logiikkaluokkaasi ei ole riippuvainen muista projektin tiedostoista. He voivat käyttää vain tämän elementin pääkehystä, tuotuja kirjastoja ja muita tiedostoja. Kun on kyse omaisuustiedostoista, kuten kuvista, nähtävyyksistä, äänistä jne., Ne on myös koteloitava elementteihin, jotta niitä on helppo käyttää uudelleen tulevaisuudessa. Voit kopioida koko kansion toiseen projektiin ja siinä se on!
Alla on esimerkkikaavio, joka näyttää edistyneemmän kohteen. Huomaa, että se koostuu käyttämästäsi näkymästä eikä ole riippuvainen muista sovellustiedostoista. Jos haluat tietää yksinkertaisen menetelmän riippuvuuksien tarkistamiseksi, katso vain tuonti-osiota. Onko nykyisen kohteen ulkopuolella tiedostoja? Jos näin on, poista nuo riippuvuudet siirtämällä ne elementtiin tai lisäämällä sopiva kutsu kuuntelijalle.
Katsotaanpa yksinkertainen esimerkki 'Hello World' 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ääritämme ElementListener
määrittää menetelmän, joka tulostaa tuloksen. Itse elementti on määritelty alla. Soittaminen sayHello
tulosta viesti elementille ElementListener
. Huomaa, että elementti on täysin riippumaton printOutput
-menetelmän toteutuksesta. Se voidaan tulostaa konsolille, fyysiselle tulostimelle tai hienolle käyttöliittymälle. Elementti ei riipu toteutuksesta. Tämän abstraktion ansiosta tämä elementti voidaan helposti käyttää uudelleen eri sovelluksissa.
Katsokaa nyt App
: n pääluokkaa. Toteuta kuuntelija ja koota elementti yhdessä konkreettisen toteutuksen kanssa. Nyt voimme alkaa käyttää sitä.
Voit käyttää tätä esimerkkiä myös JavaScriptissä täällä
Katsotaanpa elementtikuvion käyttöä suurissa sovelluksissa. On yksi asia osoittaa se esiin pienessä projektissa; toinen on soveltaa sitä todelliseen maailmaan.
Haluan käyttää täyden pinon verkkosovelluksen rakenne näyttää tältä:
src ├── client │ ├── app │ └── elements │ └── server ├── app └── elements
Lähdekoodikansiossa jaoimme aluksi asiakas- ja palvelintiedostot. Se on järkevä tehtävä, koska ne toimivat kahdessa eri ympäristössä: selaimessa ja taustapalvelimessa.
Sitten jaamme koodin jokaisessa kerroksessa kansioihin, joita kutsutaan sovelluksiksi ja kohteiksi. Kohteet koostuvat kansioista, joissa on erilliset komponentit, kun taas sovelluskansio yhdistää kaikki kohteet ja tallentaa kaikki liiketoimintalogiikat.
Tällä tavoin kohteita voidaan käyttää uudelleen eri projektien välillä, kun taas kaikki sovelluskohtaiset monimutkaisuudet on koteloitu yhteen kansioon ja usein vain yksinkertaisiin nimipuheluihin.
Jos uskomme, että käytäntö on aina etusijalla teoriaan, katsotaanpa tosielämän esimerkkiä, joka on luotu Node.js: ssä ja TypeScriptissä.
Se on hyvin yksinkertainen verkkosovellus, jota voidaan käyttää lähtökohtana edistyneemmille ratkaisuille. Se seuraa elementtiarkkitehtuuria ja käyttää laajasti rakenteellista elementtikuviota.
Kohokohdista näet, että pääsivu on eroteltu kohteena. Tämä sivu sisältää oman näkymän. Joten kun haluat esimerkiksi käyttää sitä uudelleen, voit kopioida koko kansion ja pudottaa sen toiseen projektiin. Liitä vain kaikki ja olet hyvä mennä.
Se on perusesimerkki, joka osoittaa, että voit aloittaa tuotteiden tuomisen omaan sovellukseesi jo tänään. Voit alkaa erottaa toisistaan riippumattomat komponentit ja erottaa niiden logiikan. Ei ole väliä kuinka sotkuinen koodi olet tällä hetkellä.
Toivon, että tämän uuden työkalusarjan avulla voit kehittää helpommin ylläpidettävää koodia. Ennen kuin ryhdymme käyttämään elementtikuviota käytännössä, käymme nopeasti läpi kaikki pääkohdat:
Ohjelmistoissa esiintyy monia ongelmia eri komponenttien välisten riippuvuuksien vuoksi.
Kun teet muutoksen yhdessä paikassa, voit ottaa käyttöön arvaamattoman käyttäytymisen toisessa paikassa.
Kolme yleistä arkkitehtonista lähestymistapaa ovat:
Suuri savipallo. Se on hieno nopeaan kehitykseen, mutta ei niin suuri vakaisiin tuotantotarkoituksiin.
Riippuvuuden injektio. Se on puoli ratkaisua, jota sinun tulisi välttää.
Elementtiarkkitehtuuri. Tämän ratkaisun avulla voit luoda itsenäisiä komponentteja ja käyttää niitä uudelleen muissa projekteissa. Se on ylläpidettävä ja loistava vakaan tuotannon vapauttamiseksi.
Peruselementtikuvio koostuu pääluokasta, jolla on kaikki päämenetelmät, sekä kuuntelijasta, joka on yksinkertainen käyttöliittymä, joka mahdollistaa yhteydenpidon ulkomaailman kanssa.
Täyden pinoelementtiarkkitehtuurin saavuttamiseksi käyttöliittymä erotetaan ensin taustakoodista. Luo sitten kussakin kansio sovellukselle ja kohteille. Kohteet-kansio koostuu kaikista erillisistä kohteista, kun taas sovelluskansio yhdistää kaiken yhteen.
Nyt voit siirtyä luomaan ja jakamaan omia kohteita. Pitkällä aikavälillä se auttaa luomaan helposti ylläpidettäviä tuotteita. Onnea ja kerro minulle, mitä olet luonut!
Lisäksi, jos huomaat optimoivasi koodia ennenaikaisesti, lue _ Kuinka välttää ennenaikaisen optimoinnin kirous ApeeScape-kumppaniltani Kevin Blochilta.