# Ohjelmistokehityksen menetelmät ja käytänteet

Opas on tarkoitettu ohjelmistokehityksessä tarvittavien menetelmien sekä käytänteiden kouluttamiseen. Tutustutaan eri työkalujen käyttöön, joita päivittäin ja viikottain tarvitaan. Opas on tehty opettamisen tueksi.

### Sisältö <a href="#sis-c3-a4lt-c3-b6" id="sis-c3-a4lt-c3-b6"></a>

[Tavoitteet](/tavoitteet)

**Versionhallinta**

Perusteet luvun tehtävät koostuvat useammasta tasosta. Tasot on yritetty kokoa loogiseen järjestykseen siten, että aina ennen seuraavaa tasoa olisi hyvä tehdä edellinen. Loppupäässä tehtävät ovat kuitenkin vapaampia ja enemmän tiedonhakuun liittyviä, koska joitakin asioita versionhallinnan käytöstä on vaikeampi opettaa suoraan. Erikoistilanteiden luominen opetusta varten on hankalaa ja sen sijaan pyritään tuomaan esille erilaisia tilanteita, joita työskentelyn aikana kohtaa. Monet ovat kuitenkin harvinaisia mutta varsinkin aluksi voi syntyä paljonkin erikoistilanteita mihin ei löydy suoraa vastausta tästä oppaasta.

[Opas Gitin perusteisiin](/versionhallinta/opas-gitin-perusteisiin)

[Sanasto (GIT)](/versionhallinta/sanasto)

[Git perusteet 101](/versionhallinta/git-perusteet-101)

[Git perusteet 102](/versionhallinta/git-perusteet-102)

[Git perusteet 103](/versionhallinta/git-perusteet-103)

[Git perusteet 104](/versionhallinta/git-perusteet-104)

[Git perusteet 105](/versionhallinta/git-perusteet-105)

[Git perusteet 106](/versionhallinta/git-perusteet-106)

[Git perusteet 107](/versionhallinta/git-harjoitus-107)

[Git perusteet 108](/versionhallinta/git-harjoitus-108)

[Git muu materiaali ja lähteitä](/versionhallinta/git-muu-materiaali-ja-laehteet)

**Yksikkötestaus**

Perusteissä käydään läpi yksikkötestauksen pääperiaatteet käytännössä. Tasot on suunniteltu siten, että alempi taso täydentää ylempää. Sisällöt auttavat tutustumaan aiheeseen ja opiskelijan tehtävä on itsenäisesti löytää näihin kysyttyihin asioihin vastaukset. Yksikkötestauksen harjoituksissa käytetään xUnit perheeseen kuuluvia yksikkötestauskirjastoja. Esimerkit ovat C# -ohjelmointikielellä tehtyjä mutta samat periaatteet toimivat ohjelmointikielestä riippumatta.

[Ohjelmistotestauksen periaatteet](/yksikkoetestaus/ohjelmistotestauksen-periaateet)

[NUnit perusteet 101](/yksikkoetestaus/nunit-perusteet-101)

[NUnit perusteet 102](/yksikkoetestaus/nunit-perusteet-102)

[NUnit perusteet 103](/yksikkoetestaus/nunit-perusteet-103)

[NUnit muu materiaali ja lähteitä](/yksikkoetestaus/nunit-muu-materiaali-ja-laehteitae)

**Test Driven Development (TDD)**

Testausvetoinen kehitys tai kuten se paremmin tunnetaan termillä Test Driven Development, on tärkeä osa-alue testien kirjoittamisessa. Aihe on hankalampi opettaa ja vaatii kokemuksen kerryttämistä. Esimerkeissä tullaan kuitenkin tarjoamaan mahdollisuus tämän aiheen oppimiseen mutta parhaiten taidon omaksumisesta voi varmistua, kun kokeneempi kehittäjä antaa siitä palautteen. Teoriassa helppo aihe mutta käytännössä haastava.

[TDD perusteet 101](/yksikkoetestaus/tdd-perusteet-101)

[TDD perusteet 102](/yksikkoetestaus/tdd-perusteet-102)

[TDD muu materiaali ja lähteitä](/yksikkoetestaus/tdd-muu-materiaali-ja-laehteitae)

**Ketterä ohjelmistokehitys (Agile development)**

Kirjassa ei ole varsinaisia tehtäviä ketterän ohjelmistokehityksen osalta. Lähteet toimivat vain aiheen esittelijänä. Tarkoitus on lisätä myöhemmin käytännön asioita miten kokonaisuus voi toimia ja minkälaisia hyötyjä menetelmien noudattamisesta on.

[Agile, Muu materiaali ja lähteitä](/ketterae-ohjelmistokehitys/agile-muu-materiaali-ja-laehteitae)

[Agile esimerkki, sykli ](/ketterae-ohjelmistokehitys/agile-esimerkki-sykli)(alunperin valmisteltu projektityöskentelyn harjoitusta varten)


# Tavoitteet

Oppaan tavoitteena on tukea opetusta ja sisältää pääosin erilaisia tehtäviä sisältöjen opetteluun. Vastauksia ei näihin tehtäviin ole vielä valitettavasti olemassa. Tehtävät voi suorittaa yleensä usealla eri tavalla, joten oikea vastaus ei ole tärkeintä vaan se, että työkalut ja niiden käyttötavat tulevat tutuksi.

**Opit seuraavista ohjelmistokehityksen osa-alueista**

* Versionhallinnan käyttö ohjelmoinnissa ja sen hyödyntämisestä. Käytössä Git.
* Yksikkötestaus. Käytössä NUnit kirjasto.
* Testivetoinen ohjelmistokehitys ja sen hyödyntäminen ohjelmoinnissa.
* Scrum -menetelmän perusteet.

Osa-alueita ei ei käydä läpi perinpohjin vaan opas keskittyy tutustutaan perusasioihin sekä syihin miksi näitä työkaluja ja menetelmiä tulisi hyödyntää.

Osa-alueiden oppimiseen kuuluu muutamia tehtäviä, joilla perusasiat opetellaan eri työkaluista ja menetelmistä..

Varsinainen päätarkoitus on hyödyntää näitä taitoja projektissa. Projektissa pyritään käyttämään taitoja kuten oikeassa työelämässä.

Osallistujat tullaan jakamaan pienempiin kehitystiimeihin, jotka toteuttavat parhaansa mukaan yhtä ominaisuutta. Yksi kehitystiimi on osa suurempaa kokonaisuutta, joten myös useampien kehitystiimien tulee tehdä yhteistyötä. Yhteiset tehtävät tarkentuvat projektin tehtävänannossa.

### Käytettävät ohjelmat <a href="#k-c3-a4ytett-c3-a4v-c3-a4t-ohjelmat" id="k-c3-a4ytett-c3-a4v-c3-a4t-ohjelmat"></a>

Asenna ja testaa seuraavien työkalujen toimivuus:

* Visual Studio 2019 (community riittää)
* Git -versionhallinta, lataa osoitteesta <https://git-scm.com/>

Ohjelmoimme C#-kielellä.


# Työkalut

## Visual Studio

Katso perusteet Visual Studio -kehitystyökalun käytöstä.

{% embed url="<https://www.youtube.com/playlist?list=PL3iay_FdAzV9HJV76tTfwWJLzgeysHTLd>" %}


# Projektityön rajaukset ja toimeksiannot

Toimeksiantoja projektityöhön.

Tämän sivun sisältö on tehty ohjelmistokehitykseen liittyvää moduulin suoritusta varten. Sisältöä saa käyttää vapaasti myös muissa tarkoituksissa. Tarvittaessa toteutuskertaan liittyviä rajauksia tai tarkennuksia on kirjoitettu opiskelijaryhmän omalle kurssialustalle.

## Tavoitteet <a href="#vaatimukset-toimeksiannon-ohjelmalle" id="vaatimukset-toimeksiannon-ohjelmalle"></a>

Projektin tavoitteena on toimia kehikkona ja syventää aiemmin opittuja taitoja. Projektityössä tullaan tarvitsemaan mm. versionhallinnan käyttöä sekä toimimista ketterän ohjelmistokehityksen mallien mukaisesti. Sisältöihin liittyy myös muita opetettuja asioita, jotka ovat esillä opiskelijaryhmien omalla kurssialustalla.

Projektityön lopputuloksen kannalta ei ole tärkeää lopputulos. Tärkeintä on pyrkiä toimimaan siten kuten on ohjeistettu ja oppia lisää sisällöistä. Tällä sivulla ei ole otettu esille arviointiperusteita. Arviointiperusteet on tarkennettu tarvittaessa opiskelijaryhmän kurssialustalla.

## Toimeksiannot <a href="#vaatimukset-toimeksiannon-ohjelmalle" id="vaatimukset-toimeksiannon-ohjelmalle"></a>

Projektityöhön valittavissa olevat toimeksiannot löytyvät alla olevilta sivuilta:

{% content-ref url="/pages/-Lz0UQlNUfvivDoIe8PG" %}
[Palkanlaskenta](/toimeksiannot-2020-01/palkanlaskenta)
{% endcontent-ref %}

{% content-ref url="/pages/-Lz0UsTzBOgiGR8Yk6-5" %}
[Kilometrikorvaus](/toimeksiannot-2020-01/kilometrikorvaus)
{% endcontent-ref %}

{% content-ref url="/pages/-Lz0dZcRN1a0oZIXPUnm" %}
[Laskutus](/toimeksiannot-2020-01/laskutus)
{% endcontent-ref %}

{% content-ref url="/pages/-MRUbPxnuNVW5FDbvxt2" %}
[Laskun perintä](/toimeksiannot-2020-01/laskun-perintae)
{% endcontent-ref %}

## Kehitystiimin työskentely <a href="#vaatimukset-toimeksiannon-ohjelmalle" id="vaatimukset-toimeksiannon-ohjelmalle"></a>

Projektityön aikana on tarkoitus kokeilla uusia toimintamalleja ohjelmistojen teossa. Näihin lukeutuvat eri ketterän ohjelmistokehityksen viitekehykset ja mallit. Esimerkiksi Scrum tai XP.&#x20;

Ohjelmaa toteuttaessa tulisi kokeilla toimia näiden mallien mukaisesti. Ensin on sovittava kehitystiimin kesken, että mitä mallia kokeilette soveltaa. Toimeksiannolla on aikarajaus eikä näin ollen ole mahdollista kaikkea tehdä tai noudattaa kirjaimellisesti. Tehdessä ei haittaa vaikka mallia ei kirjaimellisesti noudata. Siihen pyrkiminen on hyvä asia tai nostaa esille vain muutamia kohtia. Vinkkejä saa myös seuraavalta [Agile esimerkkiä käsittelevältä sivulta](/ketterae-ohjelmistokehitys/agile-esimerkki-sykli).

Kehitystiimin tulee myös käyttää ohjelman teossa versionhallintaa.

## Tekniset rajaukset toimeksiannon ohjelmalle

* Ohjelmointikielenä C#.
* Ohjelman toteutusmuoto on konsoli- tai WPF sovellus.
* Ohjelmoinnissa tulisi hyödyntää olio-ohjelmointiin liittyviä tapoja ja käsitteitä.
* Ohjelman tulee käynnistyä Visual Studio Community -kehitysympäristössä.

**Esimerkki konsolisovelluksen käyttöliittymästä**

![Esimerkki: Käyttäjän valinta](/files/-LnakB39ae-U1wSWx-hM)

![Esimerkki: Toimintojen valinta](/files/-LnakFfrH6gZtF0c1bRT)

![Esimerkki: Tuotelista](/files/-LnakIlx2YMv9Sl-ZKUB)

## Huomioita projektin etenemiseen

Toimeksiantojen lopputulos on avoin. Tämä on tietoinen päätös toimeksiantojen laatijalta. Tarkoitus ei ole rajata lopputulosta tarkkaan vaan mahdollistaa ryhmän itsenäiset päätökset.

Toimeksiantojen toiveet/ominaisuudet ovat tarkoituksella laajoja. Tarkoitus on, että kaikkea ei tule tehdä projektityöhön annetulla ajalla vaan ryhmä joutuu priorisoimaan tehtäviä asiakkaan näkökulmasta mietittynä. Muistakaa ottaa siis huomioon käytössänne oleva aika.

Projektin aikana ryhmä törmää varmasti tuntemattomiin asioihin mitä ei ole ennen käsitelty. Tällöin ohjaaja toivoo, että ryhmä löytäisi ratkaisutapoja itse miten se heidän nykisen taitotason perusteella onnistuisi. Projektin lopputuloksen kannalta tärkeämpää on nähdä ryhmän oppivan ohjelmoimaan pieni ohjelma annettujen määrityksien mukaan ja ratkaisemaan eteentulevia ongelmia.

Projektiryhmän kannattaa mieluummin tekemään asioita oikein ja hyvin. Vähemmän voi olla siis enemmän tässä tilanteessa.

## Palvelut ja ohjelmistot <a href="#tarvittavat-ohjelmistot" id="tarvittavat-ohjelmistot"></a>

{% embed url="<https://github.com/>" %}


# Palkanlaskenta

Harjoitustyöhön annettu toimeksianto

{% hint style="warning" %}
**Huom!** Opiskelijoille suunnatuissa projekteissa heidän arviointinsa ja palautettavat dokumentit on kuvattu tarkemmin heidän omalla oppimisalustallaan.
{% endhint %}

## Toimeksiannon kuvaus <a href="#vaatimukset-toimeksiannon-ohjelmalle" id="vaatimukset-toimeksiannon-ohjelmalle"></a>

Asiakas tarvitsee apua palkanlaskentaan. Hänelle on kerrottu, että palkat ja niiden sivukulut pystyisi laskemaan ohjelman avulla. Asiakkaalla vain ei ole tietoa ja taitoa siitä, että miten aloittaa.

Sinun tulisi suunnitella pieni sovellus, joka auttaisi asiakasta. Asiakkaalla on joitakin toiveita mitä hän haluaisi ohjelman sisältävän, jos se vain onnistuu.

* Palkattujen työntekijöiden listaus ja heidän nykyinen bruttopalkkansa.
* Palkattuja työntekijöitä saisi olla mahdollista lisätä tai heidän tietojaan muuttaa.
* Työntekijöiden kohdalla asiakas haluaisi nähdä mistä palkka koostuu. Esimerkkinä asiakas on antanut seuraavan linkin <https://www.palkka.fi/palkkalaskuri/nettolaskuri.htm>
* Asiakas joutuu myös maksamaan työnantajana sivukuluja palkasta. Jos siis mahdollista niin asiakkaan pitäisi myös nähdä työntekijän tiedoista, että paljonko erilaisia työnantaja maksuja tulisi maksaa <https://www.palkka.fi/palkkalaskuri/Index.htm>
* Asiakkaalla on myös toive, jos ohjelma voisi kertoa tulevat palkkapäivät ja niistä aiheutuvat palkka- ja sivukulut. Esimerkiksi seuraavalta 30 päivän ajalta.


# Kilometrikorvaus

Harjoitustyöhön annettu toimeksianto

{% hint style="warning" %}
**Huom!** Opiskelijoille suunnatuissa projekteissa heidän arviointinsa ja palautettavat dokumentit on kuvattu tarkemmin heidän omalla oppimisalustallaan.
{% endhint %}

## Toimeksiannon kuvaus <a href="#vaatimukset-toimeksiannon-ohjelmalle" id="vaatimukset-toimeksiannon-ohjelmalle"></a>

Asiakas tarvitsee apua kilometrikorvauksien kirjanpitoon ja maksamiseen. Asiakkaalla on useita myyntiedustajia, jotka kulkevat omalla autollaan. Pääasiassa asiakkaan tulee maksaa kirjattujen kilometrien perusteella kilometrikorvaus sekä mahdolliset päivärahat.

Asiakas on antanut lähteeksi seuraavan sivun: <https://www.vero.fi/henkiloasiakkaat/auto/kilometrikorvaus_ja_paivaraha/>

Sinun tulisi suunnitella pieni sovellus, joka auttaisi asiakasta. Asiakkaalla on joitakin toiveita mitä hän haluaisi ohjelman sisältävän, jos se vain onnistuu.

* Ohjelma sisältäisi mahdollisuuden lisätä myyntiedustajia ja kirjata heille matkakuluja
* Ohjelmaan tulisi syöttää nykyisen vuoden korvausmäärät, joista ohjelma laskee sitten kilometrikorvaukset.
* Jos mahdollista, kilometrikorvauksien lisäksi ohjelma laskisi päivärahojen suuruuden matkan keston perusteella.
* Asiakas haluaisi saada myös yhteenvedon tämän hetkisistä maksamattomista korvauksista.&#x20;
* Lisäksi jos mahdollista niin ohjelmasta näkisi, että paljonko myyntiedustajille on maksettu korvauksia ja paljonko on maksamatta.

![Esimerkki matkalaskun / kilometrikorvauksen sisällöstä](/files/-MFtemB1IHiXp_2qIqZs)


# Laskutus

Harjoitustyöhön annettu toimeksianto

{% hint style="warning" %}
**Huom!** Opiskelijoille suunnatuissa projekteissa heidän arviointinsa ja palautettavat dokumentit on kuvattu tarkemmin heidän omalla oppimisalustallaan.
{% endhint %}

## Toimeksiannon kuvaus <a href="#vaatimukset-toimeksiannon-ohjelmalle" id="vaatimukset-toimeksiannon-ohjelmalle"></a>

Asiakkaalla on tarve ohjelmalle, joka laskisi tulevia seuraavan laskutuspäivän hänen palveluidensa käytössä. Asiakkaalla on suunnitteilla toteuttaa tilausmallinen (subscription) pohjainen verkkopalvelu ja sen avuksi hän tarvitsee laskutuksen avuksi ohjelman.

Asiakkaalla on seuraavia toiveita miten ohjelman tulisi toimia:

* Ohjelmaan lisättäisiin asiakas ja palvelutaso.
* Asiakkaalla voi olla kerrallaan vain yksi palvelutaso ja laskutus tapahtuu kuukausittain aina 30 päivän välein.
* Palvelutasoja voi olla useita erilaisia ja niillä tarkoitetaan esimerkiksi Basic, Pro, Enterprise versioita tulevasta verkkopalvelusta. Palvelutasolle pitää pystyä määrittämään kuukausihinta.
* Asiakas toivoisi, että voisi nähdä ohjelmasta listan tulevista maksuista seuraavilta kuukausilta.
* Asiakas haluaisi tarjota myös mahdollisuuden ostaa esimerkiksi 6kk tai 12kk kerralla ja vasta sen jälkeen alkaisi kuukausikohtainen laskutus. Jos palvelusta maksetaan heti 6kk, kokonaishintaan annetaan 10% alennus ja 12kk kohdalla, kokonaishintaan annetaan 18% alennus.

Asiakas on pohtinut myös, että ohjelma osaisi ottaa huomioon mahdollisen 30 päivän kokeiluajan, joka on ilmainen hänen palveluidensa ostajalle.

Lisäksi asiakkaan mielestä huomioitavaa on, että palvelutaso voi muuttua kesken sen käytön eli miten esimerkiksi palvelutason nosto tai pienennys otetaan laskutuksessa huomioon?

Lue aiheesta myös <https://en.wikipedia.org/wiki/Subscription_billing_service>


# Laskun perintä

{% hint style="warning" %}
**Huom!** Opiskelijoille suunnatuissa projekteissa heidän arviointinsa ja palautettavat dokumentit on kuvattu tarkemmin heidän omalla oppimisalustallaan.
{% endhint %}

## Toimeksiannon kuvaus <a href="#vaatimukset-toimeksiannon-ohjelmalle" id="vaatimukset-toimeksiannon-ohjelmalle"></a>

Asiakkaana on perintään keskittynyt yritys. Toiminnan kasvaessa eri perintätoimeksiannoista on ollut vaikeampi pysyä perillä. Joitakin perintätoimeksiantoja on myös unohtunut uusia ja tästä on ollut haittaa velkojille.

Asiakas tarvitsee apua perinnän hoitamiseen. Laskujen periminen on hyvin etukäteen määritelty kokonaisuus. Lisää laskujen perinnästä voi lukea täältä. <https://www.kkv.fi/Tietoa-ja-ohjeita/Maksut-laskut-perinta/perinta/perintakulut-ja-perinnan-eteneminen/>

Toimeksiannon osalta asiakkaalla ei ole suuria toiveita ja hän haluaa tietää onko velkojien antamista perintätoimeksiannoista mahdollista saada tehtyä ohjelmaa, joka muistuttaisi päällä olevista perittävistä toimeksiannoista.

Toiveina olisi, että ohjelma voisi hoitaa seuraavat asiat:

* Velkojien laskujen kirjaaminen palveluun.
* Näyttää lista kirjattujen laskujen 1. maksumuistutuksesta eli milloin sen saa lähettää ja onko maskumuistutus lähetetty.
* Näyttää lista kirjattujen laskujen 2. maksumuistutuksesta eli milloin sen saa lähettää ja onko maskumuistutus lähetetty.
* Ilmoittaa mahdolliset maksulisät lähetettyjen muistutusten perusteella.
* Mahdollista kirjata ohjelmaan kirjattu lasku suoritetuksi, jolloin ohjelma ei muistuttaisi näistä laskuista enää.


# Agile esimerkki, sykli

Esimerkissä on kuvattu yksittäisen syklin (sprintti, vaihe, sykli, iteraatio jne.) kierto ja mitä se sisältää. Syklin sisältö on kerätty omien kokemusten perusteella ja se saattaa yhdistellä useita eri menetelmiä. Tarkoituksena on kuitenkin antaa esimerkki ja sen kautta harjoitusprojektin yhteydessä noudattaa ohjeistettua tapaa.

![Viitattu 1.2.2019, Smashing Magazine, Fitting Big-Picture UX Into Agile Development \[1\]](/files/-LXbfbDqNiAXnIZ5tQ1n)

### Vaatimusmäärittely <a href="#vaatimusm-c3-a4-c3-a4rittely" id="vaatimusm-c3-a4-c3-a4rittely"></a>

**Käyttäjätarina -kuvaus**

* [User Stories](https://www.agilealliance.org/glossary/user-stories)
* [Advantages of User Stories for Requirements](http://www.mountaingoatsoftware.com/articles/advantages-of-user-stories-for-requirements)
* [Role-Feature-Reason](https://www.agilealliance.org/glossary/role-feature/)

Käytämme käyttäjätarinoihin Role-Feature-Reason tapaista kuvausta. Syvempi kuvaus ei ole tässä kohdin tärkeä vaan yritetään ensin muodostaa ymmärrettävä lause, joka muodostuu mallin mukaisesti.

Usein tarkempi määrittely ja kuvaus voidaan kirjoittaa ennen tarinan toteuttamista tai jopa ennen sitä suunnitteluvaiheessa, jossa mukana on henkilö, joka tuntee tämän tarinan sisällön. Liian tarkkaan ei tarvitse määritellä vaan pystyä tekemään kuvaus, jolla priorisoidaan tarve. Käyttötapauksia voidaan hyödyntää toteuttamisvaiheen alussa ja tehdä tarkempi suunnitelma miten ominaisuudet toimivat.

**Käyttötapaus -kuvaus**

* Kts. User Stories linkki
* [Requirements 1010: User Stories vs. Use Cases](http://www.stellman-greene.com/2009/05/03/requirements-101-user-stories-vs-use-cases/)
* [User Stories Versus Use Cases](https://www.scrumalliance.org/community/member-articles/1246)&#x20;

Käyttötapaus on dokumentti mikä voidaan kirjoittaa esimerkiksi käyttäjätarinan perusteella. Huomaa lähteissäkin, että ne pyrkivät kertomaan mikä ero on käyttäjätarinalla ja käyttötapauksella. Lyhyesti, käyttötapaus voidaan nähdä tarkempana määritelmänä miten ohjelma kommunikoi eri osapuolten kanssa ja toteuttaa halutun tavoitteen.

**Tuotteen -backlog**

* [Backlog](https://www.agilealliance.org/glossary/backlog/)
* [Product Backlog](http://www.scrumguides.org/scrum-guide.html#artifacts-productbacklog)
* [Grooming Backlog](https://www.agilealliance.org/glossary/backlog-refinement/)
* [MoSCoW priorisointi](https://www.agilebusiness.org/page/ProjectFramework_10_MoSCoWPrioritisation)

Tuotteen tehtävälista on dokumentti, joka ohjaa kehitystä. Se muuttuu aika ajoin ja pääasiassa tuotteen omistaja huolehtii siitä. Kehitystiimi kuitenkin osallistuu tähän myös tarvittaessa ja varsinkin kun tehtäviä otetaan seuraavaan sykliin.

**Syklin (sprintin) -backlog**

* [Sprint Backlog](http://www.scrumguides.org/scrum-guide.html#artifacts-sprintbacklog)

Syklin tehtävälista on dokumentti, johon on valittu ne tehtävät mitkä kehitystiimi "lupaa" tehdä. Tarkoitus on, ettei valita liikaa vaan voidaan melko tarkasti sanoa, että ne toteutuvat. Tehtäviä katsotaan läpi aina syklien lopussa ja siivotaan sekä korjataan olettamuksia.

### Ohjelmointi <a href="#ohjelmointi" id="ohjelmointi"></a>

**Versionhallinta**

* Kts. Versionhallinan perusteet

**Yksikkötestaus ja TDD**

* Kts. yksikkötestauksen perusteet
* Kts. yksikkötestauksen perusteet

**SOLID -sääntö/ohje**

* [Wikipedia: SOLID](https://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29)
* [SOLID architecture principles using simple C# examples](https://www.codeproject.com/Articles/703634/SOLID-architecture-principles-using-simple-Csharp)
* [Robert Martin SOLID Principles of Object Oriented and Agile Design (video)](https://www.youtube.com/watch?v=TMuno5RZNeE)

SOLID säännöstä ei ole muuta kirjoitettua materiaalia tässä kirjassa. Lähteet auttavat sinua tutustumaan aiheeseen ja varsinkin Robert Martinin video on valaiseva. Kyseinen henkilö on säännön luonut eri kokemuksien pohjalta. Säännön tarkoitus on koostaa hyviä tapoja olio-ohjelmoinnin luokkien ohjelmointiin ja parantaa koodin laatua. Käytännössä on kyse ohjelmoinnista ja vain vinkata mitä huomioida kun ohjelman koodia tuotetaan ja kuinka se auttaa myöhemmin muutosten tekemisessä.

### Syklin lopetus <a href="#syklin-lopetus" id="syklin-lopetus"></a>

**Tuoteversio (Increment)**

* Kts. Scrum guide ja etsi sana increment.
* [Sprint Review](http://www.scrumguides.org/scrum-guide.html#events-review)
* [Sprint Retrospective](http://www.scrumguides.org/scrum-guide.html#events-retro)

Lyhyesti tarkoitetaan sitä, että kehitystiimi on lisännyt tuotteeseen ominaisuuksia, jotka tarvittaessa tuotteen omistajan hyväksymisen jälkeen voidaan julkaista. Julkaisu ei ole pakollinen vaan isompi julkaisu voidaan tehdä useammassa syklissä. Tärkeintä on, että tuote on aina julkaisuvalmis tarvittaessa, koska välttämättä kaikkien ominaisuuksien ei tarvitse olla valmiita. Tämä on ketterän ohjelmistokehityksen tavoite. Tehdä vähän, julkaista ja oppia tuotteesta. Tällöin riskit voidaan rajat esimerkiksi 2 viikon jaksoihin kuukausien sijasta.

![](/files/-LzN9j5B_kcJgE6ZNexI)

## Lähteet

\[1] <https://www.smashingmagazine.com/2012/11/design-spikes-fit-big-picture-ux-agile-development/>

\[2] <http://www.agilenutshell.com/>


# Agile, Tuotteen tehtävälista

Esimerkki tuotteen tehtävälistasta.

## Sijainnin merkintä

Yksinkertaisuudessaan tarkoitetaan ohjelmaa, jolla voidaan merkitä sijainti. Sijainti sisältää GPS koordinaatit sekä muita ominaisuuksia, joita ohjelma hyödyntää.

### Käyttäjätarinat

* Koiran ulkoiluttajana tahdon lisätä oman nykyisen sijaintini ulkoilupaikan kartalle, jotta voin ilmoittaa ulkoilupaikasta muille käyttäjille.
* Koiran ulkoiluttajan tahdon nähdä nykyisen sijaintini ympärilläni olevia ulkoilupaikkoja, jotta löydän läheltä sopivan pysähdyspaikan.
* Koiran ulkoiluttajana tahdon tarkastella merkityn ulkoilupaikan tarkempia tietoja, jotta tiedän soveltuuko se koiralleni.
* Koiran ulkoiluttajan tahdon ilmoittaa ulkoilupaikan virheellisestä informaatiosta, jotta tieto olisi ajantasaista.
* Koiran ulkoiluttajan tahdon ilmoittaa väärinmerkityn ulkoilupaikan poistamisesta, jotta tieto olisi ajantasaista.
* Koiran ulkoiluttajan tahdon nähdä sijainnista onko paikalla muita koiran ulkoiluttajia, jotta tiedän onko sijainti sillä hetkellä sopiva koiralleni.
* Koiran ulkoiluttajan tahdon nähdä nykyisen sijaintini ympärilläni olevia yrityksiä, jotka tarjoavat koirille suunnattuja palveluita.
* Koiran ulkoiluttajana tahdon ilmoittaa muille koiranomistajille, että olen menossa valitsemaani sijaintiin tiettynä ajanhetkellä.
* Koiran ulkoiluttajan tahdon lähettää kuvia ulkoilupaikasta valitsemaani sijaintiin.
* Palvelun tarjoajana tahdon, että käyttäjä merkitään sijainnissa olevaksi kun ulkoiluttaja on

  lähellä sijaintia paikkatiedon mukaan.

  Ulkoilupaikkaan liitettäviä tietokenttiä

  • <https://gist.github.com/nyluntu/ee674be05a4291ac0a6b8c6d91553603>

## Koirien merkintä / lemmikin hallinta

Toiminnon tarkoitus on mahdollistaa käyttäjän lisätä omistamansa lemmikki ohjelmaan. Tässä kohdin lemmikillä tarkoitetaan koiria. Lisättävät tiedot ovat monipuolisia, jotka pitää ottaa huomioon.

### Käyttäjätarinat

* Palvelun tarjoajana, tahdon koiran omistajan pystyvän lisäämään yhden tai useamman koiran tietonsa palveluun.
* Palvelun tarjoajana, tahdon koiran omistajan pystyvän korjaamaan hänen koiran tietonsa palveluun.
* Palvelun tarjoajana tahdon koiran omistajan pystyvät tarkastelemaan oman ja muiden koiranomistajien koirien tietoja.
* Palvelun tarjoajana tahdon koiran omistajien pystyvän voida poistamaan koiransa tiedot palvelusta.
* Koiran omistajana tahdon lisätä yhden tai useamman kuvan koirastani.

  Koiraan liittyviä tietokenttiä

  • <https://gist.github.com/nyluntu/c18163689c79a95fd318cdac1cf910f7>

## Sijaintien ja lemmikkien seuranta

Toiminnon tarkoitus on mahdollistaa käyttäjien lisätä itselleen seurattavia sijainteja ja lemmikkejä. Puhutaan yleisesti ns. "follow" tyyppisestä toiminnosta, joka on tuttu monesta eri some-palvelusta. Ei ole tarkoitus seurata sijaintia vaan lisätä sijainteja ja lemmikkejä omaan listaan, josta ollaan kiinnostuneita.

### Käyttäjätarinat

* Koiran ulkoiluttajana tahdon pystyä merkitsemään itselleni suosikkisijainteja, jotta löydän ne nopeammin palvelusta.
* Koiran ulkoiluttajana tahdon pystyä näkemään listauksen suosikkisijainneistani.
* Koiran ulkoiluttajana tahdon nähdä suosikkisijainneista, onko paikalla muita koiranomistajia

  kyseisellä ajanhetkellä.
* Koiran ulkoiluttajan tahdon pystyä poistamaan sijainteja suosikkilistaltani.
* Koiran ulkoiluttajana tahdon pystyä merkitsemään muiden omistajien koiria kaverilistalleni,

  jotta löydän tutut koirat nopeammin.
* Koiran ulkoiluttajana tahdon pystyä poistamaan koiria kaverilistaltani.
* Koiran ulkoiluttajan tahdon nähdä kaverilistaani lisäämistä koirista, ovatko ne kyseisellä

  ajanhetkellä ulkoilemassa jossakin sijainnissa.
* Koiran ulkoiluttajan tahdon nähdä kaverilistaani lisäämistä koirista, ovatko ne kyseisellä

  ajanhetkellä ulkoilemassa omistajan kanssa jossakin sijainnissa.
* Koiran ulkoiluttajan tahdon nähdä kaverilistaani lisäämistä koirista, onko omistaja

  ilmoittanut menevänsä ulkoilemaan tiettynä ajanhetkenä johonkin palvelun sisältämissä sijainneista.


# Agile, Käyttäjätarina ja käyttötapaus

Esimerkki käyttäjätarinasta ja käyttötapauksesta

## Asiakkaan kertomus ongelmakohdasta

Ravintolassani `asiakkaani` ohjataan ensin `pöytään`. Työskentelyvuorossa oleva `tarjoilija`, joka on ohjannut asiakkaat pöytään, ottaa vastaan heidän `tilauksensa`.

Tarjoilija kysyy, mitä juomia ja `ateria` -vaihtoehtoja he haluavat. Ruuat ja juomat tarjoillaan yleensä eri aikaan toimitettuina. Asiakkaalta voidaan kysyä myös, onko asiakkaalla näyttää `kanta-asiakas` -korttia tai etukuponkeja. Kanta-asiakkaana tai `etukupongilla` asiakas saa yleensä 15% alennuksen tilauksen loppusummasta.

Kun tarjoilija on merkinnyt tilauksen päätelaitteellaan järjestelmään, hän vahvistaa `tilauksen` ja tieto `tilauksen` sisällöstä tallentuu. `Tilauksen` sisältö on nähtävissä esimerkiksi `keittiön` puolella tai muissa järjestelmissä. Tilausta ei ole vielä tässä vaiheessa maksettu, joten on tärkeää pystyä erottamaan, onko tilaus vain `vahvistettu tai maksettu`.

&#x20;Kun `asiakas` on syönyt, `tarjoilija` palaa kysymään asiakkaan kuulumisia. Tässä yhteydessä, jos `asiakas` on valmis, hän yleensä maksaa tilauksensa.

## Käyttäjätarina

Tarjoilijana\
tahdon merkitä vastaanotettavan tilauksen järjestelmään,\
jotta tilauksen sisältö on selkeä keittiön henkilökunnalle.

## Käyttötapaus

**Otsikko**

Uuden tilauksen vastaanottaminen

**Tavoite**

Tarjoilija saa merkittyä asiakkaan tilauksen tilausrivit järjestelmään.

**Esiehdot**

Tilauksessa on oltava valittuna pöytä, joka ei ole varattu sillä hetkellä.\
Tilauksessa on oltava vähintään yksi tilausrivi.\
Tilauksessa on oltava merkittynä asiakkaasta tieto, onko hän kanta-asiakas tai käyttänyt etukuponkia.

**Onnistunut lopputulos**

Tilauksen tiedot ovat tallennettu järjestelmään. (esim tietokanta, tekstitiedosto tai jokin muu)

**Virheellinen lopputulos**

Tilaus epäonnistuu eikä sen tiedot tallennu oikeassa muodossa järjestelmään.

**Kuvaus käyttötapauksesta**

1. Tarjoilija painaa painiketta, joka luo uuden tyhjän tilauksen.
2. Tarjoilija merkitsee tilaukselle pöydän.
3. Tarjoilija lisää tilaukseen aterioita ja niiden määrän.
   1. Aterioita lisättäessä, tarjoilija näkee aina päivitetyn loppusumman.
4. Tarjoilija merkitsee tiedon, jos kyseessä on kanta-asiakas tai etukuponki.
5. Tarjoilija vahvistaa tilauksen
6. Onnistuneen vahvistamisen jälkeen, ohjelma palaa tarvittaessa alkutilaan.

**Kuvaus virheellisestä käyttötapauksesta**

5 kohdassa kun tarjoilija on vahvistanut tilauksen, ohjelman pitää pystyä toipumaan virhetilanteista, jotka on mainittu esiehdoissa. Näistä tietojen puutteista on näytettävä virhe tarjoilijalle ja hänen on pystyttävä täydentämään puuttuvat tiedot ilman, että joutuu aloittamaan alusta.�

## Luokkakaavio

Asiakkaan kuvauksessa ja käyttötapauksessa esiintyy seuraavia termejä:

Asiakas\
Kanta-asiakas\
Tarjoilija\
Tilaus\
Tilausrivi\
Ateria\
Pöytä�

![](/files/-LK6TOb9njkWqm-0aAEg)

## Käyttöliittymä

![](/files/-LK6TEk2FwG7C6ihRh4o)

![](/files/-LK6TL1BujIEcEOIWKG1)


# Agile muu materiaali ja lähteitä

[https://www.agilealliance.org](https://www.agilealliance.org/)

Sivusto koostaa ja selittää ketterän ohjelmistokehityksen termejä. Erittäin hyvä lähde tutustua aiheeseen. Lisäksi, jos yrität ottaa käyttöön uusia menetelmiä, sivuston "[menetelmä metrokartta](https://www.agilealliance.org/agile101/subway-map-to-agile-practices/)" ja eri menetelmien esittelyt ovat hyviä lähtökohtia.

<http://www.scrumguides.org/>

Ensimmäinen lähde SCRUM menetelmän tutustumiseen. Sisältää SCRUM oppaan, joka sisältää kaiken tarvittavat tiedot menetelmän kehittäjiltä.

<http://www.extremeprogramming.org/>\
<https://www.agilealliance.org/glossary/xp/>

Extreme Programming on SCRUMin tapaan toinen tunnettu ketterä menetelmä. Se keskittyy enemmän kehittäjän erilaisiin työvaiheisiin ja tekniikoihin. Ohjelmoijalle erittäin käytännöllinen ja taidot ovat useasti monen onnistuneen projektin takana. Usein ketterissä menetelmissä unohtuu tekniset taidot kaiken muun hälinän keskellä.

<http://www.agilenutshell.com/>

## Asiakasprofiiliin liittyvät asiat

{% embed url="<https://www.agilealliance.org/glossary/personas/>" %}

{% embed url="<https://www.romanpichler.com/blog/10-tips-agile-personas/>" %}

{% embed url="<https://www.mountaingoatsoftware.com/blog/advantages-of-the-as-a-user-i-want-user-story-template>" %}

{% embed url="<https://www.mountaingoatsoftware.com/blog/selecting-the-right-user-role>" %}


# Agile termit (scrum)

Koostettu käytetyimpiä termejä joita vilisee puhekielessä. Nämä on hyvä ymmärtää.

## Sanasto

SCRUM

Tiimi (Scrum team)

Tuotteen omistaja (Product owner)

Kehitystiimi (Development team)

Valmentaja (Scrum master)

Sprintti, Iteraatio (Sprint)

Sprintin suunnittelu

Päivittäispalaveri (Daily scrum)

Sprintin katselmointi (Sprint review)

Sprintin retrospektiivi (Sprint retrospective

Scrum tuotokset (Scrum artifacts)

Tuotteen kehitysjono (Product backlog)

Sprintin kehitysjono (Sprint backlog)

Inkrementti (Increment)

Tuotosten läpinäkyvyys (Artifact transparency)


# Sanasto Git

Sanastoa Git versionhallintaan. Termejä suomeksi ja englanniksi.

{% hint style="info" %}
Sanastossa käytetyt suomenkieliset käännökset eivät ole virallisia käännöksiä. Termit on haettu käyttäen eri lähteitä sekä sitten työelämässä käytetyistä nimityksistä. Virallisia käännöksiä ei sinällään ole.
{% endhint %}

| EN                          | FI                       | Selitys                                                                                                                                                                                                                                                                                       |
| --------------------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Repository                  | Tietovarasto             | Tarkoitetaan lähdekoodille luotua varastoa. Voidaan puhua myös eräänlaisesta "git hakemistosta". Sisältää versionhallinnan luoman muutoshistorian lähdekoodista.                                                                                                                              |
| Remote repository           | Etätietovarasto          | Tarkoitetaan sellaista olemassa olevaa tietovarasto, joka ei sijaitse kehittäjän työasemalla. Sijaitsee usein erillisellä palvelimella tai palvelussa. (Esim. Github)                                                                                                                         |
| Local repository            | Paikallinen tietovarasto | Tarkoitetaan sellaista olemassa olevaa tietovarastoa, joka sijaitsee kehittäjän työasemalla.                                                                                                                                                                                                  |
| working directory           | Työhakemisto             | Tarkoitetaan sitä kansiota missä sillä hetkellä on komentorivillä. Esimerkiksi polku nykyiseen työhakemistoon linux ympäristöissä selviää komennolla `pwd`                                                                                                                                    |
| Reference, remote reference | viittaus                 | Viittauksella tarkoitetaan Gitin käyttämää tunnistetta, toisinsanoen viittausta esimerkiksi versioihin muutoshistoriassa. Voidaan myös puhua etätietovarastojen viittauksista, joilla tarkoitetaan mihin etätietovarastoon nykyinen paikallinen tietovarasto viittaa. (Kts. komento `remote`) |
| Branch                      | haara, kehityshaara      | Tarkoitetaan versionhallinnassa päähaarasta tehtyä sivuhaaraa. Haara voi olla esimerkiksi toisen ominaisuuden takia tehty kopio nykyisestä versiosta, jota kehitetään itsenäisenä kokonaisuutena. Haara voidaan yhdistää takaisin päähaaraan.                                                 |
| Tag                         | Tagi                     | Tagi on versionhallinnassa käytettävä tunniste, jostakin tietystä versiosta. Tagi voidaan nimetä, joten sen sijaan, että version tunniste on pelkkä SHA1 tunniste, voidaan sille antaa merkittävämpi nimi.                                                                                    |
| Conflict                    | Konflikti                | Tarkoittaa sellaista tilannetta kun työkalu ei osaa yhdistää haluttuja muutoksia esimerkiksi kahden eri kehityshaaran kohdalla. Tällöin syntyy konflikti, jonka kehittäjän on selvitettävä itse ja muokattava alkuperäinen tiedosto haluttuun lopputilaan, joka vahvistetaan.                 |
| stash                       | -                        | Tarkoitetaan Gitin komentoa stash, jolla voidaan kätkeä tai piilottaa hetkellisesti nykyiset voimassa olevat muutokset.                                                                                                                                                                       |
| staging area                | valmistelualue           | Yksi Gitin käyttämä tekniikka. Halutut muutokset lisätään aina ennen vahvistamista valmistelualueelle. Kun halutut muutokset ovat koossa, voidaan tehdä pysyvä muutos versionhallinan muutoshistoriaan.                                                                                       |
| master                      | -                        | Termi tarkoittaa tietovaraston päähaaraa, joka oletuksena syntyy aina kun Git -versionhallinta otetaan käyttöön. Usein se mitä pääosan ajasta käytetään mutta riippuu työtavoista. *(Katso myös kehityshaara)*                                                                                |
| clone                       | klooni                   | Tarkoitetaan usein tietovaraston kopiointia. Tarkalleen ottaen `clone` on myös Gitin komento, joka kopioi etätietovaraston paikalliselle koneelle kun se otetaan käyttöön ensimmäistä kertaa.                                                                                                 |
| commit                      | *"Pysyvä muutos"*        | Tarkoitetaan muutosten vahvistamista, jotta ne tulevat voimaan ja näkyvät versiohistoriassa omalla tunnisteella. Muutokset on ensin pitänyt lisätä valmistelualueelle `add` komennolla.                                                                                                       |
| fetch                       | -                        | Tietojen "vetäminen" tai "päivittäminen" etätietovarastosta paikalliseen. Kyseessä on siis tarkalleen ottaen Gitin komento.                                                                                                                                                                   |
| pull                        | -                        | *Katso fetch.* Tekee saman asian mutta yhdistää muutokset paikallisen tietovaraston kanssa.                                                                                                                                                                                                   |
| push                        | -                        | Pull komennon vastakohta eli työntää paikallisessa tietovarastossa olevat uudet pysyvät muutokset etätietovarastoon.                                                                                                                                                                          |
| remote                      | -                        | Komento etätietovarastojen viittauksien hallintaan.                                                                                                                                                                                                                                           |
| SHA                         | -                        | <https://fi.wikipedia.org/wiki/SHA>                                                                                                                                                                                                                                                           |
| HEAD                        | -                        | Tarkoittaa viittausta nykyiseen ja uusimpaan muutokseen paikallisessa tietovarastossa. Aina kun uusi pysyvä muutos tehdään niin siitä tulee uusi HEAD.                                                                                                                                        |

## Lähteet

{% embed url="<https://www.linux.fi/wiki/Git>" %}

{% embed url="<https://www.cs.helsinki.fi/u/hisahi/sanastot/git_github.html>" %}


# Opas Gitin perusteisiin

Versionhallinnan avulla voidaan seurata lähdekoodin muutoksia ja työskennellä tehokkaammin yhdessä. Yksi suosituimmista versionhallintaan suunnitelluista työkaluista on Git. Seuraavassa artikkelissa käydään läpi perusteet, joiden avulla pääset alkuun.

{% hint style="danger" %}
Huomio! Joissakin lähteissä **master** branchiin viitataan nimellä **main**. Koskee toistaiseksi lähinnä Github palvelua mutta saattaa yleistyä. Kyseessä on vain teknisesti nimimuutos.
{% endhint %}

## Yleiskuva Git työkaluun

Git on monipuolinen työkalu, joka on suunniteltu toimimaan hajautettuna versionhallintana (*distributed version control*). Hajautettu versionhallinta tarkoittaa sitä, että jokainen kopio Gitin tietovarastosta toimii itsenäisesti. Verrattuna keskitettyihin versionhallintapalveluihin *(centralized version control)*, jotka vaativat toimiakseen eräänlaisen keskitetyn tietovaraston muutosten hallintaan, git toimii myös itsenäisesti. Usein kuitenkin myös Git-työkalua käytettäessä mukana on keskitetty tietovarasto, jota käytetään pääasiallisena lähteenä. Hajautettu malli mahdollistaa kuitenkin sen, että monet asiat voidaan tehdä paikallisesti ilman verkkoyhteyttä.

![Lähde: Pro Git, Distributed version control.](/files/-LzTaCdqmVgD-hiSdGNA)

Etätietovarasto kannattaa ajatella vain kopiona lähdekoodista. Usein sellainen on sijoitettu palvelimelle tai  kolmannen osapuolen palveluun, kuten esimerkiksi Github -palveluun. Etätietovarasto toimii pääosin keskitettynä lähteenä, jossa pidetään lähdekoodin tuorein  versio. Muutoksia ei suoraan tehdä etätietovarastoihin vaan ensin muutokset vahvistetaan paikallisessa tietovarastossa, josta ne sitten työnnetään *(push)* etätietovarastoon ja ovat koko kehitystiimin saatavilla, joilla vain on pääsy kyseiseen palveluun.

Hajautettu versionhallinta tuo mukanaan myös sellaisen edun, että mikä tahansa tietovaraston kopio voi toimia toisen paikallisen tietovaraston etätietovarastona. Tilanteessa, jossa alkuperäinen etätietovarasto menee vikatilaan tai sitä ei saataisi korjattua, voisi yksi nykyisistä paikallisista tietovarastoista toimia uutena etätietovarastona. Käytännössä tämä tarkoittaa sitä, että yksi kehittäjistä perustaisi uuden etätietovaraston, jonne hän oman muutoshistoriansa työntää. Tällöin kannattaa valita sellainen, jolla on mahdollisimman tuorein muutoshistoria. Tämä toimii siksi, että jokainen tietovaraston kopio sisältää koko päähaaran historian kun se kopioidaan.

Git työkalu käsittelee kaikki muutokset paikallisesti. Muutokset voidaan myös työntää etätietovarastoon *(remote repository)* kun ne tahdotaan jakaa muiden ohjelmoijien kanssa tai sitten muutoin pistää talteen. Karkeasti ottaen Gitin käyttö voidaan jakaa kahteen osa-alueeseen: **paikalliseen tapahtuvaan työskentelyyn** ja **etätietovarastoihin liittyvään työskentelyyn**.

## Gitin kolme tilaa

Ennen tutustumista paikalliseen työskentelyyn, pitää ymmärtää miten Git toimii paikallisesti ja kuinka se käsittelee tiedostojen muutokset. Puhutaan niin sanotusti kolmesta eri tilasta: **työhakemistosta** *(working directory, workspace)*, **valmistelualueesta** *(staging area)* ja Git-hakemistosta eli **paikallisesta tietovarastosta** *(repository)*.&#x20;

![Lähde: Pro Git, Working tree, staging area, and Git directory.](/files/-LzTf84vSOUR9fOjHbbA)

### Työhakemisto

Kun työskentelet Git -työkalulla, se käsittelee tietojärjestelmän kansioita ja tiedostoja. Työhakemistolla tarkoitetaan sitä kansiota (hakemistoa) mikä on alustettu käyttäen Gitin komentoa tai kloonattu etätietovarastosta. Työhakemistona voi siis toimia mikä tahansa kansio ja komentokehotetta käyttäessä, sillä tarkoitetaan usein juurikin sitä kansiota missä sillä hetkellä on.

Työhakemisto, joka on Gitin seurannassa, toimii kuten normaali kansio. Kun lisäät, muutat tai poistat tiedoston niin Git seuraa näit eroja. Työkalu kertoo missä tilassa tiedostot ovat. Työhakemistossa, jossa Git on käytössä, löytyy aina piilotettu **.git** -niminen kansio (huomaa piste nimen edessä) ja sisältää työkalun tarvittavia tiedostoja. Kyseiseen kansioon ei tulisi koskea.

Lähdekoodeihin tehdyt muutokset eivät automaattisesti säily versionhallinnassa vaan Gitin kohdalla pitää kertoa mitkä muutokset halutaan lisätä eli valmistella seuraavaa versiota varten. Tässä termillä versio tarkoitetaan pysyvää muutosta, joka on Gitin lokissa eli muutoshistoriassa. Muutoksen tilalle ei ole väliä vaan lisättiin, poistettiin tai muutettiin tiedostoa niin se tulee aina viedä niin sanotulle valmistelualueelle.

{% hint style="info" %}
Git ei käsittele itseasiassa kansioita vaan pelkkiä tiedostoja. Jos luot siis kansion, joka ei sisällä tiedostoja, ei Git huomaa eroa. Lisää siis aina jokin tiedosto tyhjään kansioon, jos haluat sen pysyvän lähdekoodien mukana jostain syystä.
{% endhint %}

### Valmistelualue

Valmistelualue on eräänlainen välitila ennen pysyvän muutoksen vahvistamista. Valmistelualueelle voidaan lisätä halutut muutokset. Työskentelyn aikana tulee tilanteita, kun ohjelmoija on koskenut useaan tiedostoon mutta haluaa vain lisätä tietyt yksittäiset muutokset eikä kaikkia muutoksia.&#x20;

Kun tiedosto lisätään valmistelualueelle, siitä otetaan viimeisin kopio talteen. Tiedoston muuttuessa tämän jälkeen, se pitää lisätä uudelleen valmistelualueelle, joten usein tämä tehdään siinä vaiheessa kun halutut muutokset on tehty. Valmistelualueella ei ole kovin tärkeää osaa päivittäisessä työskentelyssä mutta sen rooli on hyvä tuntea.

Seuraava vaihe on tehdä valmistelualueen tiedostojen kopioista pysyvä versio muutoshistoriaan. Tätä tilannetta kutsutaan ***commitiksi** (commit)*, jolloin muutokset vahvistetaan paikalliseen tietovarastoon.

### Paikallinen tietovarasto

Paikallinen tietovarasto on viimeisin kolmesta vaiheesta. Kun pysyvä muutos on tehty, se kirjataan paikalliseen tietovarastoon uutena versiona. Voidaan siis puhua niin sanotusti pysyvästä muutoksesta, josta tulee osa muutoshistoriaa. Samalla kun muutos vahvistuu niin Git merkitsee uusimman muutoksen nykyiseksi version ***"pääksi"*** *(HEAD)*, joka siis viittaa tuoreimpaan versioon.

Muutoshistoria on eräänlainen ketju muutoksia ja sisältää aina tiedon edellisestä versiosta. Eri lähteissä versioista puhutaan myös termillä *snapshot* eli eräänlaisesta sen hetkisestä tiedostojen tilasta. Pääosin Gitin komennot käsittelevät tätä paikallista tietovarastoa ja etätietovarastojen käsittelyyn varten on omat komentonsa.&#x20;

{% hint style="info" %}
Git ei tallenna kopiota koko työhakemistosta (kuten osa versionhallintaan tehdyistä työkaluista) kun pysyvä muutos tehdään. Puhutaan enemmän tiedon lisäämisestä eli jokainen muutos kertoo mikä on muuttunut edelliseen versioon nähden.&#x20;
{% endhint %}

## Asentaminen

Gitin voi asentaa koneelleen usealla eri tavoilla. Tässä oppaassa käymme läpi näistä vain yhden. Lataa uusin versio [Gitin kotisivuilta](https://git-scm.com/) ja käy asennusvaiheet läpi oletusasetuksin.

![](/files/-MRjC9ozZLRYt6oIZUMy)

Asennuksen jälkeen käynnistä ohjelma. Oppaassa sekä näissä harjoituksia käytämme Git -työkalua komentokehotteen kautta. Käyttöjärjestelmällä ei ole harjoitusten kanssa väliä, koska samat komennot toimivat. Eroja voi olla ainoastaan käyttöjärjestelmien omissa komentokehotteiden tukemissa komennoissa. Harjoituksissa esiintyy siis muutamia Linux pohjaisia komentoja, jotka toimivat Macissa sekä myös käytettävässä Git Bash -komentokehotteessa Windowsilla.

{% hint style="info" %}
Erilaisia yleisimpiä komentoja on käyty läpi [tällä videolla](https://www.youtube.com/watch?v=LAtX5h4py3I).
{% endhint %}

### Aukaise komentokehote tietokoneeltasi.&#x20;

**Windowsilla** aukaise kotivalikko ja hae komentokehotse **Git Bash** nimellä. Sinulle aukeaa tumma ruutu. Halutessasi voit myös käyttää **CMD** tai **Powershell** komentokehotteita mutta niiden eri komentoja ei harjoitteissa käydä läpi. Gitin komennot ovat samoja.

MacOS käyttöjärjestelmässä aukaise terminaali. Nopeiten tämä onnistuu painamalla `CMD+välilyönti`ja kirjoittamalla hakuun **Terminal**.

Kun komentokehote aukeaa niin kokeile Gitin toimivuus seuraavalla komennolla.

```bash
# Komento tulostaa gitin version ja komennon ei tulisi ilmoitta virheestä.
git --version

# Esimerkki tulosteesta:
# git version 2.23.0
```

### Ensimmäinen käyttökerta

Konfiguroi Git ensimmäisellä käyttökerralla. Seuraavat kaksi komentoa ovat usein ne tarpeellisimmat, jotka pitää antaa.

```bash
# Asetusten komennot eivät tulosta mitään niiden antamisen jälkeen.
# Tarkoitus on asettaa muutama tieto käyttäjästä, jotta ne näkyvät
# muutoshistoriassa. 

# Asetetaan nimimerkki, jota käytetään muutoshistoriassa.
git config --global user.name "nimesi"

# Asetetaan sähköpostiosoite, jota käytetään muutoshistoriassa.
git config --global user.email "sähköpostiosoite"

# Voit tarkistaa asetukset, jos seuraava komento tulostaa antamasi tiedot.
git config --list | grep user
```

## Paikallisen tietovaraston kanssa työskentely

Gitin kanssa työskentely on melko yksinkertainen prosessi ja samat komennot toistuvat jatkuvasti. Tärkeää on enemmän tietää mitä on tekemässä. Kaikki usein alkaa paikallisesta työskentelystä mikä tarkoittaa sitä, että tehdään muutoksia lähdekoodiin ja vahvistetaan ne paikalliseen tietovarastoon.

Paikallinen työskentely voidaan jakaa seuraaviin pääasiallisiin kokonaisuuksiin: **tietovaraston luominen** ja **muutosten tekeminen**.

### Tietovaraston luominen

Tietovaraston luominen tarkoittaa toimenpidettä missä nykyinen työhakemisto alustetaan käyttämään versionhallintaa, tässä tapauksessa Gittiä. Työhakemiston alustaminen onnistuu alla olevalla komennolla.

Komennon jälkeen työhakemistoon luodaan piilotettu **.git** -kansio. Nyt voit käsitellä työhakemistoa miten olet tottunut eikä se vaikuta normaaliin työskentelyysi.

```bash
# Esimerkissä voidaan olettaa, että työhakemiston polku on:
# C:\repositoryt\GitHarjoitukset\

# Tietovaraston luominen työhakemistoon.
git init
```

{% hint style="info" %}
Tietovaraston luominen tehdään vain kerran. Ei joka kerta kun aloittaa työskentelyn. Jos työhakemistossa on jo **.git** kansio niin tätä vaihetta ei tarvitse tehdä.

Jos paikallinen tietovarasto on alunperin kopioitu etätietovarastosta niin silloinkaan tätä vaihetta ei tarvitse tehdä.

Huomaa myös, että **.git** -kansio on vain usein projektin juuressa. Tarkoittaa sitä, että työhakemistossa olevat alakansiot eivät sisällä piilotettua **.git** -kansiota.

Vältä komennon antamista tietojärjestelmän asemien juuressa, esimerkiksi Windowsissa C:\ -aseman juuressa. Tällöin Git alkaa seuraamaan kaikkia tiedostoja asemalta ja tällöin se ei toimi halutulla tapaa.
{% endhint %}

### Muutoksen tekeminen

Muutoksia tehdessä ne pitää vielä vahvistaa. Seuraavat alla olevat komennot havainnollistavat vaiheita, miten pysyvä muutos paikalliseen tietovarastoon saadaan aikaiseksi. Ohjelmoija toistaa näitä vaiheita jokapäiväisessä työssään jatkuvasti.

```bash
# Esimerkissä voidaan olettaa, että työhakemiston polku on:
# C:\repositoryt\GitHarjoitukset\

# Esimerkin vuoksi voidaan olettaa, että työhakemistoon on lisätty tätä 
# ennen tekstitiedosto "Program.txt", joka sisältää mitä tahansa tekstiä.
# C:\repositoryt\GitHarjoitukset\Program.txt

# Näytä tietovaraston tila
git status

# Lisää kaikki muutokset valmistelualueelle. (komennon lopussa on siis piste)
git add .

# Tee valmistelualueen muutoksista pysyviä nykyiseen kehityshaaraan. 
# Kehityshaara lukee esimerkiksi status -komennon tulosteessa mutta
# tässä kohdin se on nimeltään master.
git commit -m "Minun ensimmäinen commit"
```

Komentojen jälkeen sinulla pitäisi olla tehtynä uusi versio, joka näkyy muutoshistoriassa. Muutoshistoriaa voit katsoa seuraavalla komennolla, jossa sinun pitäisi nähdä tuorein muutoksesi antamasi viestin kera.

```bash
# Esimerkissä voidaan olettaa, että työhakemiston polku on:
# C:\repositoryt\GitHarjoitukset\

# Log komento näyttää muutoshistorian ja parametri -5 tarkoittaa,
# että näyttää edelliset 5 muutosta. Jos komentokehote menee eräänlaiseen
# lukutilaan eikä hyväksy muita painalluksia, paina Q kirjainta.
git log -5
```

{% hint style="info" %}
Esimerkin tilanne voidaan suorittaa myös seuraavalla yksittäisellä komennolla, jos varmasti halutaan kaikki nykyiset muutokset lisätä eikä ole tarvetta tarkistaa sisältöä.

`git commit -a -m "Minun ensimmäinen commit"`

Esimerkissä lisättiin kaikki tiedostot kun käytettiin pistettä. Yksittäisiä tiedostoja voidaan myös lisätä.

`git add Program.txt`
{% endhint %}

## Etätietovaraston kanssa työskentely

Gitin kanssa ei ole pakko käyttää etätietovarastoja mutta usein ne ovat mukana. Tämä voidaan myös jakaa muutamaan pääasialliseen kokonaisuuteen: **tietovaraston kopiointi, etätietovaraston viittauksien muutokset, muutosten työntäminen** ja **muutosten vetäminen.**

### Etätietovaraston kopiointi paikalliseen tietovarastoon

**Tämä vaihe tehdään vain kerran** siinä tilanteessa, että etätietovarasto on jo olemassa ja sitä ei ole nykyisellä työasemalla (työkoneella) olemassa vielä. Etätietovarasto on siis perustettu jo toisen henkilön toimesta.

```bash
# Esimerkissä voidaan olettaa, että työhakemiston polku on:
# C:\repositoryt\

# clone komento kopioi sille annetusta URL osoitteesta tietovaraston 
# paikalliseksi tietovarastoksi. Merkit < ja > eivät kuulu komentoon.
# Komennon antamisen jälkeen usein pitää tunnistautua riippuen käytettävästä
# palvelusta.
git clone <osoite git repositoryyn>

# Navigoi komennon jälkeen clone komennon luomaan kansioon.
# cd kansion_nimi
```

Kun etätietovarasto on kopioitu (kloonattu) niin `clone`  komento luo etätietovaraston mukaan nimisen kansion työhakemistoon. Se ei siis kopioi tietovarastoa nykyiseen työhakemistoon vaan luo sille alakansion.

{% hint style="info" %}
Clone kopiointi tekee useita vaiheita jo valmiiksi. Esimerkiksi sen jälkeen ei tule enää antaa `git init` komentoa tai tehdä muutoksia etätietovaraston viittaamiseen, koska ne on jo tehty.
{% endhint %}

### Etätietovarastoon viittaaminen paikallisessa tietovarastossa

**Tämä vaihe tehdään vain kerran siinä tilanteessa**, että etätietovarastoa ei kopioida (kloonata) vaan on kyseessä paikallinen tietovarasto. Tässä tilantessa usein halutaan kertoa mihin etätietovarastoon olemassaoleva paikallinen tietovarasto halutaan työntää.&#x20;

Muita tilanteita ovat esimerkiksi sellaiset, että paikallinen tietovarasto muutoshistorian kanssa halutaan työntää toiseen uuteen etätietovarastoon. Käyttötapauksia on monenlaisia.

```bash
# Esimerkissä voidaan olettaa, että työhakemiston polku on:
# C:\repositoryt\GitHarjoitukset\

# Anna työhakemistossa alla oleva komento, joka lisää viittauksen 
# etätietovarastoon. Origin on tässä vapaavalintainen etätietovaraston
# nimi, jota tarvitaan muutoksia työntäessä myöhemmin. Origin on aina
# usein oletuksena annettu nimi.
git remote add origin <osoite git repositoryyn>

# Tarkista komennon antamisen jälkeen, että näet lisätyn viittauksen 
# seuraavan komennon avulla.
git remote -v
```

### Muutosten työntäminen etätietovarastoon

Kun työskentelyssä on tultu siihen pisteeseen, että muutokset halutaan jakaa muiden kehittäjien kanssa tai muutoin talteen eri sijaintiin niin tarvitsee ne työntää (push) etätietovarastoon. Tätä vaihetta tehdään niin usein kun on tarve mutta usein päivän päätteeksi.

On hyvä huomioida, että edelliset komennot ovat pääasiassa käsitelleet paikallista tietovarastoa ja seuraavat komennot käsittelevät etätietovarastoa.

```bash
# Esimerkissä voidaan olettaa, että työhakemiston polku on:
# C:\repositoryt\GitHarjoitukset\

# Anna työhakemistossa alla oleva komento. Komento työntää paikallisessa
# tietovarastossa olevat uudet muutokset etätietovarastoon. Jos uusia ei 
# ole niin komento kertoo kaiken olevan ajantasalla. Origin on viittaus
# etätietovarastoon ja master on päähaara, jota tässä ollaan lisäämässä.
git push origin master
```

Yksinkertaisesti `push` komento työntää aina muutokset etätietovarastoon. Tämän jälkeen paikalliseen tietovarastoon voidaan tehdä lisää muutoksia ja työntää taas uudelleen kun halutaan.

{% hint style="danger" %}
Vältä käyttämästä `git push --force` komentoa. Komento yliajaa muutokset ja sillä tavoin Git -historia muuttuu. Usein johtaa uusiin ongelmiin.
{% endhint %}

### Muutosten työntämisen aikana tapahtuu virhe

Push komento voi tietyissä tilanteessa epäonnistua. Todennäköisin tilanne on se kun toinen henkilö on jo ehtinyt työntää uusia muutoksia etätietovarastoon, joita sinun paikallisessa tietovarastossa ei ole. Tässä tilanteessa muutokset pitää ensin vetää omaan tietovarastoon. Alla on kuvakaappaus siitä miltä tilanne näyttää komentokehotteessa käytettäessä Gitin komentoja.

![Git push virhe](/files/-LzWIDSCq7C7fM3DZ-c1)

Kuvakaappauksessa on ensin navigoitu **dev/saliavustaja/** hakemistoon, joka tässä tilanteessa on paikallinen tietovarasto. Paikalliseen tietovarastoon on tätä ennen tehty yksi muutos. Kun on annettu komento `git push origin master` niin tulostuu viesti **rejected** ja perustelut sille.&#x20;

Perustelut kannattaa lukea tarkkaan, koska siinä sanotaan suoraan olevan kyseessä tilanne, jossa joku toinen on jo tehnyt muutoksia etätietovarastoon, joita sinulla ei ole paikallisessa tietovarastossa. Tällöin tulisi tehdä `git pull` komento, joka vetää muutokset etätietovarastosta.&#x20;

### Muutosten vetäminen etätietovarastosta

Työskentelyyn saattaa usein liittyä useampi ohjelmoija, jotka tekevät muutoksia. Tuoreet muutokset pitää vetää (pull) etätietovarastosta paikalliseen tietovarastoon siinä tilanteessa kun pitää saada muiden muutokset työasemalle.&#x20;

```bash
# Esimerkissä voidaan olettaa, että työhakemiston polku on:
# C:\repositoryt\GitHarjoitukset\

# Anna työhakemistossa alla oleva komento. Komento vetää uusimmat muutokset
# etätietovarstosta, joita paikallisessa tietovarastossa ei ole.
# Pull komento tekee myös ns. mergen eli yhdistää ne paikallisen tietovaraston
# muutoshistoriaan.
git pull origin master
```

{% hint style="info" %}
Pull komento on hyvä tehdä aina ennen töiden aloittamista niin välttää monia ongelmatilanteita vanhentuneen lähdekoodin vuoksi.

Komento voi aiheuttaa myös niin sanotun konfliktin (conflict) tilanteen, jos vedettävät muutokset koskettavat sellaisia paikallisia muutoksia mitkä osuvat samoihin tiedostoihin ja lähdekoodin riveihin.
{% endhint %}

## Muut työskentelyyn liittyvät tilanteet

Versionhallintaa käytettäessä tulee vastaan joitakin tilanteita ja tarpeita mitä pitää osata selvittää. Nämä ovat hyvin perinteisiä ja kuuluvat melkein jokapäiväiseen työskentelyyn. Erilaiset työskentelytavat vaikuttavat myös näiden tilanteiden syntyyn.

Todennäköisesti ohjelmoijan pitää jossakin tilanteessa selvittää **Gitin konflikti** tai **merkitä tiedostoja, joita ei haluta versionhallinnan seuraavan**.&#x20;

### Konfliktin selvittäminen

Konflikti tarkoittaa Gitissä tilannetta, jossa työkalu ei pysty päättelemään muutoksista niitä, jotka pitäisi yhdistämisen aikana säästää. Yhdistämisellä tarkoitetaan tässä ns. ***merge*** tapahtumaa, joka on Gitin tapa yhdistää muutokset kahdesta eri kehityshaarasta.

Konflikti voi syntyä seuraavissa tilanteissa:

* Ohjelmoija on luonut uuden kehityshaaran ja yhdistää sen siihen mistä se on alunperin luotu.
* Ohjelmoija vetää etätietovarastosta muutoksia paikalliseen tietovarastoon mutta hänellä on muutoksia samoissa lähdekoodiriveissä kuin etätietovaraston tulevissa muutoksissa.

![Git konflikti pull komennon yhteydessä](/files/-LzWJiYF6QtXXEyA9eQd)

Konflikti näyttää ylläolevan kuvan kaltaiselta kun se tapahtuu käytettäessä `git pull` komentoa. Kuvassa paikallinen tietovarasto on **dev/saliavustaja/** -hakemistossa, jossa on yritetty vetää uusia muutoksia etätietovarastosta. Gitin tulosteessa on kohta **CONFLICT**, jossa kerrotaan perässä sen tapahtuneen README.md nimisessä tiedostossa. Lisäksi mainitaan, että automaattinen yhdistäminen (merge) on epäonnistunut ja konflikti pitää korjata.

Konflikti korjataan aina manuaalisesti eli ohjelmoija itse korjaa kyseisestä tiedostosta epäselvät rivit. Kun kuvan mukaisessa tilanteessa on tapahtunut konflikti, mitään muutoksia ei varsinaisesti vahvisteta paikallisessa tietovarastossa ennen niiden korjaamista. Jos et tiedä missä tilassa paikallinen tietovarasto on niin `git status` komento auttaa myös selvittämään mikäli on kyseessä konflikti.&#x20;

![Git konflikti status komennon näkökulmasta](/files/-LzWKxhxkPoTnlLghQ1Z)

Yllä olevassa kuvassa tuloste kertoo, että sinulla on konflikti. Tällöin kaksi kehityshaaran historiaa ei ole siis oikein yhdistyneet. Kohdassa **Unmerged paths** olevat tiedostot sinun tulee käydä läpi manuaalisesti. Jos konfliktia ei haluta tapahtuvan, voidaan antaa seuraava komento, joka peruu muutokset siihen tilaan kuin ne olivat ennen konfliktin syntymistä.

```bash
# Abort parametri peruu muutokset ja on hyödyllinen konflikti tilanteissa, 
# joka on tullut odottamatta. Usein kuitenkin konflikti on selvitettävissä
# suht helposti.
git merge --abort
```

Kuten edellä on jo mainittu, konflikti selvitetään itse. Kun konflikti on selvitetty, tulee se vielä vahvistaa `commit` komentoa käyttäen. Avaa konfliktin aiheuttanut tiedosto missä tahansa tekstieditorissa (esim. notepad, visual studio, komentokehotteesa). Monet ohjelmointiin tehdyt työkalut ymmärtävät konfliktitilanteita ja tarjoavat ohjelmoijalle vaihtoehdot miten toimia. Hyväksytäänkö paikalliset muutokset, etätietovaraston muutokset vai jokin näistä yhdistelmistä.

Seuraava kuva havainnollistaa tilannetta työkalun kanssa, joka ei ymmärrä konflikteja ja miltä se näyttää Gitin näkökulmasta.

![Git konflikti nano tekstieditorissa](/files/-LzWMotd-62MAKwGkwdf)

Tiedostossa, jossa on konflikti, tärkein asia on Gitin merkintätapa ja korjaus. Konfliktissa Git lisää lähdekoodiin seuraavanlaiset merkinnät:

```bash
<<<<<<< HEAD
[tässä kohdin voi olla useita rivejä lähdekoodia]
=======
[tässä kohdin voi olla useita rivejä lähdekoodia]
>>>>>>> [version sha tunniste (f138cb...]
```

Ohjelmoijan tulee siis siivoa lopputilanne siten, että poistaa `<<<<, ====, >>>` rivit ja lopputulos on halutun näköinen. Ensimmäinen HEAD osio tarkoittaa, että siinä on nykyiset paikallisessa tietovarastossa olevat muutokset. Yhtäsuuruus-merkkien jälkeen tuleva lohko tarkoittaa etätietovarastosta vedettyjä muutoksia. Muutoksia voi olla useita rivejä, että ohjelmoija voi siistiä lähdekoodin käyttämään vain toista lohkoa tai sitten yhdistellä muutoksia haluamansa tavan mukaisesti. **Lopuksi tallenna tiedosto** sekä **kokeile tietysti ohjelman toimivuus**, jos kyseessä on oikea ohjelma.

Kun konflikti-tiedostot on selvitetty, tee muutokset pysyviksi seuraavilla komennoilla.

```bash
# Lisää korjattu tiedosto valmistelualueelle. 
# (vaihtoehtoisesti myös muut mahdollisesti muutokset) 
git add README.md

# Vahvista muutokset.
git commit -m "Konflikti korjattu, onnistuin."
```

### Tiedostojen sivuuttaminen versionhallinnassa

Usein tulee tarpeita tiedostojen sivuuttamisen kanssa. Sivuuttamisella (ignore) tarkoitetaan tässä tilannetta, että tietyn tiedoston muutoksia ei huomioida versionhallinnan näkökulmasta. Se ei ole siis koskaan osa muutoshistoriaa. Useimmat tilanteet, joissa sivuuttamista tarvitaan, liittyvät työkalujen luomiin omiin konfiguraatio hakemistoihin tai kehittävän ohjelman paikallisiin asetuksiin. Tilanteita on useita erilaisia.

Esimerkiksi Visual Studio luo aina piilokansion **.vs** projektin yhteydessä. Sinne syntyvät kehittäjälle tarkoitettuja omia tiedostoja sekä ne muuttuvat aina kun Visual Studio esimerkiksi kääntää ohjelman. Usein tällaisia tietoja ei haluta versionhallinnan seurattavaksi, koska aiheuttavat konflikti-tilanteita ja niistä ei ole apua muille kehittäjille. Vain pelkkä lähdekoodi on usein se mitä halutaan pitää versionhallinnassa sekä sitten siihen liittyvät työkalujen projektitiedostot.

Tiedostojen tai hakemistojen merkitseminen sivuutetuksi tapahtuu **.gitignore** nimisellä tiedostolla. Git sisältää joitakin tällaisia piilotettuja tiedostoja, jolla voidaan vaikuttaa versionhallinnan ominaisuuksiin.&#x20;

{% hint style="info" %}
Edellä mainittu **.gitignore** pitää aina luoda itse, jos sitä ei ole ja sen pitää olla versionhallinnan seurattavana
{% endhint %}

Alla oleva kuva on esimerkki **.gitignore** tiedoston sisällöstä. Tiedoston jokainen rivi on eri sääntö, että mitä tiedostoja ei seurata. **Tiedoston sijaintina on usein paikallisen tietovaraston juuri eli juuri se työhakemisto, missä myös .git kansio sijaitsee**.

Kyseisiä tiedostoja voi olla myös alakansioissa mutta kyse on lähinnä mieltymyksestä miten sitä käyttää. Esimerkissä on paljon erilaisia **"villejä kortteja"** (eng. wildcards, eräänlaiset merkintätavat kuten \* jne.) ja muita merkintätapoja. Yksinkertaisimmillaan voit kirjoittaa vain tiedoston nimen tai hakemiston polun mitä et halua seurattavan.

Merkintätavoista voit lukea lisää esimerkiksi täältä <https://www.atlassian.com/git/tutorials/saving-changes/gitignore#git-ignore-patterns>&#x20;

Lisäksi löytyy jo paljon valmiita malleja olemassa oleviin työkaluihin. Niitä löydät täältä <https://github.com/github/gitignore>

Etsi listalta esimerkiksi Visual Studio ja kopioi tiedoston sisältä sinun omaasi **.gitignore** tiedostoon.

![Esimerkki git ignore tiedostosta, joka on tehty Visual Studiota varten](/files/-LzWTquRfgVuOVfbawgt)

{% hint style="info" %}
Huomioitavaa kun luot **.gitinore** tiedoston, muutoin se ei toimi:

* Tiedoston nimen pitää alkaa pisteellä ja siinä ei ole tiedostopäätettä. (windowsin notepad jättää usein .txt päätteen, joten silloin tiedosto ei toimi)
* Muista tallentaa tiedosto muutosten jälkeen.
* Tiedostopolku tai hakemiston nimi kirjoitettu väärin.
* Sivuutettava hakemisto tai tiedosto on aiemmin lisätty versionhallinnan seurattavaksi. Tällöin tiedosto pitää ensin poistaa versionhallinnan seurattavien tiedostojen piiristä.
  {% endhint %}

Jos tiedosto on aiemmin lisätty versionhallinnan seurantaan ja lisäät sen **.gitignore** tiedostoon, tiedoston sivuutus ei toimi heti. Käytä seuraavia komentoja poistamaan tiedosto ensin seurannasta ja vasta sitten **.gitignore** toimii halutusti.

```bash
# Poistaa tiedoston versionhallinnan seurannasta. Parametri --cached aiheuttaa
# sen, että tiedostoa ei poisteta työhakemistosta kokonaan vaan pelkästään
# käsitteleee versionhallinnan seurattavia tiedostoja.
git rm --cached <tiedosto>

# Tekee saman kuin yllä mutta annettu lisäksi -r parametri, joka tarkoittaa 
# rekursiivista poistamista. Tätä käytetään silloin kun kyseessä on jokin 
# hakemisto eikä yksittäinen tiedosto.
git rm -r --cached <hakemisto>
```

### Aiempaan muutokseen siirtyminen

Versionhallinnassa voidaan siirtyä aiempiin muutoksiin. Voit siis hyppiä muutosten välillä ja katsoa miltä lähdekoodi on kyseisessä tilanteessa näyttänyt. Tämä onnistuu seuraavasti.

```bash
# Etsi ensin haluttu commit id etätietävarastosta tai git log
# komentoa käyttäen. Esimerkiksi seuraava komento näyttää 
# edelliset viisi muutosta.
git log -5

# Commit id on pitkä merkkijono ja on muodoltaan seuraava:
# f138cb0b291021ec24ac505e57a1bbff4643ee42
# Checkout komennolla voit siirtyä haluttuun merkintään.
# Usein riitää kahdeksan ensimmäistä merkkiä tunnisteesta.
git checkout f138cb0b

# Takasin nykyiseen versioon pääset myös checkout komennolla.
# Jos esimerkiksi olit master kehityshaarassa niin seuraavalla
# komennolla pääset takaisin viimeisimpään muutokseen.
git checkout master

```

### Keskeneräisten muutosten kätkeminen

// TODO

Lue aiheesta täältä.

<https://www.atlassian.com/git/tutorials/saving-changes/git-stash>

## Kehityshaarat

Versionhallinnan yhtenä tärkeänä käsitteenä on kehityshaara (eng. branch). Kehityshaaralla tarkoitetaan ohjelman lähdekoodissa haarautunutta polkua, jossa kaksi eri kehityshaaraa eroavat. Niiden tarkoituksena on helpottaa yhden tai useamman henkilön työskentelyä saman ohjelman parissa. Git kanssa käytetään termiä kehityshaara ja esimerkissä käytämme sen englanninkielistä vastinetta **branch.** Puhekielessä puhutaan siis "**brancheista"**.

Käsitellään kehityshaarat vielä alla olevalla havainnollistavalla kuvalla. Kuvassa **harmaat ympyrät** ovat muutoksia (committeja). Ympyrän alla on osa sen uniikkia tunnistetta, joka syntyy aina `git commit` komennon yhteydessä.  Esimerkissä ei haittaa sisältääkö yksi commit yhden vai useamman tiedoston. **Vihreä ympyrä** kuvastaa sitä mikä on viimeisin muutos. **HEAD** on kuvassa viittaus viimeisimpään muutokseen. **Keltaiset laatikot** ovat kehityshaarojen nimiä. Kuvaa luetaan vasemmalta oikealle eli älä tulkitse nuolia väärin. Nuoli näyttää aina edelliseen muutokseen muutoshistoriassa.

![Esimerkki kahdesta kehityshaarasta.](/files/-MReK9qVsQlqclsOKTSC)

Tulkitaan kuva läpi yksi muutos kerrallaan käyttäen niiden tunnisteita apuna.

**e137a9b:** Tämä on ensimmäinen muutos ohjelman historiassa, joka on tehty master kehityshaaraan.

**ea57af0:** Toinen muutos ohjelmassa. Edelleen tehty master kehityshaaraan.

**a0ecd99 - 9aeaa06:** Ensimmäisenä mainittu on uusi muutos, joka on tehty kehityshaaraan nimeltä **feature-orders**. Tämän jälkeen siihen on tehty kolme muuta muutosta.

**996af37 - c7fd458:** Nämä kaksi mainittua muutosta on tehty olemassa olevaan **master** kehityshaaraan.

Seuraamalla nuolien mukaisesti oikealta vasemmalle mistä tahansa muutoksesta niin voidaan nähdä koko kyseisen kehityshaaran historia. Esimerkin kuvassa kaksi ensimmäistä muutosta ovat siis yhteisiä **master** ja **feature-orders** kehityshaaroille. Tämän jälkeen tulevat muutokset ovat vain olemassa toisessa näistä kehityshaaroista. Tämä tarkoittaa sitä, että ilman kehityshaarojen yhdistämistä muutokset säilyvät niissä erillään.

Kehityshaarat ovat siis juurikin versionhallinnan tekemää historiaa. Aina on olemassa vähintään yksi kehityshaara, joka on nimetty oletetusta **master** nimiseksi. Gitin `log` komennolla voit aina selata historiaa ja tarvittaessa nähdä kehityshaarat. On kuitenkin suositeltavaa, että käytät tarvittaessa työpöytäohjelmaa, joka visuaalisesti näyttää muutokset.

{% hint style="info" %}
Seuraavalla komennolla voit komentokehotteella nähdä kehityshaarojen muodostaman historian.

`git log --graph --decorate --oneline`
{% endhint %}

Tutustutaan tarkemmin kehityshaarojen kanssa työskentelyyn Gitin avulla. Oppimalla käyttämään kehityshaaroja helpotat monia asioita. Työskennelläsi voit luoda esimerkiksi kehityshaaran missä haluat vain kokeilla jotain uutta tapaa ratkaista ongelma tietämättä vielä haluatko säilyttää lopputulosta. Tällöin muutoksia ei ole tarvetta heti vielä **master** kehityshaaraan.

### Uuden kehityshaaran luominen

Ennen kuin voit luoda kehityshaaroja niin sinulla pitää olla tietovarasto (repository) mitä haluat käsitellä. Lähtökohtana oletetaan, että sinulla on olemassa vain **master** kehityshaara. Ei haittaa vaikka niitä olisi jo useampi.

Voit aina tarkistaa nykyisessä tietovarastossa olemassa olevat kehityshaarat seuraavalla komennolla:

```bash
# Listaa kehityshaarat
git branch

# Listaa vain etätietovaraston kehityshaarat
git branch -r

# Listaa kaikki kehityshaarat paikallisesta sekä etätietovarastosta.
git branch -a
```

Luodaan uusi kehityshaara. Huomioi, että sinulla pitää olla vähintään yksi aikaisempi muutos (commit) tehtynä. Muuten uuden branchin luominen ei onnistu.

```bash
# Komento luo uuden feature-orders nimisen kehityshaaran.
# Komento on muotoa: git branch <kehityshaaran-nimi>
git branch feature-orders
```

Kun olet luonut kehityshaaran, voit käyttää kehityshaaroja listaavia komentoja. Huomaa, että tähti kehityshaaran nimen edessä kertoo nykyisen valitun branchin. Nykyinen kehityshaara selviää myös `git status` komennolla, joka kertoo mikä on valittuna.

Kehityshaaran luominen tapahtuu esimerkissä sinun paikallisella koneella. Ne eivät näy etätietovarastossa, esimerkiksi Githubissa, jos sinulla on sellainen käytössä. Muutokset pitää sinne työntää erikseen.

{% hint style="info" %}
Kehityshaaran voi luoda mistä tahansa muutoksesta eli niitä ei ole pakko tehdä aina master kehityshaarasta alkaen.
{% endhint %}

### Kehityshaarojen välillä vaihtaminen

Uuden kehityshaaran jälkeen sinun pitää vaihtaa se aktiiviseksi. Aktiivinen kehityshaara tarkoittaa sitä, että kun annan `git commit` komennon niin muutokset merkitään siihen.

```bash
# Kehityshaarojen välillä vaihtaminen.
# git checkout <kehityshaaran-nimi>
git checkout feature-orders

# Jos haluat vaihtaa takaisin master kehityshaaraan niin komento on seuraava.
# Kokeile myös minkälaisen tekstin saat kun koitat vaihtaa kehityshaaraan, 
# jonka nimistä ei ole olemassa.
git checkout master
```

Kehityshaarojen vaihtamisen jälkeen voit työskennelllä normaalisti käyttäen `git add` ja `git commit` komentoja. Työskentely ei siis eroa **master** kehityshaaran käytöstä.

{% hint style="info" %}
On myös mahdollista käyttää uudempaa **switch** komentoa. Komento on luotu sen vuoksi, että **checkout** komento on alunperin monipuolinen ominaisuuksiltaan ja mahdollisesti aiheuttanut sekaannuksia.

`git switch <kehityshaaran-nimi>`&#x20;

Kehityshaaran voi luoda myös seuraavilla komennolla mikä välittömästi vaihtaa siihen.

`git checkout -b <kehityshaaran-nimi>`
{% endhint %}

### Kehityshaarojen yhdistäminen

Uuden kehityshaaran luomisen jälkeen tulee usein tarve yhdistää kaksi kehityshaaraa yhtenäiseksi. Git tarjoaa tähän helpon tavan ja huolehtii, että muutokset menevät oikein eri lähdetiedostoissa. Ominaisuutta kutsutaan termillä **merge**. Havainnollistetaan kehityshaarojen yhdistämistä seuraavalla kuvalla käyttäen taas muutosten tunnisteita.

![Esimerkki kahden kehityshaaran yhdistämisestä](/files/-MRe_HFcRngxrOXai_pu)

**ea57af0:** Vasemmalta toinen muutos. Tämä on viimeinen yhteinen muutos esimerkin kahdella kehityshaaralla. Tämän jälkeen seuraavat muutokset ovat eri kehityshaaroissa.

**a0ecd99 - 9aeaa06:** Muutokset ovat **feature-orders** kehityshaaraan tehtyjä ja niitä ei vielä ole **master** kehityshaarassa.

**508e807:** Kyseessä on muutosmerkintä, joka on tullut kehityshaarojen yhdistämisestä. Tässä on tapahtunut ns. **merge** ja sisältää kaikki **feature-orders** (a0ecd99 - 9aeaa06) kehityshaaran muutokset.

**8e5362e:** Muutos, joka on taas tehty master kehityshaaraan edellisen haarojen yhdistämisen jälkeen.

Käydään komentojen avulla läpi miten esimerkin tilanne on tapahtunut.

```bash
# Esimerkin kuvassa feature-orders haara on yhdistetty takaisin
# master haaraan. Tämä tarkoittaa sitä, että aktiivisena 
# kehityshaarana on aluksi ollut masters. Vaihdetaan tarvittaessa
# siihen.
git checkout master

# Haaran yhdistäminen onnistuu merge komennolla.
# git merge <kehityshaaran-nimi>
git merge --no-ff feature-orders

# Yllä oleva --no-ff parametri ei ole pakollinen. Parametri on kuitenkin
# hyödyllinen siitä syystä, että se luo erillinen muutosmerkinnän
# haarojen yhdistämisestä. Näin on helpompi myöhemmin nähdä historiasta
# kohdat, joissa yhdistäminen on tapahtunut.
```

{% hint style="warning" %}
Merge komennon yhteydessä on mahdollista, että syntyy konflikti. Sen selvittämiseen toimivat jo aiemmin mainitut tavat. Katso oppaasta kohta **Konfliktin selvittäminen.**
{% endhint %}

Kehityshaarojen yhdistämisen jälkeen yhdistetty haara ei katoa. Esimerkissä feature-orders jää olemaan ellei sitä erikseen poisteta. Poistaminen on käsitelty tässä oppaassa myöhemmin.

### Kehityshaarojen käsitteleminen etätietovarastossa

Ohjelmoidessa tulee vastaan tilanne, että muutokset halutaan työntää etätietovarastoon. Käsitellään tilanne kehityshaarojen kanssa. Samoin myös tietojen päivittäminen voi tulla ajankohtaiseksi useamman ohjelmoijan kohdalla.&#x20;

Muutosten käsittely etätietovaraston kanssa onnistuu jo aiemmin kuvatulla tavalla mutta käydään tässä vielä esimerkin mukaiset komennot läpi.

```bash
# Kehityshaaran työntäminen etätietovarastoon. Seuraava komento toimii
# tietoja päivittäessä mutta myös uuden kehityshaaran työntämisessä.
# Ei haittaa siis vaikka kehityshaaraa ei ole etätietovarastossa.
git push origin feature-orders

# Vastaavasti uudet muutokset etätietovarastosta voidaan hakea.
git pull origin feature-orders

# Edellä mainitut komennot toimivat samalla tapaa kuin master 
# kehityshaaran kohdalla. Jälleen kerran pull komennon aikana voi
# syntyä mahdollinen konflikti tilanne.
```

Etätietovaraston kautta voit myös nähdä sinne työnnetyt kehityshaarat ja niiden historian. Alla oleva kuva esittää mistä tieto kehityshaaroista löytyy Githubin kohdalla. Ulkoasu vaihtelee aina eri palveluissa, joten ota tarvittaessa selvää näistä ominaisuuksista.

![Github palvelussa olevat branchit](/files/-MRen9whSfeMH75ER69Y)

Lähtökohta voi olla myös toinen. Käydään vielä läpi esimerkki, jossa kehityshaaraa ei ole omalla paikallisessa tietovarastossa vaan pelkästään etätietovarastossa. Tilanteena voisi olla, että toinen ohjelmoija on sen luonut ja laittanut etätietovarastoon.

```bash
# Luodaan etätietovarastossa olevasta kehityshaarasta paikallinen
# versio. Komento on muotoa: 
# git fetch origin <kehityshaaran-nimi>:<kehityshaaran-nimi>
git fetch origin feature-orders:feature-orders

# Tämän jälkeen voidaan vielä vaihtaa äskettäin haettuun kehityshaaraan.
git checkout feature-orders

# Tämän jälkeen voidaan taas työskennellä normaaliin tapaan. Push ja
# pull komennot toimivat tämän jälkeen. Fetch komentoa ei tarvitse
# enää sellaisenaan käyttää.
```

### Kehityshaaran poistaminen

Kehityshaara voi jäädä turhaksi monesta syystä. Syitä voivat olla esimerkiksi:

* Kehityshaaran yhdistäminen ja siihen ei enää haluta tehdä muutoksia.
* Kehityshaarassa on kokeiltu uusia asioita mutta niitä ei haluta yhdistää muun historian kanssa.
* Kehityshaara jää muusta syystä käyttämättömäksi.

Kehityshaaran poistamisen jälkeen sitä ei saa enää takaisin. Jos siis kehityshaaraa ei ole yhdistety siihen kehityshaaraan, josta se on alunperin luotu niin muutokset eivät säily. Git osaa huomauttaa tällaisesta tilanteesta. Mikäli kehityshaara on taas yhdistetty toiseen niin silloin siinä olleet muutokset säilyvät.

```bash
# Voit ensin tarkistaa mitä kehityshaaroja sinulla on paikallisella
# tietovarastolla. Muista myös katsoa mikä on nykyinen aktiivinen
# kehityshaara, että se ei ole sama mitä olet poistamassa.
git branch

# Komento poistaa kehityshaaran, jos se on yhdistetty siihen kehityshaaraan,
# josta se on alunperin luotu ja yhdistämisen jälkeen siihen ei ole tullut
# uusia muutoksia.
git branch -d feature-orders

# Edellinen komento antaa ilmoituksen, jos kehityshaaraa ei ole yhdistetty vielä.
# Näin vahingossa ei poistu mistään. Voit kuitenkin kiertää tämän ja silti
# poistaa kehityshaaran käyttämällä -D parametria. Tällöin sinun pitää
# vain itse huolehtia, että olet tarkoituksenmukaisesti poistamassa haaran.
git branch -D feature-orders

# Edelliset komennot poistavat kehityshaaran vain paikallisesti. Jos haluat
# poistaa sen vielä etätietovarastosta niin se onnistuu seuraavalla komennolla.
# Joskus voi olla kuitenkin tarpeen säilyttää kehityshaaroja etätietovarastoissa
# ja poistaa niitä vain paikallisesta tietotavastosta.
git push -d origin feature-orders
```

## Lähteet

{% embed url="<https://git-scm.com/>" %}

{% embed url="<https://fi.wikipedia.org/wiki/Versiohallinta>" %}

{% embed url="<https://git-scm.com/book/en/v2>" %}


# Git perusteet 101

{% hint style="warning" %}
Komennoissa on virheitä kun ne on siirretty tekstiin. Huomaa, että osa komennoista ei siis kopioimalla toimi. Yksittäisten väliviivojen tilalle voi tulla kaksi väliviivaa tai niiden edestä puuttuu tyhjä välilyönti.

Komennot kannattaa silti vielä kirjoittaa, koska kopioidessa joskus väliviivat eivät kopioidu oikein.
{% endhint %}

**Asenna Git tietokoneellesi**

Asentamisen jälkeen anna komento `git --version` ja ota kuvakaappaus.

#### Konfiguroi Git ensimmäistä käyttökertaa varten <a href="#konfiguroi-git-ensimm-c3-a4ist-c3-a4-k-c3-a4ytt-c3-b6kertaa-varten" id="konfiguroi-git-ensimm-c3-a4ist-c3-a4-k-c3-a4ytt-c3-b6kertaa-varten"></a>

Konfiguroinnin jälkeen anna komento `git config --list` ja ota kuvakaappaus.

#### Luo uusi paikallinentietovarastoja ensimmäisen pysyvän muutoksen tekeminen <a href="#luo-uusi-paikallinentietovarastoja-ensimm-c3-a4isen-pysyv-c3-a4n-muutoksen-tekeminen" id="luo-uusi-paikallinentietovarastoja-ensimm-c3-a4isen-pysyv-c3-a4n-muutoksen-tekeminen"></a>

Tietovaraston luonnin jälkeen lisää muutama tiedosto versionhallinnan jäljitettäväksi ja sen jälkeen tee muutoksista pysyviä. Anna tämän jälkeen komento `git log --stat` ja ota kuvakaappaus.

#### Luo paikallinen tietovarasto olemassa olevasta etätietovarastosta <a href="#luo-paikallinen-tietovarasto-olemassa-olevasta-et-c3-a4tietovarastosta" id="luo-paikallinen-tietovarasto-olemassa-olevasta-et-c3-a4tietovarastosta"></a>

Luo paikallinen kopio seuraavasta julkisesta tietovarastosta: <https://github.com/nyluntu/hacksummit-forecast>

Tämän jälkeen anna komento `git remote –v` ja ota kuvakaappaus.

#### Nykyisten muutosten tarkistaminen ennen pysyvän muutoksen tekemistä <a href="#nykyisten-muutosten-tarkistaminen-ennen-pysyv-c3-a4n-muutoksen-tekemist-c3-a4" id="nykyisten-muutosten-tarkistaminen-ennen-pysyv-c3-a4n-muutoksen-tekemist-c3-a4"></a>

Mieti millä komennolla näet mitkä tiedostot ovat uusia, poistettuja tai lisätty versionhallinnan jäljitettäväksi, joissa on muutoksia. Tämän jälkeen anna kyseinen Git komento ja ota kuvakaappaus. Kuvakaappauksessa tulisi vähintään näkyä uusi lisätty tiedosto ja yksi tulevaan pysyvään muutokseen lisätty muutos tai jäljitettävä tiedosto.

#### Millä komennolla saat lisättyä nykyisestä työkansiosta kaikki muutokset tulevaan pysyvään muutokseen, jos tiedostoja on useampi kuin yksi? <a href="#mill-c3-a4-komennolla-saat-lis-c3-a4tty-c3-a4-nykyisest-c3-a4-ty-c3-b6kansiosta-kaikki-muutokset-tul" id="mill-c3-a4-komennolla-saat-lis-c3-a4tty-c3-a4-nykyisest-c3-a4-ty-c3-b6kansiosta-kaikki-muutokset-tul"></a>

Kerro tähän vaadittavat komennot tai anna muu selitys mitä tulisi tehdä.

#### Mitä `git commit` komento tekee? <a href="#mit-c3-a4-git-commit-komento-tekee" id="mit-c3-a4-git-commit-komento-tekee"></a>

Kerro vapaamuotoisesti mitä commit–komento tekee käytännössä?

#### Miten sivuutan tiedostot, joiden muutoksia en halua jäljitettävän? <a href="#miten-sivuutan-tiedostot-joiden-muutoksia-en-halua-j-c3-a4ljitett-c3-a4v-c3-a4n" id="miten-sivuutan-tiedostot-joiden-muutoksia-en-halua-j-c3-a4ljitett-c3-a4v-c3-a4n"></a>

Kerro miten sivuutus tapahtuu ja miksi käyttäisit tällaista ominaisuutta? Tarvittaessa ota kuvakaappaus perustelun tueksi.

#### Tulevien pysyvien muutosten peruuttaminen <a href="#tulevien-pysyvien-muutosten-peruuttaminen" id="tulevien-pysyvien-muutosten-peruuttaminen"></a>

Millä komennolla voit peruuttaa jo valmistellut tiedostot tulevaan pysyvään muutokseen?

Eli olet esimerkiksi muuttanut tiedostoa tai lisännyt uuden jäljitettäväksi mutta huomaat, ettet haluakaan ottaa uutta tiedostoa mukaan seuraavaan pysyvään muutokseen. Muutos on siis jo tässä kohdin **staged** tilassa.

Miten siis peruuttaisit tulevan muutokset, että saat osan tiedostoista pois **staged** tilasta?

Kerro tarvittavat komennot ja ota myös `git status`–komentoa käyttäen pari kuvakaappausta ennen ja jälkeen tilanteen.

#### Mitä tekee `git mv` –komento? <a href="#mit-c3-a4-tekee-git-mv-e2-80-93komento" id="mit-c3-a4-tekee-git-mv-e2-80-93komento"></a>

Kerro mitä otsikossa mainittu komento tekee ja miksi käyttäisit tai et käyttäisi sitä?

#### Mitä tekee `git rm` –komento? <a href="#mit-c3-a4-tekee-git-rm-e2-80-93komento" id="mit-c3-a4-tekee-git-rm-e2-80-93komento"></a>

Kerro mitä otsikossa mainittu komento tekee ja miksi käyttäisit tai et käyttäisi sitä?

#### Luo oma etätietovarasto ja työnnä sinne muutoksesi <a href="#luo-oma-et-c3-a4tietovarasto-ja-ty-c3-b6nn-c3-a4-sinne-muutoksesi" id="luo-oma-et-c3-a4tietovarasto-ja-ty-c3-b6nn-c3-a4-sinne-muutoksesi"></a>

Voit luoda etätietovaraston haluamaasi palveluun. Kun olet muutokset työntänyt tietovarastoon, ota kuva palvelun Git historia-näkymästä sekä sinun paikallisesta historiasta komennolla `git log -10 --oneline`


# Git perusteet 102

{% hint style="warning" %}
Komennoissa on virheitä kun ne on siirretty tekstiin. Huomaa, että osa komennoista ei siis kopioimalla toimi. Yksittäisten väliviivojen tilalle voi tulla kaksi väliviivaa tai niiden edestä puuttuu tyhjä välilyönti.

Komennot kannattaa silti vielä kirjoittaa, koska kopioidessa joskus väliviivat eivät kopioidu oikein.
{% endhint %}

**Etätietovaraston viittauksien lisääminen ja poistaminen**

Miten voit lisätä ja poistaa viittauksia etätietovarastoihin?

Paikallinen tietovarasto osoittaa useimmiten myös yhteen etätietovarastooon, jos lähdekoodit jaetaan muiden kehittäjien kanssa.

Millä komennoilla näiden osoitteiden ja viittausten hallinta onnistuu, kun ei käytetä `git clone` –komentoa?

Anna lopuksi komento `git remote -v` ja ota kuvakaappaus, josta näkyy vähintään kaksi eri viittausta etätietovarastoon.

#### Etätietovaraston kehityshaaran hakeminen paikalliseen tietovarastoon <a href="#et-c3-a4tietovaraston-kehityshaaran-hakeminen-paikalliseen-tietovarastoon" id="et-c3-a4tietovaraston-kehityshaaran-hakeminen-paikalliseen-tietovarastoon"></a>

Millä komennoilla saat haettua etätietovarastosta erillisen kehityshaaran paikalliseen tietovarastoon?

Kehityshaara ei saa olla siis `master` –kehityshaara vaan jokin muu. Kehityshaara tulee hakea omaan paikalliseen kehityshaaraan ilman, että tapahtuu ns. `merge`.

Kerro vaadittavat komennot ja kuvaile mitä ne tekevät.

#### Etätietovaraston kehityshaaran hakeminen paikalliseen tietovarastoon vetämällä muutokset <a href="#et-c3-a4tietovaraston-kehityshaaran-hakeminen-paikalliseen-tietovarastoon-vet-c3-a4m-c3-a4ll-c3-a4-m" id="et-c3-a4tietovaraston-kehityshaaran-hakeminen-paikalliseen-tietovarastoon-vet-c3-a4m-c3-a4ll-c3-a4-m"></a>

Kysymys on sama kuin edellinen mutta nyt `merge` –tapahtuma saa tapahtua samalla. Kehityshaaran on oltava jokin muu kuin `master` –kehityshaara.

Kerro vaadittavat komennot ja kuvaile mitä ne tekevät.

#### Paikallisten tietovaraston `master` -kehityshaaran työntäminen etätietovarastoon <a href="#paikallisten-tietovaraston-master-kehityshaaran-ty-c3-b6nt-c3-a4minen-et-c3-a4tietovarastoon" id="paikallisten-tietovaraston-master-kehityshaaran-ty-c3-b6nt-c3-a4minen-et-c3-a4tietovarastoon"></a>

Kerro millä komennoilla saat työnnettyä paikallisessa tietovarastossa olevan master-kehityshaaran etätietovarastoon, kun olet ensin siihen tehnyt muutoksia?

#### Paikallisen tietovaraston kehityshaaran tai `tagin` työntäminen etätietovarastoon <a href="#paikallisen-tietovaraston-kehityshaaran-tai-tagin-ty-c3-b6nt-c3-a4minen-et-c3-a4tietovarastoon" id="paikallisen-tietovaraston-kehityshaaran-tai-tagin-ty-c3-b6nt-c3-a4minen-et-c3-a4tietovarastoon"></a>

Sama idea kuin edellisessä mutta kehityshaaran pitää olla jokin muu kuin master–kehityshaara. Ota kuvakaappaus etätietovarastosta, jossa tämä kehityshaara näkyy. Ota kuvakaappaus etätietovarastosta, josta näkyy sinne merkitty `tag`–merkintä.


# Git perusteet 103

{% hint style="warning" %}
Komennoissa on virheitä kun ne on siirretty tekstiin. Huomaa, että osa komennoista ei siis kopioimalla toimi. Yksittäisten väliviivojen tilalle voi tulla kaksi väliviivaa tai niiden edestä puuttuu tyhjä välilyönti.&#x20;

Komennot kannattaa silti vielä kirjoittaa, koska kopioidessa joskus väliviivat eivät kopioidu oikein.
{% endhint %}

**Luo uusi kehityshaara paikalliseen tietovarastoon**

Kerro millä eri tavoin voit luoda haaroja paikallisessa tietovarastossa? Kerro tarvittavat komennot ja anna lopuksi seuraava komento

`git log --graph --pretty=oneline --abbrev-commit`

Ota komennon antamasta tulosteesta kuva, jossa näkyy luotu kehityshaara. Huomioi, että sinun pitää tehdä kehityshaaraan vähintään yksi pysyvä muutos.

#### Kehityshaarojen tarkastelu <a href="#kehityshaarojen-tarkastelu" id="kehityshaarojen-tarkastelu"></a>

Kerro millä komennoilla voit nähdä paikallisen tietovaraston tai etätietovarastojen kehityshaaroja?

Ota lopuksi kuvakaappaus paikallisessa tietovarastossa olevista kehityshaaroista. Kehityshaaroja pitää olla useampi kuin kaksi.

#### Kehityshaarojen yhdistäminen <a href="#kehityshaarojen-yhdist-c3-a4minen" id="kehityshaarojen-yhdist-c3-a4minen"></a>

Kerro millä komennoilla voit yhdistää kehityshaaroja paikallisessa tietovarastossa?

Ota lopuksi kuvakaappaus käyttäen seuraavaa komentoa

`git log --graph --pretty=oneline --abbrev-commit`

#### Kehityshaaran uudelleenkirjoittaminen (rebase) <a href="#kehityshaaran-uudelleenkirjoittaminen-rebase" id="kehityshaaran-uudelleenkirjoittaminen-rebase"></a>

Kerro mitä `git rebase` komennolla voi tehdä?

#### Kehityshaarojen poistaminen <a href="#kehityshaarojen-poistaminen" id="kehityshaarojen-poistaminen"></a>

Kerro millä komennoilla voit poistaa kehityshaaroja?

Ota kuvakaappaus ennen ja jälkeen toimenpiteen kehityshaarojen listauksesta, josta näkyy tarvittavat muutokset tietovarastossa.

#### `Tag`–merkinnät <a href="#tag-e2-80-93merkinn-c3-a4t" id="tag-e2-80-93merkinn-c3-a4t"></a>

Kerro mitä ovat `tag` –merkinnät tietovarastossa ja missä tilanteessa käyttäisit niitä?


# Git perusteet 104

{% hint style="warning" %}
Komennoissa on virheitä kun ne on siirretty tekstiin. Huomaa, että osa komennoista ei siis kopioimalla toimi. Yksittäisten väliviivojen tilalle voi tulla kaksi väliviivaa tai niiden edestä puuttuu tyhjä välilyönti.

Komennot kannattaa silti vielä kirjoittaa, koska kopioidessa joskus väliviivat eivät kopioidu oikein.
{% endhint %}

#### Git login tarkastelu <a href="#git-login-tarkastelu" id="git-login-tarkastelu"></a>

Git sisältää tehokkaan `git log` komennon.

Kerro miten saat komennon avulla listattua edellisen 1 viikon aikana tehdyt pysyvät muutokset?

`log` komentoa on käytetty jo aikaisemmin, joten tutustu sen parametreihin ja myös muihin vaihtoehtoihin.

#### Muutosten tarkastelu eri versioiden välillä <a href="#muutosten-tarkastelu-eri-versioiden-v-c3-a4lill-c3-a4" id="muutosten-tarkastelu-eri-versioiden-v-c3-a4lill-c3-a4"></a>

Kerro millä komennolla voit nähdä yhden tiedoston muutokset sen edelliseen versioon verrattaessa?

Tai millä komennolla voit nähdä kaikki muutokset edelliseen loki merkintään verrattaessa?

#### Konfliktien hallinta ja selviytyminen <a href="#konfliktien-hallinta-ja-selviytyminen" id="konfliktien-hallinta-ja-selviytyminen"></a>

Yritä saada aikaiseksi Git konflikti.

Kerro mitä konflikti tarkoittaa ja miten siitä voi selvitä?

Miten Git–merkitsee konfliktitilanteen?

#### Muutosten piilottaminen väliaikaisesti <a href="#muutosten-piilottaminen-v-c3-a4liaikaisesti" id="muutosten-piilottaminen-v-c3-a4liaikaisesti"></a>

Millä komennolla voit piilottaa nykyiset muutokset väliaikaisesti ja palata jatkamaan myöhemmin?

Tämä tulee tehdä ilman `git commit`–komentoa. Esimerkiksi sinulla voi olla tilanne, jossa olet tehnyt muutoksia `master`–kehityshaaraan ja olet vetämässä etätietovarastosta muutoksia. Et tahdo tehdä ylimääräistä pysyvää muutosta mutta tahdot väliaikaisesti piilottaa muutokset, vetää etätietovaraston päivitetyn version ja sen jälkeen tuoda takaisin muutokset siihen tilaan missä alun perin olit.

#### Tutustu graafiseen Git–työkaluun <a href="#tutustu-graafiseen-git-e2-80-93ty-c3-b6kaluun" id="tutustu-graafiseen-git-e2-80-93ty-c3-b6kaluun"></a>

Git–versionhallintaa ei tarvitse aina käyttää komentojen avulla. Tutustu yhteen monista graafisista työkaluista ja tee sillä muutamia aikaisemmin läpikäytyjä komentoja. Työkalu voi olla myös integroitu IDE –ohjelmistoon. Ota lopuksi pari kuvakaappausta todisteeksi, että näin on tapahtunut ja olet tutustunut vähintään yhteen työkaluun.

Suosituimpia graafisia käyttöliittymiä versionhallinnan käyttöön on listattu seuraavassa osoitteessa, joista voit hyvin valita sopivimman. <https://acodez.in/git-gui-clients/>

Jos käytät esimerkiksi Visual Studiota työkaluna niin kannattaa tutustua sen versionhallintaominaisuuksiin.

Mac: <https://docs.microsoft.com/en-us/visualstudio/mac/version-control?view=vsmac-2019> Windows: <https://docs.microsoft.com/en-us/azure/devops/repos/git/gitquickstart?view=azure-devops&tabs=visual-studio>


# Git perusteet 105

#### Git perusteet tositoimissa <a href="#git-perusteet-tositoimissa" id="git-perusteet-tositoimissa"></a>

Aikaisemmin olet käynyt läpi useita erilaisia komentoja. Tällä tasolla ei ole enää yksittäisiä tehtäviä vaan nyt sinun pitää näyttää osaaminen. Moduulin aikana on erilaisia projekteja ja harjoitustehtäviä, joita voit käyttää tämän tukena. Voit myös käyttää omaa henkilökohtaista projektia, jos haluat. Tärkeintä on kuitenkin, että hyödynnät versionhallintaa mahdollisimman paljon ja teet useita pysyviä muutoksia tietovarastoon, josta jää muutos historia näkyville. Tämän jälkeen palauta tähän linkki etätietovarastoon, jonka haluat arvosteltavan. Huomioi, että etätietovaraston pitää olla julkinen tai muuten käyttöoikeudet kunnossa, että siihen pääsee teeman ohjaaja käsiksi.


# Git perusteet 106

Tavoitteena on oppia tekemään ensimmäinen merkintä versionhallintaan.

## Tavoite

Tehtävän tavoitteena on tehdä ensimmäisiä merkintöjä (commit) versionhallintaohjelmalla.

Omalla paikallisella koneellasi, tee sellainen harjoite, jossa sinulla on vähintään 10 merkintää Git lokissa.

Ota kuva lopputuloksesta seuraavalla komennolla:

```bash
git log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
```

```
# Jos haluat edellisen komennon ns. pikakomennoksi niin voit antaa myös seuraavan version komennosta.
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

# Tämän jälkeen riittää aina seuraava komento.
git lg
```

## Huomioi tehdessä seuraavat asiat

* Aloita tyhjällä Git projektilla. Älä kopioi sitä alkuun mistään.
* Lokista otetussa kuvassa pitää näkyä tekijän nimi. Jos näin ei ole, tee asetukset Gittiin kuntoon.
* Kun teet muutoksen, tee selkeä muutos lähdekoodiin. Tee siis jokin tuttu harjoitus uudelleen.
* Käytä esimerkin kanssa oikeaa projektipohjaa. Esimerkiksi konsoliprojekti Visual Studiossa. Ei yksittäisiä tekstitiedostoja missä ei ole mitään tarkoitusperää.
* Huomioi "commit" viestien kirjoitusasu.
* Mitä komentoja jouduit käyttämään, jotta pääsit tavoitteeseen?
* Mitä "commit" viesteissä kuuluisi lukea?
* Kokeile antaa komento `git commit -m "anna tähän viestisi"`
* Kokeile myös komentoa `git commit` ilman muita parametrejä. Mitä tapahtui ja kuinka selvitit tilanteen?


# Git perusteet 107

Tavoitteena on saada koko kehitystiimiltä ensimmäiset merkinnät versiohallintaan.

## Tavoite

{% hint style="info" %}
Suorita ensin [Git perusteet 106](/versionhallinta/git-perusteet-106)
{% endhint %}

Tehtävä tulee suorittaa usean henkilön kanssa. Yksittäin suoritusta ei voi tehdä. Tavoitteena on oppia hyödyntämään Git versionhallintaa kehitystiimin kanssa.

Ennen suoritusta sinulla pitää olla tehtynä Gitlab -tunnus. <https://gitlab.com/>

Ensimmäiseksi kehitystiimin kanssa, luokaa ensin yksi uusi yhteinen projekti Gitlabiin. Jakakaa käyttöoikeudet kaikille kehitystiimin jäsenille. Nyt yksi ryhmän jäsenistä työntää Gitlab repositoryyn ensimmäiset lähdekoodinsa. Voit käyttää \*Git perusteet 106\* tekemääsi esimerkkiä.

Seuraavana vaiheena muiden kehitystiimissä olevien kehittäjien on tarkoitus kloonata Gitlabissa oleva ohjelma omalle koneelleen.

Kolmantena vaiheena kaikki kehitystiimin jäsenet tekevät muutoksia lähdekoodeihin ja tekevät niistä merkintöjä versionhallintaan.

Neljäntenä vaiheena kehitystiimin jäsenet työntävät uudet muutokset Gitlab projektiin. Tämän seurauksena kaikkien tulee myös huolehtia, että muiden muutokset tulevat vedetyksi omaan paikalliseen repositoryyn.

Lopputuloksena jokaisella kehitystiimillä on paikallisessa repositoryssä sama versionhallinnan muutoshistoria kuin muilla kehitystiimin jäsenillä. Lisäksi Gitlabissa on sama historia näkyvillä.

Ota kuvakaappaus jokaisesta kehitystiimin jäsenen historiasta sekä Gitlabin historiasta.

## Huomioi tehdessä seuraavat asiat

* Mitä komentoja sinun tuli käyttää päästäksesi lopputulokseen?
* Mitä ongelmakohtia tuli vastaan, jotka jouduitte selvittämään?
* Sattuiko teille vastaan ns. "merge conflict"? Jos kyllä, miten selvititte tämän?
* Käytä esimerkin kanssa oikeaa projektipohjaa. Esimerkiksi konsoliprojekti Visual Studiossa. Ei yksittäisiä tekstitiedostoja missä ei ole mitään tarkoitusperää.


# Git perusteet 108

Tavoitteena on ymmärtää mikä on merge conflict ja miten sellainen selvitetään.

## Tavoite

{% hint style="info" %}
Suorita ensin [Git perusteet 107](/versionhallinta/git-harjoitus-107)
{% endhint %}

Aiheuttakaa kehitystiimin kanssa niin sanottu **merge conflict** tilanne. Selvittäkää kyseinen tilanne. Jokaisen kehitystiimin jäsenen tulee selvittää konflikti.

Käyttäkää pohjana edellisessä harjoituksessa ollutta Gitlab projektia.

Lopputuloksena, ottakaa Gitlabista kuvakaappaus versionhallinnan historiasta, josta näkyy, että konflikteja on selvitetty. (kun selvitätte konfliktin, nimetkää commit viesti sen mukaisesti)

Kehitystiimin tulee osata vastata seuraaviin kysymyksiin kun ne heiltä kysytään:

* Mikä on konflikti tilanne?
* Miksi konflikti tilanne syntyy?
* Miten konflikti tilanne voidaan selvittää? (tähän on useita tapoja selvittää)
* Millä toimintatavoilla konfliktitilanteita voidaan välttää?


# Git muu materiaali ja lähteet

{% embed url="<https://git-scm.com/book/en/v2>" %}

{% embed url="<https://www.atlassian.com/git>" %}

{% embed url="<https://learngitbranching.js.org/>" %}

{% embed url="<https://try.github.io/levels/1/challenges/1>" %}

{% embed url="<https://blog.prototypr.io/git-for-beginners-12-commands-you-need-to-know-e084cce9cc94>" %}

{% embed url="<https://medium.com/@christo8989/what-college-students-should-learn-about-git-6bbf6eaac39c>" %}

{% embed url="<http://rogerdudler.github.io/git-guide/>" %}

Suurinpiirtein osaa gitin perusteet kun seuraava alkaa naurattaa: <https://www.youtube.com/watch?v=CDeG4S-mJts>

### Sekalaista

{% embed url="<https://stackoverflow.com/questions/10564/how-can-i-set-up-an-editor-to-work-with-git-on-windows>" %}

{% embed url="<https://stackoverflow.com/questions/7527982/applying-gitignore-to-committed-files>" %}


# Ohjelmistotestauksen periaateet

Alla olevassa soittolistalla on käsitelty aihetta. Katso soittolistan videot aihealueen tutustumisen vuoksi.

Jos koko soittolista ei näy niin avaa video Youtubessa.

{% embed url="<https://www.youtube.com/playlist?list=PL3iay_FdAzV-T2Q8hso3sC-XDjAXYFF-X>" %}


# NUnit lisääminen VS2019

Alla kuvasarja Visual Studio 2019 työkalusta ja kuinka luoda siinä pohja testiprojektille. Lue kuvien sisällöt niin onnistut. Älä välitä kuvissa näkyvästä **käyttötilanteiden tallentimesta**, joka on lähinnä ohjelma joka kuvat on ottanut.

### Kuva 1. Luo ensin uusi Console App -projekti.

{% hint style="info" %}
Ei ole merkitystä, valitsetko projektityypin jossa lukee **.NET Core** tai **.NET Framework** kunhan on vain C# projekti.
{% endhint %}

![](/files/-LzcUpAir62oi93plspE)

### Kuva 2. Klikkaa hiiren oikealla Solution tiedoston päällä ja valitse Add > New Project

![](/files/-LzcUpAjZ0vfQE7K0AzM)

### Kuva 3. Valitse NUnit Test Project -projetityyppi

{% hint style="info" %}
Muista valita samanlainen projektityyppi kuin alussa eli **.NET Core** tai **.NET Framework**.
{% endhint %}

![](/files/-LzcUpAkYoAwzH3TKKYJ)

### Kuva 4. Nimeä ohjelma samoin kuin ensimmäinen projekti mutta lisää nimen loppuun Tests

![](/files/-LzcUpAYhDRDfbVJ_mCY)

### Kuva 5. Sinulla pitäisi olla kuvan Solution Explorer ikkunan mukaisesti kaksi eri projektia.&#x20;

![](/files/-LzcUpAdgYPwuM75UJCs)

### Kuva 6. Valitse "Test" valikosta "Test Explorer" kohta.

![](/files/-LzcUpAeKVQnx4m1J_5V)

### Kuva 7. Paina Run All Tests avautuvasta ikkunasta.

![](/files/-LzcUpAfpuNDy0KmD3ZP)

### Kuva 8. Jos testit ajamisen jälkeen näyttää vihreää niin hyvä.

![](/files/-LzcUpAgy2ZwMNPJS2yN)

### Kuva 9. Lopputilanne

Sinulla pitäisi olla Solution Explorer ikkunan mukaan kaksi projektia ja testit menevät läpi.&#x20;

Nyt projektipohja on valmis ja voit aloittaa harjoittelun.

![](/files/-LzcUpAhC4H6BBDNiyut)


# NUnit perusteet 101

## **Tavoite**

Osaat luoda Visual Studio projektin, jossa käytössä on NUnit yksikkötestauskirjasto.

## **Katso ensin video** malliksi

{% embed url="<https://www.youtube.com/watch?v=f2NrKazjWes>" %}

{% hint style="warning" %}
Otettu myös kuvakaappaukset Visual Studio 2019 versiosta. Katso sivu [NUnit lisääminen VS2019](/yksikkoetestaus/nunit-lisaeaeminen-vs2019).
{% endhint %}

## **Videon katsomisen jälkeen**

Tee Visual Studio projekti, jossa on tehty seuraavat toimenpiteet.

### Luo NUnit kirjastoa käyttävä projekti videon mukaisesti

Kokeile siis päästä samaan tilanteeseen kuin videon lopussa, että työkalu tulee tutuksi. Sinun pitäisi pystyä ajamaan siis muutama testi malliksi. Voit käyttää videolla tehtyä esimerkkiä.

### Lisää aiemmin luotuu projektiin muutamia eri testejä lisää

Harjoittele siis luomalla yksittäisiä testejä lisää. Videolla luodaan yksinkertainen laskin. Voit esimerkiksi lisätä laskimeen metodin kertolaskulle, jakolaskulle, jakojäännökselle jne. Voit myös luoda muunlaisen metodin millä vain pystyt kokeilemaan testien epäonnistumista ja ajoa.

### Lisää samaan Solutioniin toinen projekti, joka on tyypiltään Console Application

Videolla Console Application projektia ei lisätty. Tee se kuitenkin samaan tapaan kuin videolla muutoin tehtiin projekti. Kun olet luomassa uutta projektia, sinun pitäisi pystyä siinä kohdin valitsemaan, että se lisätään olemassa olevaan Solution projektiin.

{% hint style="info" %}
Kun olet palauttanut tehtävän niin pidä lopputulos tallessa. Se kuvastaa hyvin paljon lähtötilannetta muihin harjoituksiin tai töihin.
{% endhint %}

{% hint style="info" %}
Visual Studiossa on kahdenlaisia projektityyppejä. Solution ja Project. Solution on eräänlainen kokoava projektimuoto, jossa voi olla useita projekteja. Alla kuva joka havainnollistaa rakennetta mutta sinun voi olla nimetty eri tavoin.
{% endhint %}

![Esimerkki Visual Studion projektirakenteesta.](/files/-LzYJaZv5RDBE-Kvhxas)

## Lähteitä

Lisätietoja Visual Studion projektirakenteesta: <https://docs.microsoft.com/en-us/visualstudio/get-started/tutorial-projects-solutions?view=vs-2019>


# NUnit perusteet 102

#### Tutustu alla oleviin NUnit attribuutteihin ja kokeile esimerkein miten ne toimivat <a href="#tutustu-alla-oleviin-nunit-attribuutteihin-ja-kokeile-esimerkein-miten-ne-toimivat" id="tutustu-alla-oleviin-nunit-attribuutteihin-ja-kokeile-esimerkein-miten-ne-toimivat"></a>

Luo itse lähteiden mukaan omia esimerkkejä, jotka auttavat ymmärtämään attribuuttien käytön tarkoituksen. <https://github.com/nunit/docs/wiki/Attributes>

* TestFixture
* Test
* Author
* Category
* Ignore
* OneTimeSetTup
* OneTimeTearDown
* SetUp
* TeadDown
* TestCase
* TestCaseSource

#### Tutustu alla oleviin Assert -tarkistuksiin ja kokeile esimerkein miten ne toimivat <a href="#tutustu-alla-oleviin-assert--tarkistuksiin-ja-kokeile-esimerkein-miten-ne-toimivat" id="tutustu-alla-oleviin-assert--tarkistuksiin-ja-kokeile-esimerkein-miten-ne-toimivat"></a>

Luo itse lähteiden mukaan omia esimerkkejä, jotka auttavat ymmärtämään assert-tarkistusten käytön tarkoituksen. Kokeile myös assert-tarkistusten ehtoihin. (Constraints)

<https://github.com/nunit/docs/wiki/Assertions>

<https://github.com/nunit/docs/wiki/Constraints>

* Assert.That
* EqualTo
* GeaterThan
* LessThan
* Is.Not
* Is
* Empty
* True
* False
* Null
* Throws
* Throws.Nothing


# NUnit perusteet 103

Yksikkötestaus ei eroa varsinaisesti ohjelmoinnista ja attribuutit sekä testien kirjoittaminen jää paremmin mieleen ohjelmoimalla.

Sovella aiemmin oppimaasi seuraaviin käytännön läheisiin harjoitustehtäviin. Sinua auttavat myös muutamat apukysymykset.

#### Tutustu valmiiseen ohjelmaan, jossa on hyödynnetty testejä <a href="#tutustu-valmiiseen-ohjelmaan-jossa-on-hy-c3-b6dynnetty-testej-c3-a4" id="tutustu-valmiiseen-ohjelmaan-jossa-on-hy-c3-b6dynnetty-testej-c3-a4"></a>

Kloonaa projekti <https://github.com/nyluntu/saliavustaja>

Käynnistä projekti Visual Studiolla. Yritä kääntää projekti, jotta kaikki riippuvuudet ladataan. Tämän jälkeen valitse projekteista Saliavustaja.UI. Projektin päällä klikkaa hiiren oikeata painiketta ja kontekstimenusta valitse "set as startup project". Tämän jälkeen käynnistä projekti ja kokeile, että ohjelma käynnistyy.

Seuraavaksi sulje ohjelma ja tutustu SaliavustajaTests -projektiin. Yritä saada ajettua testit Visual Studiolla. Yritä tehdä havaintoja testeistä:

* Mitä testit testaavat? Mitä ne siis yrittävät todistaa?
* Miten testiluokat on nimetty?
* Miten testimetodit on nimetty?
* Miten eri attribuutteja on käytetty?
* Miten eri Assert-tarkistuksia on käytetty?
* Miten itse testit on rakenteeltaan ja luettavuudeltaan kirjoitettu?

#### Arrange-Act-Assert -sääntö testien kirjoittamisessa <a href="#arrange-act-assert-s-c3-a4-c3-a4nt-c3-b6-testien-kirjoittamisessa" id="arrange-act-assert-s-c3-a4-c3-a4nt-c3-b6-testien-kirjoittamisessa"></a>

Tutustu seuraavaan artikkeliin. <http://wiki.c2.com/?ArrangeActAssert>

Mikä on Arrange, Act, Assert säännön tarkoitus=

Tutustu edelliseen Saliavustaja esimerkkiin ja huomioi, toteutuuko siellä kyseinen rakenne?

Mitä muita tapoja on järjestellä yksikkötestien ohjelmointikoodia?


# NUnit perusteet 104

## **FizzBuzz -ohjelman toteuttaminen yksikkötestein**

Tutustutaan klassikoksi muodostuneeseen ohjelmointiongelmaan:

> Kirjoita ohjelma, joka kysyy käyttäjältä lukua yhden ja sadan väliltä ja tulostaa luvun. Jos luku on kolmella jaollinen, luvun sijaan tulostetaan "Fizz". Jos luku on viidellä jaollinen, luvun sijaan tulostetaan "Buzz". Jos luku on sekä kolmellä että viidellä jaollinen, luvun sijaan tulostetaan "FizzBuzz".

Ohjelma voi olla sinulle tuttu. Nyt tavoitteena on tehdä ohjelma ensin yksikkötestien kanssa ja vasta lopuksi toteuttaa konsoliohjelma syötteiden kysymiseen.&#x20;

Tarkoituksena on oppia erottamaan testikoodi niin sanotusta tuotantokoodista. Yritä, että saisit testien avulla varmistettua ensin ohjelman toimivuuden.&#x20;

Ohjelman toimivuuden todentamiseksi riittää toteutetut testit. Konsoliprojektia ei tarvitse välttämättä olla, jos et halua vielä sellaista lisätä.

```
# Esimerkki mitä ohjelman tulisi tehdä kun sille annetaan lukuja 1-100 väliltä.
# Huomaa, että testaan usealla luvulla, jotta se varmasti käyttäytyy oikein.

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
... aina lukuun 100 asti.
```

{% hint style="info" %}
Tehtävänannossa puhutaan tarkoituksella, että käyttäjä antaa syötteen. Lopullisen ohjelman tulisi toimia tällä tavoin mutta sinun tehtäväsi on pohtia, miten esimerkiksi käyttäjän syöte tulee huomioitua testeissä. Tarvitseeko sitä edes testata?
{% endhint %}

## Vinkkejä matkan varrelle

Harjoitus ei ole ohjaajan luoma vaan siihen löytyy useita ratkaisuehdotuksia. Pyri kuitenkin ensin itse ratkaisemaan ongelma ja vasta sitten tarvittaessa hae apua.

Ratkaise logiikka ensin paperilla. Kokeile miettiä miten ohjelman tulee toimia ja vasta sitten siirry ohjelmoinnin pariin.

Jos testit eivät onnistu ensimmäisenä niin ratkaise se ensin ilman niitä. Lisää sitten vasta testit.

Pilko ongelma pienempiin palasiin... lähde helpoimmasta päästä testaamaan eli arvosta 1. Sitten yksi kerrallaan kokeile erilaiset tilanteet läpi. Tarkoitus ei ole käydä kaikkia 100 lukua läpi vaan vain sen verran, että ohjelman voi todeta toimivan.


# NUnit perusteet 105

## Merkkijono laskin -ohjelman toteuttaminen yksikkötestein

Seuraava harjoitus ei ole kirjoittajan oma vaan perustuu Roy Osheroven String Calculator harjoitukseen. <http://osherove.com/tdd-kata-1/>

Harjoitusta on hieman muutettu alkuperäisestä.

Vältä katsomasta esimerkkejä vaan keskity seuraavan tehtävänannon ohjeistukseen ja yritä ratkaista se ensin itse niin pitkälle kuin pääset. Harjoituksen tavoitteena on luoda yksinkertainen ohjelma, joka on tarkoin määritelty ja sen oikea toiminnallisuus tulee todistaa testien avulla.

## **Tavoite**

Oppia hyödyntämään yksikkötestausta sekä testivetoista kehitystä.

Pyri kirjoittamaan seuraava testi aina valmiiksi ja sitten vasta sen läpäisevä tuotantokoodi.

### **Laskimen määritys**

{% hint style="info" %}
Tee yksi kohta kerrallaan. Vältä etenemästä seuraavaan ennen ratkaisua ja katsomatta liikaa muita vaatimuksia.

Kokeile myös ensin katsomatta esimerkkejä syötteistä mutta voit käyttää niitä sitten myös apuna.
{% endhint %}

Ohjelmassa on **MerkkijonoLaskin** niminen luokka. Luokassa on yksi metodi nimeltään **Laske.** Metodi palauttaa numeroarvon. **Laske** -metodi ottaa parametrikseen merkkijonon (string).

Luo ohjelma alla mainittujen vaatimuksiin perustuen siten, että sinulla on vähintään yksi testi jokaiselle vaatimukselle. Kun olet kirjoittanut testin, voit vielä tehdä ohjelmasta konsoliohjelman.

* \[ ] Tyhjä merkkinojo palauttaa nollan.
* \[ ] Yksi numero, laskin palauttaa annetun numeron arvon..
* \[ ] Kaksi numeroa, pilkulla erotettuna, palauttaa lukujen summan.
* \[ ] Toteuta ominaisuus, että numeroita voidaan antaa pilkulla erotettuna rajoittamaton määrä ja laskin palauttaa lukujen summan.
* \[ ] Toteuta ominaisuus, että pilkkujen tilalla voidaan käyttää newline merkintää lukujen erottimena pilkkujen sijaan. (newline = \n)
  * Esimerkiksi arvo "1\n2,3" palauttaisi summan 6.
  * Ei tarvitse tukea muotoa, jossa erottimet seuraavat toisiaan. Esimerkiksi "1,\n". Voidaan olettaa, ettei tällaisia syötteitä anneta.
* \[ ] Negatiivinen luku, pienempi kuin nolla, aiheuttaa virheen. (Exception)
* \[ ] Luvut, jotka ovat yli 1000, ei huomioida yhteenlaskussa.

### Esimerkkejä syötteistä

| Laske metodin parametri | Metodin palauttama arvo                          |
| ----------------------- | ------------------------------------------------ |
| ""                      | 0                                                |
| "0"                     | 0                                                |
| "1"                     | 1                                                |
| "2"                     | 2                                                |
| "1,1"                   | 2                                                |
| "3,4"                   | 7                                                |
| "2,7,4"                 | 13                                               |
| "5,5,5,4"               | 19                                               |
| "1\n2,3"                | 6                                                |
| "-1"                    | throw exception("negatiivisia lukuja ei sallita) |
| "3,-1"                  | throw exception("negatiivisia lukuja ei sallita) |
| "3,1001"                | 3                                                |


# NUnit perusteet 106

## Keilauksen pistelaskuri

Tutustu alla olevaan tehtävänantoon. Sinun tehtäväsi on toteuttaa ohjelma käyttäen yksikkötestausta. Tehtävänanto on tarkoituksella jätetty pilkkomatta pieniin välivaiheisiin. Sinun pitää itse lähteä purkamaan tehtävänantoa ja miettiä mitä testaisit ensin tai mistä lähtisit liikkeelle. Voit aloittaa vaikka hahmottelemalla miten ohjelma toimii.

Tee itsellesi muistiinpanot, miten tehtävän ratkaisisit. Kun sinulla on jonkinlainen ajatus niin yritä toteuttaa ratkaisusi. Alkuun voit esimerkiksi listata helpoimmat testit, jotka vievät ohjelman kokonaisuutta eteenpäin.

> Yksi keilasarja koostuu kymmenestä ruudusta. Yhdeksään ensimmäiseen ruutuun saa heittää kaksi heittoa, jos ensimmäinen heitto ei ole kaato ja kymmenenteen ruutuun heitetään kolme heittoa, jos ensimmäinen heitto on kaato tai toinen heitto on paikko.
>
> Jokaisesta heitosta saa pisteitä yhtä paljon kuin on kaadettuja keiloja. Jos heitto on kaato, kyseisen ruudun pisteisiin lasketaan mukaan lisäksi kahden seuraavan heiton pisteet ja paikon jälkeen lasketaan ruutuun mukaan seuraavan yhden heiton pisteet.
>
> Ruudun pisteet lasketaan ja merkitään vasta kun kaikki ruutuun tarvittavat heitot on heitetty, esimerkiksi kaadon jälkeen on heitettävä ensin kaksi heittoa ennen kuin pisteet voidaan laskea.
>
> Maksimipisteet 300 saadaan, kun heitetään 12 kaatoa peräkkäin, jolloin jokaista ruutua kohti tulee 30 pistettä.
>
> (alkuperäinen idea \[<http://codingdojo.org/kata/Bowling/>]\(<http://codingdojo.org/kata/Bowling/>))


# NUnit muu materiaali ja lähteitä

{% embed url="<http://nunit.org/>" %}

{% embed url="<https://www.codeproject.com/Articles/197662/Unit-Testing-Getting-Started-with-NUnit>" %}

{% embed url="<http://wiki.c2.com/?ArrangeActAssert>" %}

## Online kursseja ja videoita

Pluralsight tarjoaa monipuolista sisältöä ja sieltä löytyy myös testaukseen liittyviä kokonaisuuksia. Katso linkki alta.

{% embed url="<https://www.pluralsight.com/search?q=nunit>" %}

{% embed url="<https://www.youtube.com/watch?v=HYrXogLj7vg>" %}


# TDD perusteet 101

#### Mitä tarkoittaa Test Driven Development? <a href="#mit-c3-a4-tarkoittaa-test-driven-development" id="mit-c3-a4-tarkoittaa-test-driven-development"></a>

Lue lähteissä olevista kirjoista mitä termillä tarkoitetaan. Voit tutustua myös muihin lähteisiin mitä löydät aiheesta.

#### Mitkä ovat TDD:n kolme sääntöä työskentelyn aikana? <a href="#mitk-c3-a4-ovat-tddn-kolme-s-c3-a4-c3-a4nt-c3-b6-c3-a4-ty-c3-b6skentelyn-aikana" id="mitk-c3-a4-ovat-tddn-kolme-s-c3-a4-c3-a4nt-c3-b6-c3-a4-ty-c3-b6skentelyn-aikana"></a>

Ymmärrä lähteiden avulla näiden sääntöjen tarkoitus. Tulet tarvitsemaan niitä myöhemmin harjoitustehtävien aikana.

#### Mitä hyötyä TDD:n noudattamisesta on? <a href="#mit-c3-a4-hy-c3-b6ty-c3-a4-tddn-noudattamisesta-on" id="mit-c3-a4-hy-c3-b6ty-c3-a4-tddn-noudattamisesta-on"></a>

Etsi lähteistä miksi toimintatapa on hyödyllinen? Tee luettelo hyödyistä ja mahdollisista haitoista.


# TDD perusteet 102

#### Tee merkkijonolaskin harjoitus TDD:tä käyttäen <a href="#tee-merkkijonolaskin-harjoitus-tddt-c3-a4-k-c3-a4ytt-c3-a4en" id="tee-merkkijonolaskin-harjoitus-tddt-c3-a4-k-c3-a4ytt-c3-a4en"></a>

[NUnit perusteet 103](vscode-resource:/Users/sovelluskontti/dev/ohjelmistokehityksen-menetelmat/nunit-perusteet-103.md) -harjoituksissa esiteltiin merkkijonolaskimen tehtävänanto. Tee harjoitus uudelleen mutta nyt pidättäydy mahdollisimman tarkasti TDD:n kolmessa säännössä. Säännöt alkuperäisessä muodossaan on lueteltu alla.

> Uncle Bob describes TDD with three rules:
>
> 1. You are not allowed to write any production code unless it is to make a failing unit test pass.
> 2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
> 3. You are not allowed to write any more production code than is sufficient to pass the one failing unit test.

#### Tee keilapistelaskuri harjoitus TDD:tä käyttäen <a href="#tee-keilapistelaskuri-harjoitus-tddt-c3-a4-k-c3-a4ytt-c3-a4en" id="tee-keilapistelaskuri-harjoitus-tddt-c3-a4-k-c3-a4ytt-c3-a4en"></a>

[NUnit perusteet 103](vscode-resource:/Users/sovelluskontti/dev/ohjelmistokehityksen-menetelmat/nunit-perusteet-103.md) -harjoituksissa esiteltiin keilapistelaskurin logiikka. Tee harjoitus uudelleen mutta käytä nyt aiemmin oppimaasi hyödyksi. Tunnet toivottavasti ongelman jo paremmin. Ratkaise ongelma noudattaen TDD:n kolmea sääntöä ja pyri ohjelmoimaan pienissä välivaiheissa.


# TDD perusteet 103

Harjoituksen tavoitteena on oppia testivetoisen ohjelmoinnin perusteet. Tee tehtävä ohjeistuksen mukaan. Vältä katsomasta etukäteen osakokonaisuuksia.

## Esitiedot

* Git versionhallinnan perusteet.
* Jonkin yksikkötestauskirjaston perusteet.

## Vaihe 1

Avaa merkkijonolaskimen tehtävänanto: <https://osherove.com/tdd-kata-1>

Vältä lukemasta läpi tehtävänantoa vaan aloita ensimmäisestä vaiheesta. Jatka merkkijono tehtävän seuraavaan osioon.&#x20;

**Varaa tähän 60min.** Kun aika on täynnä, pidä lyhyt tauko ja siirry seuraavaan vaiheeseen tämän tehtäväkokonaisuuden osalta.

{% hint style="info" %}
Kaikkia kohtia ei ole tarkoitus saada valmiiksi, tee vain niin monta vaihetta alkuperäisestä tehtävästä kuin pystyt. Rajoite on vain käytettävissä oleva aika.
{% endhint %}

{% hint style="warning" %}
Tehtävässä tulee käyttää versiohallintaa siten, että tee **master** branchin ensimmäinen commit siten, että projektissa ei ole valmisteltu mitään. Sen jälkeen tee uusi branchi nimeltä **tdd-perusteet-103-vaihe-01**

Kun olet luonut yhden testin ja saanut sen läpi, tee tästä aina yksi commit. Tarkoituksena on historiasta nähdä miten ongelmaa ratkaistiin.
{% endhint %}

## Vaihe 2

Katso video: <https://www.youtube.com/watch?v=Li-omXFK9NE>

Kun olet katsonut videon, pidä pieni tauko ja siirry seuraavaan vaiheseen.

## Vaihe 3

Tee uudelleen vaihe 1, josta aloitit. Edelleen aikaraja on 60min.&#x20;

Aloita tämä vaihe ns. puhtaalta pöydältä vaan tee uusi branchi.

Kun aikaraja on täynnä, lopeta.

Miten videon jälkeen se muutti tapaasi ratkaista tehtävä?

{% hint style="warning" %}
Nimeä branchi seuraavasti: **tdd-perusteet-103-vaihe-03**
{% endhint %}


# TDD muu materiaali ja lähteitä

[Test Driven Development: By Example](https://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530), Kent Beck

[Agile Principles, Patterns, and Practices in C#](https://www.amazon.com/Agile-Principles-Patterns-Practices-C/dp/0131857258/ref=pd_sim_14_24?_encoding=UTF8\&pd_rd_i=0131857258\&pd_rd_r=G80BGWEHB5HMV067RWTW\&pd_rd_w=VQaWo\&pd_rd_wg=IQ8d4\&psc=1\&refRID=G80BGWEHB5HMV067RWTW), Robert C. Martin

[Test Driven Development](https://en.wikipedia.org/wiki/Test-driven_development), Wikipedia

[9 Benefits of Test Driven Development](https://www.madetech.com/blog/9-benefits-of-test-driven-development), David Winter

[The Three laws of TDD ](https://www.youtube.com/watch?v=AoIfc5NwRks)(video), Robert C. Martin

[TDD Basics with C# (video),](https://www.youtube.com/watch?v=l4xhTq4qmC0) Jeremy Clark

[ Get some hands-on practice with test-driven development in C#](https://medium.freecodecamp.org/tdd-explanation-hands-on-practice-with-c-a0124338be44), Moshe Binieli, Viitattu 14.2.2019

## 22 vastausta TDD aiheisiin kysymyksiin

{% embed url="<https://www.youtube.com/playlist?list=PL3iay_FdAzV-bFzWOhjw2x1YcYSEQCHvH>" %}


# Johdanto

UML (Unified Modeling Language) -kaavioiden perusteet.

UML on lyhenne termeistä Unified Modelin Language. Kyseessä on tapa mallintaa ohjelmiston komponentteja, rakenteita ja suoritusvaiheita. UML sisältää useita erilaisia kaaviotyyppejä mallintamiseen ja antaa täten valmiita, sekä standardoituja tapoja, kuvata ohjelmistojen suunnitteluun liittyviä asioita.

Historia ulottuu 80-luvun lopulle mutta ensimmäinen UML 1.0 julkaistiin vuonna 1997. Voidaan ajatella tämän olevan lähtökohta UML -mallinnuskielelle. Kyseessä on siis mallinnuskieli, ei menetelmä. Kuvaustapoja on olemassa erilaisia ja mikään ei ole varsinaisesti väärin. UML on yksi tunnetuimpia tapoja ja täten tarjoaa yhtenäisen tavan kuvata ja suunnitella ohjelmistoja.

Artikkelissa tuon esille asioita mitkä ovat hyvä tuntea ohjelmoijan näkökulmasta. Moni asia perustuu lähteissä mainittuihin teoksiin tai Internet lähteisiin. Kaikkia eri kaaviotyyppejä ei käsitellä vaan esille nostetaan niitä, jotka kirjoittaja on kokenut toimivammaksi.

On hyvä muistaa, että UML ei kovin usein tule tänä päivänä ilmi. Ketterän ohjelmistokehityksen toimintamallit ovat muuttaneet työtapoja ja moni ennestään olemassa oleva asia unohtuu. UML historia on kuitenkin hyvin paljon olio-ohjelmoinnin suosion alkupäässä ja sisältää paljon oliokeskeisiä mallinnustapoja. Ohjelmistokehityksessä on usein suunnitteluun ja analyysiin keskittyvä vaihe missä tehdään etukäteen suunnitelmia ohjelmiston rakenteesta. Näihin tilanteisiin UML -mallinnuskieli on tehty.

Vaikka ohjelmistojen tuottaminen on muuttunut 80- ja 90-luvusta lähtien valtavasti, sekä myös 2000 -luvun alusta niin UML -mallinnuskielelle on silti paikka ohjelmistokehityksessä. Tänä päivänä suositaan lyhyempiä suunnitteluvaiheita ja keskittymistä toteutusvaiheeseen. UML -kuitenkin tarjoaa hyvän "kirjaston" erilaisia mallinnustapoja, jotka auttava ajatusten hahmottamisessa ja viestimisessä.

Dokumentointi on tärkeässä osassa ohjelmistotuotantoa. Dokumentoinnin haasteet ovat lähinnä nopeasti muuttuvissa vaatimuksisa ja vaarana sen vanheneminen. UML -kaavioita käsin piirtäen ei ole tehokkain dokumentointitapa muuttuvien vaatimusten vuoksi. Mukaan on tullut paljon kaavioiden piirtämiseen tarkoitettuja ohjelmistoja sekä työkaluja, jotka luovat olemassa olevasta lähdekoodista halutunlaisia kaavioita.

Aloitetaan tutustuminen muutamiin tärkeimpiin kaaviotyyppeihin. Sen kautta pyrimme tutustumaan miten UML -mallinnuskielestä voi olla hyötyä ohjelmistoja suunnitellessa.

## Kaaviotyypit

UML -mallinnuskieli sisältää useita kaaviotyyppejä ja ne voidaan karkeasti jakaa kolmeen erilaiseen päätyyppiin.&#x20;

**Rakennekaavio (Structure diagram)**

* Komponenttikaavio (Component diagram)
* Koostekaavio (Composite structure diagram)
* *<mark style="background-color:green;">Luokkakaavio</mark>* (Class diagram)
* Oliokaavio (Object diagram)
* Pakkauskaavio (Package diagram)
* Sijoittelukaavio (Deployment diagram)

**Käyttäytymiskaavio (Behavior diagram)**

* *<mark style="background-color:green;">Aktiviteettikaavio</mark>* (Activity diagram)
* *<mark style="background-color:green;">Käyttötapauskaavio</mark>* (Use case diagram)
* Tilakaavio (State (machine) diagram)

**Vuorovaikutuskaavio (Interaction diagram)**

* Ajoituskaavio (Timing diagram)
* Kokoava vuorovaikutuskaavio (Interaction overview diagram)
* Kommunikointikaavio (Communication diagram)
* Sekvenssikaavio (Sequence diagram)

Kaaviot voidaan karkeasti jakaa kolmeen erilaiseen päätyyppiin.&#x20;

*Rakennekaaviot* kuvaavat ohjelmiston rakenteita, joiden täytyy olla mallinnettavassa järjestelmässä. Tämä voi tarkoittaa esimerkiksi ohjelmiston eri komponenttien osittamista toisiinsa nähden.&#x20;

![Esimerkki luokkakaaviosta](/files/RWUHMhliDKJvtHjNE83h)

*Käyttäytymiskaaviot* korostavat ohjelmsiton käyttäytymistä eri tilanteissa. Esimerkiksi miten ohjelman logiikan tulisi toimia kuvatussa tilanteessa.&#x20;

![Esimerkki aktiviteettikaaviosta](/files/GjnsWWICcCYZ4pZrbCKD)

*Vuorovaikutuskaaviot* korostavat yksittäisten ohjelmiston osien yhteistyötä. Esimerkiksi voidaan kuvata kahden eri järjestelmän välistä viestimistä ja käyttäytymistä.

![Esimerkki sekvenssikaaviosta](/files/IeNNgCRHGPZBjgjUPlng)

### Kuvauskieli

UML -kaaviot sisältävät standardoidun kuvauskielen eli notaation. Kirjallisuudessa puhutaan siis notaatiosta millä tarkoitetaan eri kaavioille luotuja merkintätapoja. Yhteenveto näistä notaatioista löytyy alla olevasta liitetiedostosta.

{% file src="/files/I49tyIafNTKrrtiAOmgj" %}
Tiedosto sisältää lähdeteoksesta skannatun yhteenvedon notaatioista.
{% endfile %}

Tutustu myös Tutorials Point sivuston notaatioiden yhteenvetoon.

{% embed url="<https://www.tutorialspoint.com/uml/uml_basic_notations.htm>" %}

### Luokkakaaviot

Luokkakaavioista on tullut oliosuuntautuneiden menetelmien keskeinen osa. Näihin liittyy erittäin laaja joukko mallinnuskäsitteitä. Materiaalissa esittellään ns. peruskäsitteet, joita tarvitaan useammin.

Luokkakaavio tarkoitus on kuvata järjestelmässä olevia oliotyyppejä ja niiden välillä esiintyviä erilaisia staattisia suhteita. Nämä suhteet jakautuvat kahteen päätyppiin:

* Assosisaatiot - esimerkiksi asiakas voi vuokrata joukon videoita.
* Alityypit - sairaanhoitaja on yksi henkilölaji.

Suhteiden lisäksi luokkakaavioissa voidaan esittää **operaatioita**, jotka ovat niitä prosesseja mitkä luokka osaa toteuttaa. Tällainen voi olla luokkakaavion esimerkissä oleva Tilaus-luokan **lähetä()**-operaatio.

{% file src="/files/FNtMBi5Y9NdRipYQ6udP" %}

Tutustu myös Tutorials Point sivuston tarjoamaan materiaaliin luokkakaavioihin liittyen.

{% embed url="<https://www.tutorialspoint.com/uml/uml_class_diagram.htm>" %}

{% embed url="<https://fi.wikipedia.org/wiki/Luokkakaavio>" %}

### Aktiviteettikaaviot

Aktiviteettikaavioita käytetään järjestelmän työkulun mallintamiseen. Toiselta nimeltä nämä tunnetaan myös *toimintakaavioina*. Toimintakaavio kuvaa tehtävien tapahtumajärjestystä. Siinä voidaan esitellä ehdollista, että rinnakkaista toimintaa. Aktiviteettikaaivo muistuttaa *tilakaaviota* mutta niiden sisällössä on pieniä eroja. Notaatiot muistuttavat toisiaan.

{% file src="/files/NElxLnfwshKF3ScjX6Qm" %}

Tutustu myös Tutorials Point sivuston yhteenvetoon aktiviteettikaavioista.

{% embed url="<https://www.tutorialspoint.com/uml/uml_activity_diagram.htm>" %}

{% embed url="<https://fi.wikipedia.org/wiki/Aktiviteettikaavio>" %}

### Käyttötapauskaaviot

Käyttötapaukset (use cases) ovat tapa kuvata järjestelmän ominaisuuksia sekä niiden tavoitteita. Nämä ovat usein tekstipohjaisia kevyitä kuvauksia siitä miten järjestelmän tulisi toimia tietyssä tissa. Käyttötapauksista on puhuttu erikseen tämän sivuston [materiaaleissa](/ketterae-ohjelmistokehitys/agile-kaeyttaejaetarina-ja-kaeyttoetapaus#kaeyttoetapaus).&#x20;

Käyttötapauskaaviot puolestaan ovat tapa mallintaa näitä vaatimuksia suhteellisen yksinkertaisella tavalla. Kaavioihin liittyy lähinnä **toimijoiden, käyttötapausten** ja niiden välisten **suhteiden** kuvaamista.

{% file src="/files/BrdvFTIOVntAfLbNidAH" %}

Tutustu myös Tutorials Point sivuston yhteenvetoon käyttötapauskaavioista.

{% embed url="<https://www.tutorialspoint.com/uml/uml_use_case_diagram.htm>" %}

{% embed url="<https://fi.wikipedia.org/wiki/K%C3%A4ytt%C3%B6tapauskaavio>" %}

## Lähteet

UML, Martin Fowler & Kendal Scott, Docendo, 2. painos 2004 (alkuperäinen teos Martin Fowler, Kendal Scott: UML Distilled, <https://www.pearson.com/uk/educators/higher-education-educators/program/Fowler-UML-Distilled-A-Brief-Guide-to-the-Standard-Object-Modeling-Language-2nd-Edition/PGM454835.html>)

Wikipedia, Unified Modeling Language, <https://en.wikipedia.org/wiki/Unified_Modeling_Language>

Wikipedia, UML -mallinnus, <https://fi.wikipedia.org/wiki/UML-mallinnus>


# Johdanto

Seuraavissa luvuissa tutustutaan relaatiotietokantojen käsitteisiin sekä SQL kyselykieleen.

Harjoituksissa käytetään pääosin <https://dev.mysql.com/doc/sakila/en/> harjoitustietokantaa. Myös Mysql Tutorials sivuston harjoitustietokanta on osassa esimerkeissä käytössä <https://www.mysqltutorial.org/mysql-sample-database.aspx>

Kirjoittamattomat aiheet:

* SQL injektiot
* <http://www.mysqltutorial.org/mysql-full-text-search.aspx>
* harjoitustietokantojen käyttöönotto


# Sanasto

Tietokantoihin tutustuessa tulee vastaan useita eri termejä, jotka on hyvä tuntea. Tässä on esitelty joitakin relaatiotietokantoihin liittyviä termejä.

**taulu** - Tällä tarkoitetaan relaatiotietokannan pääasiallista rakennetta, jonne tieto tallentuu. Esimerkiksi voisi olla taulut nimellä *kirjat, koirat* tai *asunnot*.

**rivit** - Taulut sisältävät rivejä. Rivi on aina yksi tiedonjyvä, joka on uniikki taululle. Taulun ei tulisi sisältää siis ns. duplikaatteja.

**sarake** - Rivit sisältävät sarakkeita. Sarake on aina yksittäinen tiedon osa. Tällaisia voisi olla esimerkiksi *koirat* -taulussa *ikä, rotu, nimi* jne.

**pääavain** - Tunniste, joka on uniikki ja erottaa taulun rivit toisistaan.

**viiteavain** - Tunniste, joka viittaa toisen taulun pääavaimeen.

**records** tai **tuples** - Näillä tarkoitetaan rivejä.

**attribuutti** - Tällä tarkoitetaan saraketta.

**rajoitteet** (constraints)

**mahtavuus** (Cardinality)


# Mysql perusteet -videosarja

Mysql perusteet on käsitelty seuraavalla soittolistalla. Sisältö kattaa pääosin kyselyt ja tietokannan muokkaamisen sekä taulujen suhteet. Lopuksi puhutaan vielä joistakin tärkeistä käsitteistä mitkä usein tulevat vastaan ja on hyvä tuntea.

{% embed url="<https://www.youtube.com/playlist?list=PL3iay_FdAzV_DrpXk7csd90fyUitBQEEK>" %}


# Pää- ja viiteavaimet

Luvussa käsitellään pää- ja viitevainten tarkoitusta sekä miten niitä tulisi käyttää.

Relaatiotietokannat sisältävät tauluja. Taulut sisältävät suhteita toisiinsa, joita on muutamia erilaisia. Erilaiset suhteet on kuvattu myöhemmässä luvussa. Tässä luvussa keskitytään taulujen pää- ja viiteavaimien tarkoituksiin.

## Pääavain

Pääavaimen tarkoituksena on olla uniikki arvo taulussa olevien rivien erottamiseksi toisistaan. Yhdessä taulussa ei voi olla useita samanarvon sisältäviä pääavaimia. Jokaisella taululla on oltava pääavain ja niitä voi olla vain yksi per taulu. Pääavaimen arvo ei voi olla NULL eli tyhjä.

Pääavain voi koostua yhdestä tai useammasta taulun sisältämistä sarakkeista. Arvon ei siis tarvitse olla pelkkä numero vaan voi sisältää muitakin arvoja. Usein voidaan nähdä nousevasti laskettu numeroarvo (1,2,3,4,5...), joka toimii pääavaimena. Suositus on kuitenkin, että pääavain olisi mahdollisimman luonnollinen. Esimerkiksi henkilötunnus voisi toimia pääavaimena taulussa, jossa on kuvattu henkilöitä.

Tutustutaan esimerkin kautta pääavaimeen. Tutkitaan **products** taulua harjoitustietokannasta.

![Products taulun rakenne.](/files/-LoqLxboQkJ7gddezOOB)

{% code title="products-taulun-luontikomento" %}

```sql
CREATE TABLE `products` 
  ( 
     `productcode`        VARCHAR(15) NOT NULL, 
     `productname`        VARCHAR(70) NOT NULL, 
     `productline`        VARCHAR(50) NOT NULL, 
     `productscale`       VARCHAR(10) NOT NULL, 
     `productvendor`      VARCHAR(50) NOT NULL, 
     `productdescription` TEXT NOT NULL, 
     `quantityinstock`    SMALLINT(6) NOT NULL, 
     `buyprice`           DECIMAL(10, 2) NOT NULL, 
     `msrp`               DECIMAL(10, 2) NOT NULL, 
     PRIMARY KEY (`productcode`), 
     KEY `productline` (`productline`), 
     CONSTRAINT `products_ibfk_1` FOREIGN KEY (`productline`) REFERENCES 
     `productlines` (`productline`) 
  ) 
engine=innodb 
DEFAULT charset=latin1 
```

{% endcode %}

Yllä on siis kuva tuote-taulusta sekä sen luontikomento. Kuvassa pääavaimen kenttä on värjätty sinisellä. Pääavaimena toimii siis **productCode** niminen sarake, joka on tietotyypiltään **varchar**.&#x20;

Luontikomennosta nähdään kuinka pääavain on määritetty taulua luodessa. Alla oleva rivi siis kertoo, että mikä sarake toimii pääavaimena. Sarakkeella tulisi siis olla ne ominaisuudet mitä edellä jo lueteltiin eli tärkeintä on, jotta arvo ei voi toistua toisen tuotteen kohdalla. Tuotteita ajatellessa tuotenumero on hyvä lähtökohta pääavaimelle vaikka joskus se ei toimi käytännössä. Tällöin jos huomataan, ettei pääavain sovi, niin yritä miettiä muuta pääavaimeksi tai useita sarakkeita.

```sql
-- Rivi 12
-- Luontikomento on seuraavan muotoinen.
-- PRIMARY KEY ([pääavaimen_sarake])
PRIMARY KEY (`productcode`)
```

Pääavaimen määrittäminen ei ole edellistä esimerkkiä hankalampaa. Usein voi olla vaikeampi löytää sopiva pääavain. Usein nähdään käytettävän juoksevaa numeroa pääavaimena, että luku kasvaa aina yhdellä kun rivi lisätään. Tällainen pääavain voidaan luoda käyttäen `AUTO INCREMENT` määritystä. Itsenäisesti kasvava pääavain on kätevä monessa tilanteessa mutta kannattaa aina miettiä löytyykö pääavaimeksi jokin muu arvo taulun sarakkeista. Käydään seuraavaksi esimerkki miten juokseva pääavain luodaan.

{% code title="auto-increment-example" %}

```sql
CREATE TABLE `customers_example` 
  ( 
     `customernumber`         INT(11) NOT NULL auto_increment, 
     `customername`           VARCHAR(50) NOT NULL, 
     `contactlastname`        VARCHAR(50) NOT NULL, 
     `contactfirstname`       VARCHAR(50) NOT NULL, 
     PRIMARY KEY (`customernumber`) 
  ) 
engine=innodb 
DEFAULT charset=latin1 
```

{% endcode %}

Esimerkin vuoksi taulu on pidetty yksinkertaisena ja perustuu **customers** tauluun. Erona on, että nyt pääavaimena toimiva sarake on määritetty rivillä 3 `auto_increment` määrityksellä. Tämä tekee pääavaimesta juoksevan numeron ja tietokanta itsessään huolehtii, että seuraava arvo on aina uniikki.

Tietokanta sisältää tiedon siitä mikä on taulun pääavain ja mikäli kyseessä on juokseva numero niin aina viimeisin arvo tiedetään. Tämän vuoksi tietokanta huolehtii, ettei samaa arvoa anneta kahteen kertaan. Esimerkiksi jos tietokannassa on pääavaimena arvot **1001, 1002 ja 1003**. Rivi **1002 ja 1003** poistetaan. Kun uusi rivi lisätään niin arvoksi tulee **1004** eikä jokin poistetuista. Tällä tavoin ei jo kertaalleen olleita arvoja anneta uudestaan. On tottakai mahdollista saada sama arvo mutta tämä tarkoittaa sitä, että taulun ylläpitämää tietoa on muutettu toisella komennolla hyvästä syystä.

Pääavaimella on vielä yksi tärkeä ominaisuus. Se on aina [indeksoitu](http://www.mysqltutorial.org/mysql-index/). Indeksi on selitetty omassa luvussaan myöhemmin. Lyhyesti tämä tarkoittaa sitä, että toimiakseen tehokkaasti niin pääavain toimii indeksina kun taulusta haetaan tietoa. Jos tiedetään pääavain, esimerkiksi tuotenumero **S12\_3380** niin hakiessa tällä arvolla **WHERE** ehdon kanssa, rivi löytyy lähes välittömästi. Pääavain on siis usein nopein tapa etsiä yksittäinen rivi, koska sen kuuluu olla uniikki taulun sisältämille riveille.

## Viiteavain

Kun taulujen välisiä suhteita kuvataan niin tauluihin pitää pystyä viittaamaan. Pääavain toimii aina uniikkina avaimena ja siksi voi toimia toisessa taulussa viiteavaimena. Viiteavaimella voidaan sanoa olevan seuraavia ominaisuuksia.

Taulu voi sisältää yhden tai useamman viiteavaimen toisiin tauluihin. Viiteavain voi myös viitata tauluun itseensä eikä erilliseen tauluun. Viiteavaimet ovat myös indeksoituja, jotta tietojen hakeminen nopeutuu. Viiteavaimena toimivan kentän ei tarvitse olla uniikki.

Päätarkoitus viiteavaimella on toimia tietokannan näkökulmasta tiedon eheyden varmistuksessa. Tämä tarkoittaa sitä, että kun tietoja poistetaan, lisätään tai päivitetään, tulisi viittausten pysyä toimivina. Esimerkiksi, jos poistamme tuoteryhmän niin sitä ei tulisi pystyä poistamaan, jos siihen on viitattu tuotteissa. Muutoin tuotteella ei olisi enää tuoteryhmää.

Eheyden varmistamiseksi on olemassa muutamia sääntöjä mitä tietokanta noudattaa tietoja poistettaessa. Puhutaan ns. eheyssäännöistä. Nämä käsitellään erillisessä luvussa.

Käydään viiteavaimen käyttöä vielä läpi edellisen esimerkin tapaan. Laajennamme kuitenkin esimerkkiä siten, että otamme mukaan kaksi muuta taulua. Esimerkissämme esiintyy siis taulut **products, productLines** ja **orderDetails**.&#x20;

![Esimerkki pää- ja viiteavaimista.](/files/-LoqW2g9V3fo05w10XlK)

Kuvasta pystymme lukemaan seuraavaa. **Products** -taulun pääavaimena toimii **productCode** -sarake. **ProductLines** -taulun pääavain on **productLine** -sarake. OrderDetails -taulun pääavain koostuu kahdesta sarakkeesta, **orderNumber** ja **productCode**. Tälssä taulussa on hyvä esimerkki siis juurikin pääavaimesta, joka koostuu useammasta sarakkeesta.&#x20;

Esitellään vielä taulujen luontikomennot, jotka kertovat saman asian. Products -taulun luontikomento on jo esitelty pääavaimen osiossa, joten tässä esitellään vain uusien taulujen luontikomennot.

{% code title="viiteavain-esimerkki-luontikomennot" %}

```sql
CREATE TABLE `orderdetails` (
 `orderNumber` int(11) NOT NULL,
 `productCode` varchar(15) NOT NULL,
 `quantityOrdered` int(11) NOT NULL,
 `priceEach` decimal(10,2) NOT NULL,
 `orderLineNumber` smallint(6) NOT NULL,
 PRIMARY KEY (`orderNumber`,`productCode`),
 KEY `productCode` (`productCode`),
 CONSTRAINT `orderdetails_ibfk_1` FOREIGN KEY (`orderNumber`) REFERENCES `orders` (`orderNumber`),
 CONSTRAINT `orderdetails_ibfk_2` FOREIGN KEY (`productCode`) REFERENCES `products` (`productCode`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

CREATE TABLE `productlines` (
 `productLine` varchar(50) NOT NULL,
 `textDescription` varchar(4000) DEFAULT NULL,
 `htmlDescription` mediumtext,
 `image` mediumblob,
 PRIMARY KEY (`productLine`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
```

{% endcode %}

Yllä olevissa uontikomennoissa rivit 9 ja 10 ovat tärkeitä. Niissä on määritetty miten viiteavain luodaan. (huomaa myös rivillä 7 oleva usean sarakkeen pääavaimen luonti.)

```sql
-- Luontikomento on seuraavan muotoinen.
-- CONSTRAINT [viiteavaimen_nimi] FOREIGN KEY ([viiteavain_sarake]) REFERENCES [viitattava_taulu] ([viitattavan_taulun_pääavain])

-- Luodaan viittaus orders taulun orderNumber sarakkeeseen. Orders -taulue
-- ei esiinny esimerkissä.
CONSTRAINT `orderdetails_ibfk_1` FOREIGN KEY (`orderNumber`) REFERENCES `orders` (`orderNumber`),

-- Luodaan viittaus products taulun productCode sarakkeeseen.
CONSTRAINT `orderdetails_ibfk_2` FOREIGN KEY (`productCode`) REFERENCES `products` (`productCode`)
```

Edellä on siis vain kuvattu **orderLines** -taulun viiteavaimet. Kuvassa oleva **productLines** -taulu ei sisällä viiteavaimia vaan lähinnä siihen viitataan **products** -taulussa. Katsotaan siis vielä tarkemmin aiemmin esitellyn **products** -taulun luontikomennosta, miltä sen viiteavaimet näyttävät.

```sql
-- Rivi 14 pääavaimen kohdalla esitetyssä esimerkissä.
CONSTRAINT `products_ibfk_1` FOREIGN KEY (`productline`) REFERENCES `productlines` (`productline`) 
```

Viiteavaimesta voimme siis nähdä, että **products** -taulussa on sarake **productline**, joka viittaa **productLines** -taulun **productline** -sarakkeeseen, joka taas on sen pääavain.

## Rajoitteet

Tietokantojen kohdalla puhutaan usein myös rajoitteista. Pää- ja viiteavaimet itsessään ovat tietynlaisia rajoitteita miten tietokanta toimii. On myös olemassa muutama muu rajoite, jotka yhdistetään pää- ja viiteavaimiin. Tässä kohdin voidaan puhua viittaussäännöistä, jotka pyrkivät huolehtimaan tietokannan tiedon eheydestä.

Säännöt jaetaan kahteen eri osaa:

* `ON DELETE [käyttäytymissääntö]` - määrittää tapahtuvan, jonkin alla olevista säännöistä kun rivi poistetaan.
* `ON UPDATE [käyttäytymissääntö]` - määrittää tapahtuvan, jonkin alla olevista säännöistä kun rivin tietoja päivitetään.

Näille kahdelle säännöille on olemassa tarkemman käyttäytymismallinsa, joita on pääasiassa viisi:

* `CASCADE` - jos päätaulun rivi poistetaan tai päivitetään, lapsitaulussa olevat viitatut rivit poistetaan tai päivitetään automaattisesti.
* `SET NULL` -  jos päätaulun rivi poistetaan tai päivitetään, lapsitaulussa olevien viittaus-sarakkeiden arvot asetetaan tyhjiksi. (NULL)
* `RESTRICT` - jos lapsitauluissa on viittauksia päätauluun, tietokanta itsessään estää poistamasta tai päivittämästä päätaulun rivejä.
* `NO ACTION` - on sama kuin edellä mainittu RESTRICT
* `SET DEFAULT` - Mysql syntaksissa komento tunnistetaan mutta ei voi käyttää InnoDB tyyppisen tietokannan kanssa. Eli ei usein tarvita vaan voidaan käyttää esimerkiksi SET NULL -sääntöä tämän sijasta.

Edellä mainittiin **pää- ja lapsitaulut**. Käsite on hyvä tuntea. Englanninkielisissä lähteissä puhutaan usein *Parent tables* ja *Child tables* nimityksillä. Nämä ovat tärkeitä, jotta voidaan ymmärtää edellisten sääntöjen vaikutus. Otetaan esimerkki jo aiemmin esitettyjen taulujen kohdalta.

![Päätaulu ja lapsitaulut](/files/-LoqW2g9V3fo05w10XlK)

Harjoitustietokannassa ei ole määritetty `ON DELETE` tai `ON UPDATE` sääntöjä. Tällöin oletuksena Mysql käyttää tämän tyyppisessä tilanteessa sääntöä `RESTRICT`. Säännöt tulisi määrittää viiteavainten luonnin yhteydessä seuraavanlaisella komennolla.

```sql
-- Tämä on siis osa CREATE TABLE komentoa, jolloin
-- voidaan määrittää nämä säännöt.
-- Esimerkissä sääntönä on, että arvot asetetaan tyhjäksi,
-- jos viittauksia on lapsitauluissa.
CONSTRAINT fk_category
    FOREIGN KEY (categoryId) 
        REFERENCES categories(categoryId)
        ON UPDATE SET NULL
        ON DELETE SET NULL
```

**Päätauluksi** kutsutaan sitä taulua, jossa pääavain sijaitsee. Edellisessä esimerkissä **productlines** ja **products** -taulut ovat kummatkin päätauluja. Suhde niiden välillä määräytyy vasta tarkemmin viittauksia tarkaltaessa.

**Lapsitauluksi** kutsutaan sitä taulua, jossa on viittauksia muiden taulujen pääavaimiin eli sisältävät viiteavaimia. Esimerkissä **orderdetails** ja **products** -ovat lapsitauluja. Suhde määräytyy taas kun viittauksia tarkastellaan lähemmin.

Kun puhutaan **products** taulusta niin:

* taulu sisältää pääavaimen **productCode**. (on tässä päätaulu)
* taulu sisältää viiteavaimen **productLine**, joka viitaa **productLines** -tauluun. (on tämän mukaan myös **productLines** -taulun lapsitaulu.)
* **orderDetails** -taulu sisältää viittauksen **products** -taulun **productCode** -pääavaimeen, joten **orderDetails** on lapsitaulu **products** -taulun näkökulmasta.

Muutamia esimerkkejä käytännössä on esitetty lähteissä, jotka näyttävät eri sääntöjen vaikutuksista: <http://www.mysqltutorial.org/mysql-foreign-key/>

Esimerkit tullaan myöhemmin lisäämään myös tänne mutta sääntöja pitäisi olla helppo tulkita kun ne tietää. On kuitenkin tärkeää huomata, että tietokantaa suunnitellessa on pistetty ylös mitä sääntöä tulisi käyttää oletuksena. Kun eri sääntöjä sekoitetaan paljon niin ne aiheuttavat vaikeuksia päivittää tietokantaa. Kannattaa siis pysyä esimerkiksi `CASCADE` tai turvallisemmassa `RESTRICT` säännössä, jos nämä eivät ole tuttuja.

## Lähteitä

{% embed url="<https://stackoverflow.com/questions/1027656/what-is-mysqls-default-on-delete-behavior>" %}


# ER kaaviot

Luvussa käsitellään Entity Relationship -kaavioita. Lyhennettynä ER tai ERD riippuen lähteistä. Niiden tarkoitus on olla apuna tietokannan suunnittelussa sekä kommunikoinnissa.

## Kaavioiden tarkoitus

Tietokantasuunnittelussa yksi osa-alue on kuvata tietokantarakennetta. Todellinen rakenne tiedetään kun se on toteutettu mutta monet ongelmat voi ratkaista paperilla. Jotta rakenteiden tulkinta olisi ymmärrettävämpää usean henkilön kanssa, on tätä varten luotu erilaisia kuvaustapoja.

ER -kaavio eli Entity Relationship Diagram kuvaa taulujen välisiä suhteita sekä niiden sisältöjä. Esimerkki kaaviosta alla.

![http://www.mysqltutorial.org/mysql-sample-database.aspx](/files/-LpdZfh7z4-7pG1dZIo8)

## Termistön läpikäynti

**Entiteetti (eng. entity)** - tarkoittaa käsiteltävää asiaa, esinettä, aihetta tai muuta kuvattua asiaa. Taulua voidaan kutsua myös tällä termillä.

**Attribuutti (eng. attribute)** - tarkoittaa entiteettiä kuvaavia asioita. Esimerkiksi autolla voi olla väri, malli tai  renkaiden koko. Sellaiset asiat mitkä ovat tyypillisiä kuvattaville asioille. Taulujen sarakkeita kutsutaan myös siis termillä attribuutti.

**Suhde (eng. relationship)** - tarkoittaa kahden entiteetin välistä suhdetta miten ne ovat yhteydessä toisiinsa. Kaavioissa tämä on kuvattu viivana ja viivan päissä oleva merkintä voi tarkentaa suhteen muotoa.

**Notaatio (eng. notation)** - tarkoittaa yksinkertaisesti kuvaustapaa. Voidaan puhua, että kaavio on kuvattu UML notaatiolla. Esimerkeissä käytämme variksen varpaita. (Crow's Foot)

## Taulujen väliset suhteet

Tietokantoja suunnitellessa on tärkeää tuntea taulujen väliset suhteet ja niiden kuvaustavat. Kyseessä ei ole sen erityisempi asia kuin, että tarkoitus on kuvata tietokannan sisältämän tiedon keskinäisiä suhteita. Esimerkiksi, jos opiskelija voi osallistua useammalle kurssille, voidaan tällöin sanoa, että opiskelijan ja kurssin välillä on eräänlainen suhde mikäli se mallinnetaan tietokannaksi. Näitä suhteita siis löytyy arkielämästä asioista, joita tietokanta sisältää.

Tietojen välillä voi olla seuraavia suhteita:

* Yksi suhde yhteen (eng. One-to-One)
* Yksi suhde moneen (eng. One-to-Many)
* Moni suhde yhteen (eng. Many to One)
* Moni suhde moneen (eng. Many-to-Many)

**Yksi suhde yhteen** - tarkoittaa sellaista suhdetta kahden asian välillä, joita voi olla olemassa vain yksi kerrallaan. Esimerkkinä voisimme ajatella autovuokraamoa. On sovittu, että vuokraajalla voi olla vain yksi auto vuokralla kerrallaan ja auto voi olla vain yhdellä vuokraajalla. Voisimme esittää suhteen seuraavalla kaaviolla.

![Yksi suhde yhteen](/files/-LpACyrWHz3veQv_jpC2)

**Yksi suhde moneen** - tarkoittaa sellaista suhdetta, jossa asia voi esiintyä usean kerran. Jatkaaksemme edellistä esimerkkiä voimme ajatella, että toimipisteellä voi olla useita vuokra-autoja mutta auto voi kuulua vain yhteen toimipisteeseen. Tällainen suhde voidaan kuvata seuraavalla kaaviolla.

![Yksi suhde moneen](/files/-LpdcFbe5zVSTT4lmC_O)

**Moni suhde yhteen** - tarkoittaa pitkälti samankaltaista suhdetta kuin yllä oleva esimerkki. Kyse on lähinnä näkökulmasta miten asiaa tarkastellaan. Esimerkin vuoksi voimme ajatella, että usea vuokra-auto kuuluu samalle toimipisteelle ja kuvata sen seuraavasti. Huomaa, että entiteetit ovat käännetty ympäri.

![Moni suhde yhteen](/files/-Lpdd8-UzSwuJe-aU1VK)

**Moni suhde moneen** - tarkoittaa suhdetta, jossa kaksi entiteettiä voi esiintyä pareittain usealla eri tavalla. Esimerkissämme voimme ajatella, että vuokra-auton voi varata useampi henkilö ja henkilö voi vuokrata useita eri autoja. Suhde kuvattaisiin seuraavalla tavalla.

![Moni suhde moneen](/files/-Lpdfc7wdsfoXZoWA2RA)

Pääasiassa tärkeimmät suhteet on kuvattu yllä. Lähestulkoon kaikki toimivat näiden mallien mukaisesti yhdistellen. Esimerkeissä on käytetty kuvaamiseen [Crow's Foot (variksen varpaat)](http://www2.cs.uregina.ca/~bernatja/crowsfoot.html) notaatiota. Esimerkeissä ei käyty läpi kaikkia eri kuvaustapoja vaan yksittäisillä viivoilla on merkityksensä, joilla voidaan vielä tarkentaa niiden merkitystä. Käydään yksittäiset merkintätavat läpi vielä.

![](/files/-LpdixSZ4TF3Uqk2_07F)

Kuvaustapoja tarkastelemalla voimme vielä todeta, että ne eivät aina selitä itseään. Siksi on tärkeää tarvittaessa perustella mikä liitos on tai mitä sillä tarkoittaa. Usein liitos voidaan pukea lauseeksi. Esimerkiksi

* *Opiskelijan on kuuluttava vähintään yhteen vuosiryhmään, vuosiryhmään voi kuulua useampi opiskelija.*
* *Opiskelijalla voi kerrallaan olla yksi käynnissä oleva moduuli, moduulissa voi olla vähintään yksi tai useampi opiskelija.*

Kaavioissa voidaan korostaa vielä suhteita esimerkiksi kirjoittamalla suhdetta kuvaavan viivan päälle mitä se tarkoittaa.

![Suhteen kuvaus](/files/-LpdlFUaKgputA2JnawL)

Kun tiedetään miten suhteita kuvataan, niitä voidaan aina tarkentaa. Esimerkiksi heti alussa esitetty tietokantamallin kuva sisältää taulujen nimiä ja sarakkeita. Näillä voidaan vielä selkeästi tarkentaa miten yhteydet on muodostettu asioiden välille.

Huomaa kuitenkin, että kuvaustapa ei välttämättä kerro miten teknisesti suhde toteutetaan. Esimerkiksi Mysql -tietokannassa suhde voidaan luoda eri tavoin. Kaavion onkin tarkoitus olla ohjeistus miten tietokantamallin tulisi toimia mutta toteutustapa voi eroa eri relaatiotietokannoissa. Ota aina tarvittaessa selvää miten näitä tulee toteuttaa. **Moni suhde moneen** -tilanteissa on hyvin tyypillistä luoda ns. liitostaulu.

## Taulujen väliset suhteet SQL kielellä

[Tutustu pää- ja viiteavaimiin](/relaatiotietokannat/paeae-ja-viiteavaimet). SQL kielessä nämä suhteet luodaan käyttäen kyseisiä avaimia ja tarvittaessa erilaisia taulurakenteita. Myös mahdollisesti `UNIQUE` määrityksen käyttäminen sarakkeissa on tarpeen.

## Muita notaatioita

Esimerkeissä on käytetty notaatioina variksen varpaita. Se on yksi tunnetuista tavoista mutta kuvaustapoja on myös useita muita. Tarvittaessa ota selvää mikä kuvaustapa on, jotta osaat tulkita suhteet. Joitakin kuvaustapoja on lueteltu alla olevassa lähteessä.

{% embed url="<https://en.wikipedia.org/wiki/Entity%E2%80%93relationship_model#Cardinalities>" %}

## Lähteet

{% embed url="<https://www.guru99.com/er-diagram-tutorial-dbms.html>" %}

{% embed url="<http://www.mysqltutorial.org/mysql-sample-database.aspx>" %}

{% embed url="<https://stackoverflow.com/questions/3113885/difference-between-one-to-many-many-to-one-and-many-to-many>" %}


# Viite-eheys ja ACID

Tietokannan tärkeimpiä ominaisuuksia on tiedon eheyden ylläpitäminen. Tämä tapahtuu useiden eri toiminnollisuuksien avulla ja on tärkeä asia tietää tietokanta suunnittelun näkökulmasta. Kaikki tietokantaohjelmistot eivät toteuta eheyteen liittyviä ominaisuuksia samalla tavoin, joten on aina hyvä tutustua vieraaseen tietokantaohjelmistoon ensin.

Seuraavassa yhteenvedossa on käsitelty Mysql viite-eheydet sekä ACID -periaatteet mitä niillä tarkoitetaan.

## ACID -periaate

ACID tarkoitetaan joukkoa tietokantajärjestelmien periaatteita ja ominaisuuksia ja lyhenne tulee seuraavista sanoista:

* Atomisuus (Atomicity)
* Eheys (Consistency)
* Eristyneisyys (Isolation)
* Pysyvyys (Durability)

Periaatteiden tarkoituksena on turvata tietokannan tietojen eheys kaikissa tilanteissa. Ominaisuudet ovat käytössä useimmissa tietokantaohjelmistoissa, jotta niitä ei tarvitsisi toteuttaa itse ja sen vuoksi tietokannan käyttäminen oikein on tärkeä huomioida.

Mysql -tietokannan kanssa huomioitavaa on, että **InnoDB** -tietomalli (moottori, storage engine) toteuttaa ACID -periaatteet. MyISAM -ei näitä toteuta, joten tarkista tarvittaessa mitä tapaa tietokannassa käytetään.

### Atomisuus

Tarkoitetaan transaktion suorittamista kokonaan tai ei laisinkaan.

Transaktiolla tarkoitetaan erilaisia tietokantaoperaatioita, jotka on esimerkiksi tarkoitus suorittaa kokonaisuutena.

### Eheys

Tarkoitetaan sitä, että tietokannan tieto on eheää (ehjä, rikkoutumaton).

Kun tietokanta muuttaa tilaansa transaktioiden yhteydessä, huolehtii tietokanta siitä, että tiedon tila on eheä myös lopputilanteessa.

### Eristyneisyys

Tarkoitetaan transaktioiden olevan eristettyjä toisistaan ja toimivat yksinään. Toinen transaktio ei voi siis vaikuttaa toisen suoritukseen.

### Pysyvyys

Tarkoitetaan tiedon pysyvyyttä transaktioiden jälkeen, joka pyritään siihen, että tieto ei katoa enää järjestelmästä.

## Viite-eheys

Viite-eheys toteutetaan viiteavaimilla ja sillä tarkoitetaan sitä, että tietokannan lapsitauluun ei voida merkitä tietoa mitä ei esiinny sen päätaulussa.

Lapsitaulu (child table) on sellainen, jossa on viitevain toiseen tauluun. Tämä toinen taulu on kyseisen taulun päätaulu (parent table) tai monissa lähteissä on käytetty myös termiä "äititaulu".

![Esimerkki pää- ja lapsitauluista.](/files/-Lp56iXHQR0-ngUDeuup)

Yllä olevassa kuvassa on esimerkki pää- ja lapsitauluista. Taulu, joka esiintyy lapsitauluna riippuu aina näkökulmasta ja siitä missä viiteavain esiintyy.

Taulu **televisiosarjat** on *päätaulu*, jos tarkastellaan sen yhteyttä **luojat** tauluun. **Luojat** taulu on siis tässä tilanteessa **televisiosarjat** taulun *lapsitaulu*. Tämä johtuu siitä, että **luojat** taulussa on *viiteavain -kenttä (tvsarja\_id)*, joka viittaa **televisiosarjat** taulun *pääavaimeen (id -kentttä)*.

Kun kyseessä on taas **tyylilajit** taulu niin **televisiosarjat** taulu on *lapsitaulu* ja tyylilajit on *päätaulu*. Tämä johtuu siitä, että **televisiosarjat** taulussa on *viiteavain -kenttä (tyylilajin\_id)*, joka viittaa **tyylilajit** taulun *pääavaimeen (tyylilajin\_id)*.

Kolmantena esimerkkinä on **televisiosarjat\_tvkanavat** liitostaulu. Tässä tilanteessa kyseinen liitostaulu on *lapsitaulu* **televisiosarjat** ja **tvkanavat** tauluille. Tällöin **televisiosarjat** ja **tvkanavat** taulut ovat *päätauluja* liitostaululle.

Näiden välisten yhteyksien huomiointi on tärkeää, koska [viitevainten rajoitussäännöissä](/relaatiotietokannat/paeae-ja-viiteavaimet#rajoitteet) on määritelmiä siitä miten tietokannan taulut tulevat keskenään lopulta toimimaan.

Lue lisää viittaustavoista [ER kaaviot](/relaatiotietokannat/er-kaaviot) yhteenvedosta.

## Lähteet

{% embed url="<https://fi.wikipedia.org/wiki/ACID>" %}

{% embed url="<https://en.wikipedia.org/wiki/ACID>" %}

{% embed url="<https://en.wikipedia.org/wiki/Atomicity_(database_systems)>" %}

{% embed url="<https://en.wikipedia.org/wiki/Consistency_(database_systems)>" %}

{% embed url="<https://en.wikipedia.org/wiki/Isolation_(database_systems)>" %}

{% embed url="<https://en.wikipedia.org/wiki/Durability_(database_systems)>" %}

{% embed url="<https://dev.mysql.com/doc/refman/5.7/en/mysql-acid.html>" %}


# SQL JOIN -lauseke

Artikkelissa käydään läpi mikä JOIN -lausekkeen tarkoitus SQL -kielessä. Jos et ole opetellut SQL perusteita niin se kannattaa käydä ensin läpi.

## Mikä on JOIN -lausekkeen tarkoitus?

SQL -kielissä JOIN -lauseke esiintyy vahvasti osana hakukyselyjä. JOIN voi esiintyä myös tietoja lisättäessa (INSERT), päivittäessä (UPDATE) tai poistaessa (DELETE). Alla esimerkki perinteisestä JOIN -ehdon sisältämästä kyselystä.

{% code title="JOIN\_esimerkki\_01" %}

```sql
SELECT asiakkaat.customernumber, 
       tilaukset.ordernumber, 
       tilaukset.orderdate, 
       tilaukset.status 
FROM   customers AS `asiakkaat` 
       LEFT JOIN orders AS `tilaukset` 
              ON asiakkaat.customernumber = tilaukset.customernumber 
ORDER  BY asiakkaat.customernumber ASC 
```

{% endcode %}

Yllä olevassa esimerkissä on kuvattu kuinka JOIN -ehto on lisätty kyselyn osaksi. *(rivi 6)* Esimerkin LEFT JOIN on yksi ehto mutta SQL kielessä on muutamia ehtoja taulujen liittämiseen. JOIN -ehdot toimivat eräänlaisina suodattimina WHERE ehdon tapaan.&#x20;

SQL -kielten kehityksen historiassa tällaiset liitokset on voitu tehdä WHERE ehdolla. JOIN -siis esittelee vain erilaisen tavan koostaa taulujen tietoja yhteen hakuja varten. JOIN -myös ratkaisee joitakin ongelmia mitkä pelkillä WHERE -ehdoilla on ollut vaikeata tai monimutkaista toteuttaa.

{% hint style="info" %}
Muista seuraavat:

* JOIN tarkoittaa käytännössä kahden eri taulun tietojen koostamista yhdeksi tulosjoukoksi.
* JOIN -ehtoja voi sisällyttää kyselyyn myös useamman kuin yhden.
* JOIN -ehdon tyyppi määrittää sen mitä lopulliseen tulosjoukkoon saadaan koostettua.
  {% endhint %}

Seuraava kuva havainnollistaa taulujen liittämistä JOIN -ehdon avulla yllä olevan esimerkin kaltaisessa tilanteessa. Seuraavissa esimerkeissä käymme läpi pääasialliset JOIN -ehdot, joilla voi vaikuttaa lopulliseen tilanteeseen.

![Esimerkki JOIN lauseen tarkoituksesta](/files/-Log4VPeLz7LuIRXqMo-)

Esimerkin kuvassa ei esiinny kaikkia tietoja taulusta, jotta se olisi selkeämpi. Kuvassa esiintyvä välitaulukko on nimensämukaisesti väliaikainen taulu, jota SQL käyttää apunaan kyselyä tehdessä. Välitaulukko on olemassa vain palvelimen muistissa sen aikaa kun sitä tarvitaan ja se poistuu tämän jälkeen. Se ei esiinny missään oikeana tauluna tietokannan näkökulmasta.

Välitaulukko sisältää  tietoja mitä kahdessa laidalla olevissa tauluissa ei näy. Lähteissä on mainittu sivusto, josta harjoitustietokanta on ladattu. Kuvan esimerkissä punaisella on rajattu hakukyselyssä käytetty ehto eli kaksi taulua on liitetty asiakasnumeron perusteella toisiinsa.

Tauluja voi olla useampiakin kuin kaksi. Tällainen tilanne on esitelty tässä artikkelissa myöhemmin. Käytäntö on kuitenkin sama, että taulut liitetään esimerkin mukaisesti yhteen. **SQL kuitenkin suorittaa taulujen JOIN -komennot järjestyksessä ja käyttää aina edellisen JOIN -lausekkeen tulosjoukkoa seuraavassa liitoksessa.**

![https://en.wikipedia.org/wiki/Join\_(SQL)#/media/File:SQL\_Join\_-\_01\_A\_Left\_Join\_B.svg](/files/-Log6HmHbnFGYdu2Ollm)

Taulujen väliset liitokset esitellään usein eri lähteissä yllä olevan tapaisella [Vennin diagramilla](https://fi.wikipedia.org/wiki/Venn-diagrammi). Vennin diagrammiin on hyvä tutustua mutta se on matematiikassa joukko-opissa käytettävä diagrammi. Sen tarkoituksena on kuvata joukon välisiä suhteita. Esimerkin kuvassa on esitetty LEFT JOIN -liitos ja diagrammia tullaan käyttämään artikkelissa eri liitosten havainnollistamisessa.

Esimerkin kuvan voi lyhyesti lukea seuraavasti:

* Joukko A on tässä esimerkin taulu asiakkaat.
* Joukko B on tässä esimerkin taulu tilaukset.
* Esimerkin LEFT JOIN palauttaa tässä kaikki rivit joukosta A, vaikka ne eivät esiintyisi joukossa B. Puuttuvat arvot saavat arvon NULL.

Myöhemmin eri JOIN -ehdot on selitetty niiden omissa osioissa auki, että mitä esiintyy lopullisessa tulosjoukossa.

## INNER JOIN -selitettynä

> INNER JOIN palauttaa kaikki rivit, jotka esiintyvät molemmissa tauluissa ehdon mukaisesti.

![INNER JOIN -kuvattuna Vennin diagrammina](/files/-LogCo7d1Ujrxa-4h-Jp)

Kyseinen liitostyyppi on hyvin yleinen ja usein oletustapa miten SQL -liittää tauluja yhteen ellei muuta tapaa ole erikseen kerrottu. **Mysql** -tietokannassa tämä on oletusliitos.

{% hint style="info" %}
Seuraavan esimerkin vuoksi on hyvä muistaa, että harjoitustietokannassa **customers** taulu sisältää 122 riviä. **Orders** taulu sisältää 326 riviä.
{% endhint %}

{% code title="inner\_join\_esimerkki" %}

```sql
SELECT asiakkaat.customernumber, 
       tilaukset.ordernumber, 
       tilaukset.orderdate, 
       tilaukset.status 
FROM   customers AS `asiakkaat` 
       INNER JOIN orders AS `tilaukset` 
               ON asiakkaat.customernumber = tilaukset.customernumber 
ORDER  BY `customernumber` ASC;
```

{% endcode %}

**SELECT kysely selitettynä**

* **Rivi 5:** FROM kertoo, että ensimmäinen taulu on customers.
* **Rivi 6:** INNER JOIN määrittää, että tehdään liitos orders tauluun.
* **Rivi 7:** ON kertoo ehdon eli liitetään taulut käyttäen niiden customernumber -saraketta.
* **HUOM!** rivillä 6 join voitaisiin kirjoittaa myös ilman INNER avainsanaa, koska se on oletustapa Mysql -tietokannassa.

Kun esimerkin mukainen kysely suoritetaan harjoitustietokantaa vasten, saadaan vastaukseksi 326 riviä. Alla kuvakaappaus osasta tuloksista.

![INNER JOIN esimerkin tulos](/files/-LogGqSx67VcTpBj4YOa)

**Mistä tulosjoukko muodostuu?**

Ensimmäisenä voidaan huomata, että 326 riviä on yhtä paljon kuin **orders** -taulun sisältämä rivien määrä. Kuvasta näkyy myös, että **customerNumber** -kentässä esiintyy useamman kerran sama asiakastunniste.

INNER JOIN hakee tulokseksi siis niiden asiakkaiden tilaukset, joiden asiakastunniste esiintyy **orders** -taulussa. **Orders** -taulussa ei esiinny tilauksia kaikille asiakkaille ja tällöin tulosjoukko ei sisällä näitä asiakkaita, joilla tilauksia ei ole vielä yhtään.

![Esimerkki inner join liitoksesta](/files/-LogRrKfV7-ipSCiQ61c)

Yllä oleva pelkistetty kuva havainnollistaa vielä INNER JOIN -lausekkeen käyttäytymistä.&#x20;

* **Vihreä** **customerNumber** sarake esittää kahden taulun välistä liitosehtoa. Taulut liitetään siis asiakastunnisteen perusteella.
* **Sininen tausta** havainnolistaa vasemman taulun tietoja. (asiakkaat)
* **Keltainen tausta** havainnollistaa oikean taulun tietoja. (tilaukset)

Tulosjoukko on siis INNER JOIN kyselyn tulos. Siitä nähdään, että mitkä rivit ovat valikoituneet lopuksi. Liitos valitsee vain ne asiakkaat, jotka esiintyvät **tilaukset** -taulussa. Kun siis katsot tarkkaan tulosjoukkoa niin huomaat, että asiakkaat *Jean* ja *Peter* puuttuvat alapuolella olevasta yhteenvedosta. Heillä ei siis ole yhtään tilausta esimerkin mukaan.

Ne asiakkaat, joilla on tilauksia niin esiintyvät tulosjoukossa. Huomaa kuitenkin, että jos tilaukset -taulu sisältää tässä kohdin useita tilauksia samalta asiakkaalta, asiakasrivi monistuu tulosjoukossa. Esimerkiksi asiakas *Janine* ja *Carine* ovat tehneet kaksi tilausta.

Tällainen tietojen monistuminen on hyvin yleistä JOIN -kyselyissä ja tulee ottaa huomioon. Riippuen tietokantojen [normalisointisääntöjen](https://fi.wikipedia.org/wiki/Tietokannan_normalisointi) noudattamisesta, nämä eivät ole usein vakavia. Jos normalisointisääntöjen noudattaminen on laiminlyöty pahasti niin silloin tietojen monistuminen saattaa olla ongelma. Tarkoittaa käytännössä sitä, että tietokannassa ei välttämättä ole toteutettu oikeanlaisia viiteavaimia tai sarakkeiden sisältävien tietojen purkamista pienempiin itsenäisiin kokonaisuuksiin.

Seuraava lähde havainnollistaa tätä liitosta pienellä animaatiolla. <https://dataschool.com/how-to-teach-people-sql/inner-join-animated/>

## LEFT JOIN -selitettynä

> LEFT JOIN -palauttaa kaikki rivit vasemmasta joukosta (taulusta) VAIKKA ne eivät esiintyisi oikeanpuoleisessa joukossa (taulussa). Puuttuvat tiedot merkitään NULL -arvoisiksi.

![LEFT JOIN -kuvattuna Vennin diagrammina](/files/-Log6HmHbnFGYdu2Ollm)

Liitos tulee hyvin usein vastaan ja toimii samankaltaisesti monessa eri SQL -tietokannassa. Liitoksesta löytyy myös LEFT OUTER JOIN -variaatio mikä tarkoittaa sitä, että se palauttaa vain A -joukon rivit. Tämä tarkoittaa, että voitaisiin saada tulokseksi ne rivit, jotka eivät esiinny B joukossa. Tämä variaatio on käyty läpi alempana ensimmäisen esimerkin jälkeen.

{% code title="left\_join\_esimerkki" %}

```sql
SELECT asiakkaat.customernumber, 
       tilaukset.ordernumber, 
       tilaukset.orderdate, 
       tilaukset.status 
FROM   customers AS `asiakkaat` 
       LEFT JOIN orders AS `tilaukset` 
               ON asiakkaat.customernumber = tilaukset.customernumber 
ORDER  BY `customernumber` ASC;
```

{% endcode %}

{% hint style="info" %}
Esimerkin kysely on aivan samanlainen kuin INNER JOIN -esimerkissä. Nyt LEFT JOIN esiintyy vain INNER JOIN -tilalla.
{% endhint %}

Kun esimerkin mukainen kysely suoritetaan harjoitustietokantaa vasten, saadaan vastaukseksi 350 riviä. Alla kuvakaappaus osasta tuloksista.&#x20;

![Esimerkki LEFT join kyselyn tulosjoukosta](/files/-LogXZLVWzPkqLWcLnLj)

**Mistä tulosjoukko muodostuu?**

Huomioi heti alkuun, että tilauksia on vain tietokannassa 326 riviä. Asiakkaitakin vain 122 riviä. Mistä siis tulevat nämä 350 riviä?

Tulosjoukosta huomaat myös, että se sisältää rivejä, joissa on NULL -arvoja. NULL tarkoittaa tässä, että vasemman puoleisen taulun (asiakkaat) tietoja ei löytynyt oikeanpuoleisesta taulusta (tilaukset). Kuitenkin **LEFT JOIN** -ehdon määritelmä on se, että sisällytä **KAIKKI** vasemmanpuoleisen taulun tulokset **SEKÄ** oikeanpuoleisen taulun tulokset, jotka osuvat JOIN ehtoon.

Edellä mainittu asia on tärkein muistettava seikka. INNER JOIN -esimerkistä muistat, että se sisälsi vain 326 riviä, joka oli yhtä paljon kuin **tilaukset** -taulussa olevien rivien määrä. Nyt LEFT JOIN -tilanteessa näiden tilauksien lisäksi tulosjoukkoon tulevat siis asiakkaiden tiedot vaikka heillä ei olisi yhtään tilausta.

![Esimerkki left join liitoksesta](/files/-Log_s3Z2JRb-g-gBdmh)

Yllä oleva pelkistetty kuva havainnollistaa vielä LEFT JOIN -lausekkeen käyttäytymistä.&#x20;

* **Vihreä** **customerNumber** sarake esittää kahden taulun välistä liitosehtoa. Taulut liitetään siis asiakastunnisteen perusteella.
* **Sininen tausta** havainnolistaa vasemman taulun tietoja. (asiakkaat)
* **Keltainen tausta** havainnollistaa oikean taulun tietoja. (tilaukset)

Tulosjoukko muistuttaa tässä tilanteessa paljon INNER JOIN -esimerkin tulosjoukkoa. Erona on kuitenkin tällä kertaa asiakkaiden *Jean* ja *Peter* rivit, jotka ovat mukana tulosjoukossa mutta tilaustietoina heillä ei ole mitään. Nämä asiakkaat puuttuivat INNER JOIN -esimerkin tulosjoukosta.

Tämän liitoksen avulla voitaisiin siis nähdä myös asiakkaat, joilla ei ole vielä yhtään tilausta. Käytännön esimerkkinä tilanne, jossa näille asiakkaille voitaisiin suunnnata jonkinlaista markkinointia, että saadaan heidät tekemään ostopäätös.

Seuraavasta lähteestä löydät myös animoidun version liitoksen käyttäytymisestä: <https://dataschool.com/how-to-teach-people-sql/left-right-join-animated/>

**LEFT OUTER JOIN -variaatio**

Liitoksesta on myös mahdollista tehdä variaatio, jossa haettaisiin vain ne asiakkaat, joilla ei ole yhtään tilausta. Tämä onnistuisi seuraavanlaisella hakulauseella, joka on muokattu esimerkistä:

{% code title="left\_join\_esimerkki\_null" %}

```sql
SELECT asiakkaat.customernumber, 
       tilaukset.ordernumber, 
       tilaukset.orderdate, 
       tilaukset.status 
FROM   customers AS `asiakkaat` 
       LEFT JOIN orders AS `tilaukset` 
              ON asiakkaat.customernumber = tilaukset.customernumber 
WHERE  tilaukset.customernumber IS NULL 
ORDER  BY `customernumber` ASC;
```

{% endcode %}

{% hint style="info" %}
Esimerkissä ero on rivillä 8, jossa määritetään haettavan vain ne rivit, joissa tilaukset taulun asiakastunniste on arvoltaan NULL. Huomioi, että tällaisia arvoja ei ole **orders** -taulussa vaan NULL tulee tulosjoukkoon LEFT JOIN -liitoksen vuoksi.
{% endhint %}

Kun esimerkin mukainen kysely suoritetaan niin tulosjoukosta huomataan, että nyt palautuu vain asiakastietoja, joissa tilauksien kentät ovat tyhjiä. Tällaisia asiakkaita on 24 riviä. Kun taas muistetaan, että **orders** -taulu sisälsi alunperin 326 tilausta niin summaamalla nämä luvut (326+24) saamme yhteismääräksi 350 riviä eli juurikin LEFT JOIN -esimerkin mukaisen tulosjoukon.

![left join variaatio esimerkki](/files/-LogcmJIovGR7HxO-_U4)

## RIGHT JOIN -selitettynä

> RIGHT JOIN -palauttaa kaikki rivit oikeanpuoleisesta joukosta (taulusta) VAIKKA ne eivät esiintyisi vasemmanpuoleisessa joukossa (taulussa). Puuttuvat tiedot merkitään NULL -arvoisiksi.

![RIGHT JOIN kuvattu Vennin diagrammina](/files/-LogegFJc5WIg3OA0i4M)

Liitoksista RIGHT JOIN ei ole kovin yleinen. Usein huomataan, että tämänkaltaiset liitokset voidaan kuvata myös LEFT JOIN -ehtoina. Periaate kummassakin on samanlainen. Tällöin olemme kiinnostuneet vain B joukon sisällöstä.

{% code title="right\_join\_esimerkki" %}

```sql
SELECT asiakkaat.customernumber, 
       tilaukset.ordernumber, 
       tilaukset.orderdate, 
       tilaukset.status 
FROM   customers AS `asiakkaat` 
       RIGHT JOIN orders AS `tilaukset` 
               ON asiakkaat.customernumber = tilaukset.customernumber 
ORDER  BY `customernumber` ASC;
```

{% endcode %}

{% hint style="info" %}
Ainoa ero LEFT JOIN esimerkkiin on rivin 6 muutos, jossa on määritetty RIGHT JOIN.
{% endhint %}

![Esimerkki RIGHT JOIN -tulosjoukosta](/files/-Logg1j8UpvvjIldf3WV)

Kun esimerkin kaltainen kysely suoritetaan harjoitustietokantaan, saadaan tulosjoukoksi 326 riviä. Määrä vastaa **orders** -taulun rivimäärää. Tässä esimerkissä määrä ei eroa INNER JOIN -liitoksen tulosjoukosta, koska nyt valitsemme oikeanpuoleisesta taulusta pääasiallisesti **KAIKKI** tiedot.

**Orders** -taulu on siitä syystä "oikeanpuolimmainen", koska se esiintyy JOIN kyselyssä. FROM kyselyssä on siis ensin mainittu **customers** taulu. SQL suorittaa kyselyt vasemmalta oikealle järjestäen eli tässä tilanteessa juurikin aina ensin mainittu taulu on vasemmanpuoleinen.

{% code title="right\_outer\_join\_esimerkki" %}

```sql
SELECT asiakkaat.customernumber, 
       tilaukset.ordernumber, 
       tilaukset.orderdate, 
       tilaukset.status 
FROM   customers AS `asiakkaat` 
       RIGHT JOIN orders AS `tilaukset` 
              ON asiakkaat.customernumber = tilaukset.customernumber 
WHERE  asiakkaat.customernumber IS NULL 
ORDER  BY `customernumber` ASC;
```

{% endcode %}

**RIGHT OUTER JOIN** -variaatio muodostetaan ylläolevan esimerkin mukaisesti. Muistuttaa tilannetta LEFT JOIN kohdalla. Huomaa kuitenkin rivillä 8, että nyt ehtona on, että **customers** (asiakkaat) -taulun asiakastunniste on tyhjä. Tällaista tilannetta ei kuitenkaan löydy harjoitustietokannasta ja tulosjoukko on tyhjä.&#x20;

Alla on esitelty esimerkki käyttäen **employees (työntekijät)** -taulua, jossa voidaan esitellä paremmin RIGHT JOIN -liitos.

{% code title="right\_join\_esimerkki\_02" %}

```sql
SELECT tyontekijat.employeenumber, 
       asiakkaat.customernumber 
FROM   customers AS `asiakkaat` 
       RIGHT JOIN employees AS `tyontekijat` 
               ON asiakkaat.salesrepemployeenumber = tyontekijat.employeenumber 
ORDER  BY tyontekijat.employeenumber;
```

{% endcode %}

![Right join tulosjoukon esimerkki 02](/files/-LogigPkKnDQ4I1YMuAI)

Customers -taulu on esitetty ensimmäisenä, joten siitä tulee vasemmanpuoleinen taulu. Employees -taulu on oikeanpuoleinen. Esimerkistä näemme, että nyt asiakasnumero on osassa tyhjä. Tämä tarkoitaa sitä, että osa myyjistä ei ole laskuttanut vielä yhtään asiakasta.

&#x20;Jos muutamme hakua seuraavan esimerkin mukaisesti niin saamme muodostettua **RIGHT OUTER JOIN** -ehdon ja tällöin tulosjoukko kertoo suoraan ne työntekijät, joilla ei ole laskutettuja asiakkaita.

{% code title="right\_outer\_join\_esimerkki\_02" %}

```sql
SELECT tyontekijat.employeenumber, 
       asiakkaat.customernumber 
FROM   customers AS `asiakkaat` 
       RIGHT JOIN employees AS `tyontekijat` 
               ON asiakkaat.salesrepemployeenumber = tyontekijat.employeenumber 
WHERE  asiakkaat.salesrepemployeenumber IS NULL 
ORDER  BY tyontekijat.employeenumber;
```

{% endcode %}

![Right join tulosjoukon esimerkki 03](/files/-LogkxSH0i9Z6bRBMODu)

## CROSS JOIN -selitettynä

> CROSS JOIN on liitos, jonka tulosjoukkona on [**karteesinen tulo**](https://fi.wikipedia.org/wiki/Karteesinen_tulo). Tämä tarkoitaa sitä, että kaikki vasemmanpuoleisen taulun rivit liitetään jokaisen oikeanpuoleisen taulun riveihin. Puuttuvat kentät merkitään NULL arvolla.

Liitos on harvinaisempi eikä siihen usein törmää. Liitosta on vaikea esittää Vennin diagrammia käyttäen, joten esitetään suoraan esimerkki.

{% code title="cross\_join\_esimerkki" %}

```sql
SELECT tyontekijat.employeenumber, 
       tyontekijat.firstname, 
       asiakkaat.customernumber, 
       asiakkaat.contactfirstname 
FROM   customers AS `asiakkaat` 
       CROSS JOIN employees AS `tyontekijat` 
ORDER  BY tyontekijat.employeenumber;
```

{% endcode %}

{% hint style="info" %}
Huomaa, että rivillä 6 CROSS JOIN kanssa ei tule käyttää ON -avainsanaa kuten muissa liitoksissa. Tätä ei siis tarvita tämän liitoksen toimintatavan vuoksi.
{% endhint %}

![Cross join tulosjoukon esimerkki](/files/-LogoBFjMeXIRp41uwQJ)

Tulosjoukosta huomaamme heti, että rivejä on 2806. Harjoitustietokannassa on kuitenkin **employees** **(tyontekijat)** taulussa vain 23 riviä ja **customers (asiakkaat)** taulussa 122. Liitos käyttäytyy oikeasti siten, että se liittää jokaisen rivin kahdesta taulusta toisiinsa. Eli jos laskemme 23x122 niin saamme tulokseksi 2806 riviä. Seuraavassa esimerkissä on kuvattu CROSS JOIN -liitoksen käyttäytymistä yksinkertaisemmalla tavalla.

![Cross join esimerkki ](/files/-LogsSHvlkPEJ4OM0vhm)

## Useampi JOIN -ehto kyselyssä

Kun tunnet ensin perusteet miten eri JOIN ehdot toimivat niin olet valmis siirtymään eteenpäin. Tietokantojen kanssa työskentelyssä tulee vastaan myös kyselyjä, jotka vaativat useamman JOIN -kyselyn yhdistämistä. Tämän vuoksi sinun on hyvä tuntea miten SQL -tietokanta käsittelee näitä kyselyjä.

Yritä muista seuraavat säännöt:

* Taulu, joka on esitelty esimerkiksi SELECT lauseessa ennen toista taulua, on aina vasemmanpuoleinen taulu. (yritä pitää mielessä Vennin diagrammin, A ja B joukot)
* Esimerkiksi, jos kyselyssä on mainittu **FROM customers** ja sen jälkeen myöhemmin **LEFT JOIN orders** niin tällöin customers -taulu on vasemmanpuoleinen.
* SQL -tietokanta, joka tulkitsee kyselyn, suorittaa JOIN -lauseet siinä järjestyksessä kun ne on esitelty.

{% code title="useampi-join-esimerkki" %}

```sql
-- Hakulauseke hakee Suomessa asuvien asiakkaiden tilausrivit ja 
-- ilmoittaa kuinka paljon on yksittäisten tilausrivien ostosten
-- kokonaissumma. Tämä ei vielä ryhmitä summia tilauksien mukaan.
SELECT c.customernumber, 
       c.contactfirstname, 
       c.contactlastname, 
       o.ordernumber, 
       o.status, 
       od.orderlinenumber, 
       od.productcode, 
       od.quantityordered, 
       od.priceeach, 
       ( od.quantityordered * od.priceeach ) AS `orderLineTotalSum` 
FROM   customers c 
       INNER JOIN orders o USING (customernumber) 
       LEFT JOIN orderdetails od USING (ordernumber) 
WHERE  Lower(c.country) LIKE 'finland';
```

{% endcode %}

Ylläoleva esimerkki sisältää useamman JOIN lauseen ja käymme läpi seuraavaksi vaiheittain kuinka se suoriutuu. Kun kysely ajetaan harjoitustietokantaan niin siitä saadaan alla oleva tulosjoukko.

![Esimerkki useamman joinin tulosjoukosta](/files/-LogzG9_sD9g5LB5XnWq)

### Ensimmäinen vaihe

Vaiheet käydään läpi yksitellen mutta ei mennä liian syvälle SQL tietokannan yksityiskohtiin. Käymme ne vain päätasolla läpi.

Jos katsomme esimerkin kyselyä niin ensin voimme pilkkoa kokonaisen kyselyn 4 eri vaiheeseen.

Ensimmäinen vaihe koostuu vasemmanpuoleisesta taulusta eli tässä tapauksessa taulu **customers**. Jos tekisimme seuraavanlaisen kyselyn niin se vastaisi esimerkkiä ilman mitään ehtoja:

```sql
-- Joukko A
SELECT c.customernumber, 
       c.contactfirstname, 
       c.contactlastname 
FROM customers c;
```

{% hint style="warning" %}
Tämän tulos eli käytännössä koko **customers** taulu on nyt nimetty joukoksi A eli vasemmanpuoleinen taulu Vennin diagrammissa. Pidä tämä mielessä.
{% endhint %}

### Toinen vaihe

Seuraavassa vaiheessa SQL tietokanta tulkitsee esimerkin rivillä 15 olevan INNER JOIN lauseen. INNER JOIN -tarkoitti, että tulosjoukkoon tulee vain ne rivit, jotka esiintyvät kahdessa liitettävässä taulussa.

{% code title="useampi-join-esimerkki-toinen-vaihe-01" %}

```sql
-- Esimerkissä USING on vain lyhenne merkinnälle:
-- ON c.customerNumner = o.customerNumber
INNER JOIN orders o USING (customernumber)
```

{% endcode %}

Voimme nimetä tämän liitettävän taulun B:ksi. Eli nyt tiedossa on A ja B joukko tämän toiseen vaiheen aikana.

![INNER JOIN Vennin diagrammina](/files/-LogCo7d1Ujrxa-4h-Jp)

Tässä kohdin teemme kuten normaalisti INNER JOIN -ehdon toteutuessa. Kun suoritamme tämän vaiheen niin voimme ajatella suorittavan seuraavanlaisen kyselyn:

{% code title="useampi-join-esimerkki-toinen-vaihe-02" %}

```sql
SELECT c.customernumber, 
       c.contactfirstname, 
       c.contactlastname, 
       o.ordernumber, 
       o.status 
FROM   customers c 
       INNER JOIN orders o USING (customernumber);
```

{% endcode %}

![Tulosjoukko vaiheen 2 jälkeen.](/files/-Loh2Yk4WBItqb-5H3pK)

Kun toinen vaihe on suoritettu niin tulosjoukko on yllä olevan kuvan mukainen. Muista kuitenkin mitä artikkelin alussa mainittiin. **Kun JOIN kysely suoritetaan niin SQL tietokanta laittaa tietoja talteen välitauluihin eli muistinvaraisiin tauluihin, joita käytetään seuraavissa vaiheissa.**

Tämä tarkoittaa nyt sitä, että ensimmäisen vaiheen joukko A ei enää ole olemassa vaan voimme ajatella, että nyt toisen vaiheen jälkeinen tulosjoukko on uusi joukko A. Eli siitä tulee vasemmanpuoleinen taulukko Vennin diagrammina kuvattu.

### Kolmas vaihe

Seuraavassa vaiheessa jatkamme SQL kyselyn suorittamista. Nyt meillä on muistissa toisen vaiheen aikana syntynyt tulosjoukko. Esimerkissä rivillä 16 on seuraava JOIN:

{% code title="useampi-join-esimerkki-kolmas-vaihe-01" %}

```sql
LEFT JOIN orderdetails od USING (ordernumber)
```

{% endcode %}

Nyt tästä **orderdetails** taulusta tulee B joukko, koska se esiintyy aiempien vaiheiden jälkeen JOIN kyselyssä. Tällöin A joukko on juuri toisen vaiheen lopputulos eli jälleen kerran voimme noudattaa normaalia LEFT JOIN -ehdon sääntöä.

![LEFT JOIN Vennin diagrammina](/files/-Log6HmHbnFGYdu2Ollm)

Seuraavaksi voimme ajatella, että suoritetaan alla olevan mukainen SQL kysely, joka muistuttaa jo hyvin alkuperäistä esimerkin kyselyä:

{% code title="useampi-join-esimerkki-kolmas-vaihe-02" %}

```sql
SELECT c.customernumber, 
       c.contactfirstname, 
       c.contactlastname, 
       o.ordernumber, 
       o.status, 
       od.orderlinenumber, 
       od.productcode, 
       od.quantityordered, 
       od.priceeach, 
       ( od.quantityordered * od.priceeach ) AS `orderLineTotalSum` 
FROM   customers c 
       INNER JOIN orders o USING (customernumber) 
       LEFT JOIN orderdetails od USING (ordernumber);
```

{% endcode %}

Kun kysely on suoritettu, saamme seuraavan tulosjoukon mikä muistuttaa alla olevaa tulostetta. Tämän kolmannen vaiheen lopussa on taas jäljellä vain yksi tulosjoukko eli voimme jälleen kerran tästä tulevan joukko A.

![Tulosjoukko 3 vaiheen jälkeen.](/files/-Loh4laz0yNR0X4kk-hY)

### Neljäs vaihe

Kun meillä on edellsen vaiheen tulosjoukko tiedossa, siirrymme SQL kyselyssä eteenpäin. Seuraavaksi ei ole enää jäljellä kuin hakuehtoa rajaava määritys:

{% code title="useampi-join-esimerkki-neljas-vaihe-01" %}

```sql
WHERE Lower(c.country) LIKE 'finland';
```

{% endcode %}

SQL on tässä kohdin suorittanut siis kaikki JOIN -ehdot ja WHERE ehtoa sovelletaan viimeiseen tulosjoukkoon. Tulosjoukko sisältää kaikki **customers** taulun sarakkeet vaikka niitä ei esiteltäisi SELECT lauseen alussa. Tässä esimerkissä lopputulosta on suodatettu siis vielä maan nimen mukaisesti.

Tällä tavoin vaihe vaiheelta rakentuu usean JOIN kyselyn suoritustapa. Aina edellisen JOIN ehdon tulosjoukkoa käytetään seuraavassa JOIN lausekkeessa. Vastaavanlainen esimerkki erilaisin tiedoin on esitelty seuraavassa lähteessä: <https://academy.vertabelo.com/blog/illustrated-guide-multiple-join/>

Jos esimerkki sisältäisi esimerkiksi GROUP BY tai ORDER BY sääntöjä niin näitä sovellettaisiin sitten suodatettujen tietojen jälkeiseen tulosjoukkoon.

Käytännössä tällä tavoin SQL tietokanta käsittelee kyselyn kokonaisuudessan eräänlaisten välitaulujen avulla vaikka se ei näy ulospäin suoraan. Tämän tarkoituksena ei ole selittää meneekö asia teknisesti oikein vaan toimia esimerkkinä hahmottamaan kuinka kirjoitta oikein JOIN kyselyjä peräkkäin.

{% hint style="info" %}
JOIN kyselyissä voi sattua erilaisia virheitä ns. duplikaattirivien vuoksi. Ole siis tarkkana kun teet kyselyjä, jotka sisältävät useita JOIN -ehtoja. <https://alexpetralia.com/posts/2017/7/19/more-dangerous-subtleties-of-joins-in-sql>
{% endhint %}

## Yhteenveto&#x20;

Taulujen väliset liitokset ovat tärkeä asia tuntea SQL -tietokannoissa. JOIN -ehdot ovat ensimmäinen konsepti mikä voi olla hankala ymmärtää esimerkkien kanssa tai ilman. Usein nämä tulevat vastaan vasta käytännössä tietokantojen kanssa työskentelyn ohessa ja niistä on suuri hyöty. Lisäksi tuntemalla nämä tavat, osaat myös etukäteen suunnitella tietokantamalleja, jotka tukevat tietynlaisia kyselyjä paremmin.

## Lähteet

{% embed url="<http://www.mysqltutorial.org/basic-mysql-tutorial.aspx>" %}

{% embed url="<https://en.wikipedia.org/wiki/Join_(SQL)>" %}

{% embed url="<https://github.com/hamk-webdev-18a/turon-tietokanta>" %}

{% embed url="<https://www.dofactory.com/sql/join>" %}

{% embed url="<https://dataschool.com/how-to-teach-people-sql/sql-join-types-explained-visually/>" %}

{% embed url="<https://sql-joins.leopard.in.ua/>" %}

{% embed url="<https://academy.vertabelo.com/blog/illustrated-guide-multiple-join/>" %}

{% embed url="<https://alexpetralia.com/posts/2017/7/19/more-dangerous-subtleties-of-joins-in-sql>" %}


# Normalisointi

Luvussa käsitellään tietokantojen normalisointisääntöjä, jotka tulisi tuntea tietokantasuunnittelun vuoksi. Normalisointisäännöt ohjaavat kohti hyvää tietokantaratkaisua.

## Mitä normalisoinnilla tarkoitetaan?

Lyhyesti sanottuna normalisointi (eng. normalization) tarkoittaa tietokantasuunnitteluun liittyviä tekniikoita, joiden tarkoitus on minimoida tiedon toistuvuutta ja riippuvuutta. Säännöt keskittyvät oleellisesti tietokantataulujen sisältöihin.

Noudattamalla sääntöjä ne ohjaavat siihen, että suuri taulu saadaan pilkottua pienemmiksi tauluiksi sekä luomaan näiden välille riippuvuussuhteita. Kts. [Pää- ja viiteavaimet](/relaatiotietokannat/paeae-ja-viiteavaimet). Lopputuloksena tietokannassa oleva tieto on siis selkeämmin järjestetty. Terminä normalisointi viittaakin tietokannan rakenteisiin .&#x20;

Erilaisia normaalimuotoja on yhteensä kuusi kappaletta mutta pääasiassa kolme ensimmäistä on tärkeintä. Kolmannen jälkeen ei aina saada suuria hyötyjä mutta hyvä tapa on yrittää noudattaa kolmea ensimmäistä. Sääntöjen noudattaminen tarkoittaa myös, että toteuttaakseen esimerkiksi kolmannen normaalimuodon pitää sen hetkisen ratkaisun toteuttaa myös kaksi edellistä normaalimuotoa.

Kun tietokannassa on huomioitu nämä säännöt niin voidaan lyhyesti aina ilmaista esimerkiksi, että tietokantamalli on 3. normaalimuodon mukainen. Tämä jo heti antaa viitteen sille minkälainen tietokanta on kyseessä. Aina näin ei ole ja suunnitteluvirheet johtavat erilaisiin ongelmiin tiedon käsittelyn kanssa.

Normalisoinnin lisäksi voidaan puhua denormalisoinnista (eng. denormalization), joka tarkoittaa sääntöjen rikkomista. Tämä tehdään usein hyvästä syystä ja perustellen. Ei siksi, että sääntöjä ei noudatettaisi vaan sillä voidaan joissain tilanteissa nostaa esimerkiksi suorituskykyä.

Tietokannan normalisoinnin taustalla on [Edgar Codd](https://fi.wikipedia.org/wiki/Edgar_F._Codd), joka on esitellyt ja määritellyt ensimmäiset kolme sääntöä. Tutustutaan seuraavaksi kolmeen ensimmäiseen normaalimuotoon syvemmin.

## Normalisoimaton tieto

Normalisointisäännöt tullaan esittämään esimerkin kautta. Ensimmäisenä esittelemme  normalisoimattoman taulun, josta esimerkit syntyvät. Tietokantamalli ei voi toteuttaa seuraavaa normaalimuotoa ellei se toteuta myös edellisiä normaalimuotoja.

On mahdollista, että oikean tiedon kanssa tietyissä olosuhteissa normalisointisäännöt eivät toteudu tai ne niiden yli voidaan hypätä. Esimerkki on kuitenkin tehty siitä näkökulmasta, että erilaiset tilanteet tulevat vastaan. Tietokantamallina toimii seuraavanlainen tv-sarjoja sisältävä tietokantataulu.

![Normalisoimaton tietokantataulu](/files/-LozYcOIPp7lvcqXR0sS)

{% code title="Esimerkkidata-televisiosarjat" %}

```
*************************** 1. row ***************************
              id: 1
            nimi: Game of Thrones
           tyyli: fantasia
       kestoaika: 4920
     lyhytkuvaus: Game of Thrones on yhdysvaltalainen fantasiadraamasarja, jonka ovat luoneet David Benioff ja D. B. Weiss. Se perustuu George R. R. Martinin Tulen ja jään laulu -fantasiakirjasarjaan.

Martin toimi yhtenä sarjan vastaavista tuottajista ja myös käsikirjoitti muutaman jakson.
          luojat: David Benioff,D.B. Weiss
        perustuu: George R. R. Martinin kirjasarjaan Tulen ja jään laulu
       paaosissa: Peter Dinklage,Lena Headey,Nikolaj Coster-Waldau,Emilia Clarke,Kit Harington,Sophie Turner,Iain Glen,Aidan Gillen,Maisie Williams,Alfie Allen,Isaac Hempstead-Wright,Rory McCann,Jack Gleeson,Michelle Fairley,Richard Madden,Sean Bean,Mark Addy,Harry Lloyd,Conleth Hill,John Bradley,Jerome Flynn,Charles Dance,Sibel Kekilli,James Cosmo,Joe Dempsie,Dean-Charles Chapman,Tom Wlaschiha,Jason Momoa,Liam Cunningham,Carice van Houten,Natalie Dormer,Stephen Dillane,Rose Leslie,Oona Chaplin,Gwendoline Christie,Hannah Murray,Michael McElhatton,Kristofer Hivju,Iwan Rheon,Michiel Huisman,Nathalie Emmanuel,Indira Varma,Jonathan Pryce
     alkuperamaa: Yhdysvallat
       tvkanavat: HBO,HBO Nordic,C More,Yle TV2
        esitetty: 17. huhtikuuta 2011 – 19. toukokuuta 2019,12. tammikuuta 2012 – jatkuu edelleen
  tuotantokausia: 8
         jaksoja: 73
   tunnuskappale: Ramin Djawadin säveltämä
       tuottajat: Frank Doelger,Carolyn Strauss,Greg Spence
       vastaavat: David Benioff,D. B. Weiss,Carolyn Strauss,Frank Doelger,Bernadette Caulfield
        ohjaajat: Jack Bender,Alex Graves,Michelle MacLaren,Neil Marshall,Daniel Minahan,Mark Mylod,David Nutter,Daniel Sackheim,Alik Sakharov,Miguel Sapochnik,Tim Van Patten,Jeremy Podeswa,Michael Slovis,Alan Taylor
kasikirjoittajat: David Benioff,D. B. Weiss,Bryan Cogman,George R. R. Martin,Vanessa Taylor,Dave Hill,Jane Espenson
      saveltajat: Ramin Djawadi
        kuvaajat: Alik Sakharov,Marco Pontecorvo,Matthew Jensen
   tuotantoyhtio: HBO
```

{% endcode %}

Yllä oleva malli esittää yhden esimerkkirivin millaista tietoa taulu sisältää. Kun tietoa ei ole tallennettu oikealla tavalla, tuottaa se usein ongelmia. Tiedon lisääminen, muokkaaminen ja poistaminen osoittautuu yleensä hankalaksi. Ensimmäiseksi tarkastelemme esimerkkiä 1. normaalimuodon määrittelemällä tavalla.

## Ensimmäinen normaalimuoto (1NF)

Ensimmäinen normaalimuoto on tosi, jos:

* jokainen taulun sarake sisältää yhden arvon.
* jokainen taulun rivi on uniikki.

{% hint style="info" %}
Englanninkielisissä lähteissä puhutaan termillä **atomic value**. Sillä tarkoitetaan arvoa, jota ei voi enää jakaa pienempiin osiin.
{% endhint %}

Kun tarkastellaan esimerkin taulua **televisiosarjat** niin on melko selkeää, ettei se vastaa ensimmäistä sääntöä lainkaan. Pelkästään esimerkin tiedot paljastavat toistuvat arvot. Katsotaan esimerkkinä sarake **luojat**, joka sisältää kaksi nimeä: **David Benioff ja D.B. Weiss**. Lähestulkoon aina sarake, jossa on kokoelma tietoa niin voidaan pilkkoa. Jotta pääsemme kohti 1. normaalimuotoa niin ratkaisu tähän on pilkkoa kenttä omaan tauluunsa. Luodaan siis taulu **luojat**.

![Luojat -taulu](/files/-Lp4ZEI9BIINPJutwZRm)

Nyt tilanne ei vielä ole muuttunut paremmaksi. Taulujen välillä ei ole liitosta ja uusi **luojat** -taulu ei sisällä pääavainta. Jos mietimme ensin pääavainta niin valintamme voisi olla jokin seuraavista:

* Juokseva numerointi (1,2,3,4,5....)
* Jokin luonnollinen yhdistelmä sarakkeita, kuten esimerkiksi **sarjan tunniste** ja **henkilön nimi**.

Koska taulujen välillä ei ole minkäänlaista suhdetta niin voimme vielä miettiä, että mikä sen kuuluisi olla. Kun tiedämme, että alkuperäisessä sarakkeessa on ollut kaksi arvoa niin voimme päätellä, että yhdellä tv-sarjalla on yksi tai useampi luoja. Voimme tarkastella aina myös muita taulun rivejä, josta voisimme päätellä lisää mutta tässä kohdin tiedämme, että luojia voi olla useita mutta usein vähintään yksi. Tottakai tilanne, jossa luojaa ei tiedetä on aivan mahdollinen. Muotoillaan suhde seuraavasti:

* **Tv-sarjalla voi olla useita luojia tai ei yhtään.**&#x20;

Tämän perusteella saattaisimme päästä seuraavanlaiseen taulujen suhteeseen. Esimerkki sisältää jo kentät edellä olevan suhdetyypin luomiselle. Alla olevassa kuvassa taulu **televisiosarjat** on liitetty **luojat** -tauluun. Kuvassa ei näy suhteen tyyppiä mutta se on aiemmin kuvatun mukainen. [(Suhteiden kuvaamistavasta on oma lukunsa)](/relaatiotietokannat/er-kaaviot). **Televisiosarjat** -taulusta huomaamme, että siitä puuttuu nyt kokonaan **luojat** -sarake. Sarakkeen tietojen perusteella on siis luotu kokonaan oma taulunsa. Huomaamme myös, että **luojat** -taulun pääavaimena toimii nyt sen kaksi saraketta. Palaamme tähän vielä myöhemmin.

![televisiosarjat - luojat - relaatio](/files/-Lp4d-bRhVrH9w8CcbCE)

Alla näemme esimerkit tämän ensimmäisen kohdan normalisoinnin jälkeen eli miten tieto on esitetty **luojat** -taulussa. **Luojat** taulussa siis viitataan **televisiosarjat** -riviin sen tunnisteella **(id)**.

![Esimerkki televisiosarjat taulun riveistä](/files/-Lp4d2-Ms7dpiU2sJkqO)

![Esimerkki luojat taulun riveistä](/files/-Lp4d40P0U03mz11foeM)

{% hint style="info" %}
Luojat -taulun pääavain ei ole vielä kovin järkevät mutta asioita usein tehdään yksi kerrallaan. Pääavaimessa on kuitenkin se etu, että henkilöä ei voi nyt lisätä toiseen kertaan samaan tv-sarjaan luojaksi mikäli rivi on jo olemassa. Mysql antaa seuraavanlaisen virheen kun pääavaimen ehdot eivät täyty:

`#1062 - Duplicate entry '1-David Benioff' for key 'PRIMARY'`
{% endhint %}

Pääsääntöisesti tässä on kyse 1. normaalimuodon toteutumisesta eli jokainen tällainen sarake, joka sisältäisi useita arvoja niin tulee käsitellä. Usein ratkaisu on juurikin toinen taulu mutta taulujen väliset suhteet voivat vaihdella tiedon sisällön mukaan. Tehdään vielä toinen vastaava esimerkki käyttäen **tvkanavat** -saraketta. Kun noudatamme samanlaista sääntöä niin lopputulos voisi olla seuraavanlainen.

![televisiosarjat - luojat - tvkanavat - relaatio](/files/-Lp4iQ_FDHougcu_-p8n)

![Esimerkki tvkanavat taulun riveistä](/files/-Lp4iSwfm6xZmlFxOq5N)

Molemmissa tilanteissa **tvsarja\_id** -sarake viittaa **televisiosarjat** -taulun pääavaimeen. Tällöin siis **tvsarja\_id -sarake toimii viiteavaimena**. Tähän tapaan jatkettaisiin muiden tietojen kohdalla. Kaikkia ei käydä läpi yksitellen, koska vastaavia sarakkeita on esimerkissä paljon. Nyt siis taulut eivät vielä täysin toteuta 1. normaalimuotoa mutta jatkamalla loppuun asti samalla tapaa, näin tulisi käymään. Esimerkissämme siirrymme 2. normaalimuotoon.&#x20;

{% hint style="info" %}
Taulussa voisi olla myös tilanne missä olisi sarakkeet: paaosa\_01, paaosa\_02, paaosa\_03 jne. Tällaiset sarakkeet kertovat myös huonosta suunnittelusta, koska ovat samalla tavoin arvoja, joita on useita vaikka eivät yhdessä sarakkeessa olekaan. Ongelma on myös, että joudumme aina muuttamaan tietokantarakennetta, jos tietojen määrä kasvaa. Tähän tulisi myös noudattaa 1. normaalimuodon sääntöä.
{% endhint %}

## Toinen normaalimuoto (2NF)

Toinen normaalimuoto on tosi, jos:

* ensimmäinen normaalimuoto on tosi.
* kaikki sarakkeet ovat täysin riippuvia koko pääavaimesta, poislukien avaimet.

Nykyinen esimerkkimme on 2. normaalimuodon osalta huono. **Televisiosarjat** -taulu sisältää pääavaimen, joka koostuu yhdestä sarakkeesta niin tällöin kaikki muut sarakkeet ovat riippuvaisia siitä. Toinen normaalimuoto korostuu erityisemmin silloin kun taulun pääavain koostuu useammasta sarakkeesta. Tämän esimerkin vuoksi muutamme hieman **tvkanavat** -taulua seuraavanlaiseksi.

![tvkanavat esimerkki 2. normaalimuoto](/files/-Lp4umIHYFOGg-Cf14Gc)

Kuvan mukaisessa tilanteessa **tvkanavat** -taulu sisältää nyt uuden pääavaimen, **joka koostuu tvsarja\_id ja kanavan\_id -sarakkeesta**. Kun nyt tarkastelemme kanavan nimeä niin voimme miettiä riippuuko se koko pääavaimesta. Nimi riippuu selkeästi kanavan tunnisteesta (kanavan\_id) arvosta. Kun taas TV-sarjan tunniste muuttuu niin sillä ei ole mitään yhteyttä kanavan nimeen.&#x20;

Tällaisessa tilanteessa huomaamme, että **kanavan\_nimi** -sarake ei riipu molemmista pääavaimen sarakkeista mutta sen arvo myös toistuu. Jos kanavan tunniste vaihtuu niin kuuluisi muistaa päivittää vielä kanavan nimi sekä muut toistuvat tiedot. Kuvattu tilanne usein tarkoittaa, ettei taulu toteuta 2. normaalimuotoa. Näissä tilanteissa tiedot pitää myös purkaa omaan tauluun. Esimerkin tilanteessa voimme saada aikaiseksi seuraavan tietokantarakenteen:

![2. normaalimuoto, liitostaulu](/files/-Lp4zOhmJu_DCCV8yTZU)

![tvkanavat taulu](/files/-Lp4zUb7lJjOVgIps1h7)

![Liitostaulu tvkanavat ja tvsarjat](/files/-Lp4zWx4qmAdq-n34SHo)

Tv-kanavat taulu muuttui siten, että tv-sarjan tunniste poistettiin. Tällöin sisältö vastaa paremmin taulun sisältöä muutenkin eli se sisältää tv-kanavien tietoja. Muutoksen myötä kadottaisimme tiedon siitä missä tv-kanavissa kyseistä sarjaa on esitetty. Tätä varten voidaan luoda usein liitostaulu, joka yhdistää nämä asiat. Esimerkissämme olemme siis luoneet **televisiosarjat\_tvkanavat** -nimisen taulun, jossa on vain tunnisteet.

Jos nyt päivittäisimme TV-kanavan tietoja niin sisältö pysyy ajantasaisena. Koska kanavia voi olla useita yhtä tv-sarjaa kohden niin kyseessä on **monen suhde moneen -liitos**.

Samankaltainen tilanne saattaisi tulla vastaan **luojat** -taulun kanssa. Kun taas mietimme tietokannan sisältöä niin tällaiset suhteet voitaisiin pystyä huomaamaan jo tietokannan suunnittelun aikana ja siten suunnitella etukäteen. Toisinaan taas yhteydet huomataan myöhemmin kun oikeaa tietoa saadaan luotua. Usein tietojen suhteet keskenään eivät ole selviä kuten aina esimerkeissä.

## Kolmas normaalimuoto (3NF)

Kolmas normaalimuoto on tosi, jos:

* toinen normaalimuoto on tosi.
* sisältää sarakkeita, jotka eivät ole transitiivisesti riippuvaisia taulun pääavaimesta.

{% hint style="info" %}
**Transitiivisella riippuvuudella** tarkoitetaan sitä, että sarake A on riippuvainen sarakkeesta B jonkun toisen sarakkeen kautta. Käytännössä sarake A on transitiivisesti riippuvainen sarakkeesta B, jos sarake A on riippuvainen sarakkeesta C, joka on riippuvainen sarakkeesta B. Tässä A, B ja C voivat sisältää myös useampia sarakkeita.
{% endhint %}

Esimerkkiä varten keskitymme **televisiosarjat** -taulun **tyylit** -sarakkeeseen. Yksinkertaisuuden vuoksi olemme luoneet taas tilanteen missä tauluun on lisätty sarake **tyyli\_id**. Alla on kuva tilanteesta, jossa ei näy kaikkia sarakkeita taulusta.

![Esimerkki kolmannesta normaalimuodosta - lähtötilanne - televisiosarjat taulu](/files/-Lp52jyC7372Ao0hewYx)

Kun tarkastelemme taulua nyt 3. normaalimuodon ehdoilla niin voimme ilmaista asian seuraavasti. Sarakkeet **tyyli** (tv-sarjan kategoria tai tyylilaji) ja **tyyli\_id** ovat molemmat riippuvaisia pääavaimesta. Se siis määrittää tyylilajin. Mainitut kaksi saraketta eivät kuitenkaan ole toisistaan riippumattomia. Tyylilaji voidaan tässä päätellä tyylilajin tunnisteen perusteella. Tv-sarjoja on olemassa vielä useampia kuin tyylilajeja, joten tämä aiheuttaa myös tiedon toistuvuutta **televisiosarjat** -taulussa.

Kun edellä mainitun oloinen tilanne kohdataan, ratkaisu on jälleen kerran helppo. Tiedot tulisi siirtää omaan tauluunsa. Tämän perusteella voimme siis päästä seuraavanlaiseen tietokantaratkaisuun.

![3. normaalimuoto - esimerkki lopputilanne](/files/-Lp56iXHQR0-ngUDeuup)

**Televisiosarjat** -tauluun jäi siis vain tyylilajin tunniste (sarake myös uudelleen nimetty) ja tyylilaji erotettiin omaksi taulukseen. Televisiosarja -taulusta viitataan tyylilajeihin ja **tyylilajit** -taulu ei sisällä tv-sarjan tunnistetta. Tällöin voidaan puhua, että puhutaan **yksi suhde yhteen -liitoksesta** taulujen välissä. Taulujen sisältämä tieto näyttää nyt vielä seuraavalta.

![Televisiosarjat -taulu muutoksen jälkeen.](/files/-Lp57TuVsoPwZFLQkIYA)

![Tyylilajit -taulu.](/files/-Lp57Yv2R_tQmG209Ypv)

Esimerkissämme jätämme normaalimuotojen käsittelyn tähän. Usein 3. normaalimuoto on hyvä tavoite ja työmäärä tai hyöty seuraavista vaiheista ei aina maksa itseään takaisin. Perusteina on hyvä tuntea nämä kolme ensimmäistä. Normaalimuotojen tunnistaminen on usein haastavaa ja siksi kannattaa katsoa myös alla olevista lähteistä lisää tietoja ja esimerkkejä miten nämä on kerrottu muiden esimerkkien avulla.

## Normalisoinnin tavoitteet

Kertaamme vielä miksi normalisointi on tärkeä aihe tietokantasuunnittelussa. Se sopii myös hyvin erilaisiin tietokantaratkaisuihin tarvittaessa vaikka onkin alunperin suunniteltu relaatiotietokantojen suunnitteluun.

Tavoitteet lyhyesti:

* Luoda sellaiset suhteet tietojen välille, että vältytään ei-toivottujen lisäys, muokkaus tai poisto komentojen riippuvuuksista.
* Vähentää taulujen rakenteiden muuttamista tilanteissa, jossa esitellään uusia tietoja sekä kasvattaa rakenteen elinkaarta.
* Tehdäkseen taulujen välisistä suhteista ja sen sisältämästä tiedosta ymmärrettävämpää käyttäjille.

Niin sanottuja **ei-toivottuja** riippuvuuksia tiedon muuttamisen kohdalla ovat pääasiassa seuraavat tilanteet, jotka esiintyvät mahdollisesti huonosti normalisoidun tietokannan kohdalla.

**Tiedon lisäämisen yhteydessä -** Uutta tietoa ei voida luoda ilman, että sille luodaan jokin muu riippuvuus mitä ei välttämättä ole olemassa. Esimerkkinä voimme ajatella vaikkapa **Luojat** -sarakkeen tämän luvun esimerkeissä. Kyseessä voisi olla tilanne, että emme saisi lisättyä uutta Tv-sarjaa ellemme tiedä myös sen luojaa, mikäli se on pakollinen tieto. Voisimme aina laittaa kyseisen kentän tyhjäksi mutta se usein viittaa tämän kaltaiseen tilanteeseen, jossa riippuvuudet eivät ole määritetty oikein.

**Tiedon päivittämisen yhteydessä -** Sama informaatio voidaan esittää usealla rivillä. Tällöin tiedon päivittäminen yhden rivin kohdalla voi johtaa tilanteeseen, missä tiedon eheys on laiminlyöty. Voidaan siis joutua tilanteeseen, missä esimerkiksi jokin tunniste ei vastaa sitä vastaavaa aihetta.

**Tiedon poistamisen yhteydessä** - Poistaessa tietoja saatamme joutua tilanteeseen, jossa poistamalla esimerkiksi TV-sarjat, joudumme poistamaan paljon muita siihen viittaavia tietoja. Tällöin jokin tieto ei voi esiintyä ilman toista vaikka ne oikeassa maailmassa olisivat riippumattomia toisistaan.

Hyvin normalisoidut tietokannan kohdalla tietojen päivittäminen ja sen käyttö on sujuvaa. Uusien tietojen esittäminen ei vaadi rakenteen muuttamista. Kaikki tämä on siis hyvä tavoite ja kun puutteita näkee, niitä pitäisi yrittää korjata ajoissa mallintamalla tietoa uudelleen. Myöhemmässä vaiheessa tämä on usein hankalaa kun tietoa on jo olemassa ja tällöin vaatisi erilaisia migraatioita tietokannan rakenteeseen.

## Lopputilanne

Esimerkin tietokanta jäi 3. normaalimuodon esimerkin kuvauksen muotoiseksi. Tämä ei tarkoita, että tietokanta olisi vielä 3. normaalimuodon mukainen tai edes **televisiosarjat** -taulu. Edellisiä vaiheita tulisi toistaa loppujen sarakkeiden kohdalla ja ensin koko taulu yrittää saada 1. normaalimuodon mukaiseksi. Tämä tarkoittaisi, että kaikki sarakkeet, joissa on mainittu listana henkilöitä tulisi laittaa omaan tauluunsa.

Huomaamme kuitenkin, että tiedoissa on paljon näyttelijöiden tai muiden henkilöiden nimiä. Tämä toimii vielä hyvänä esimerkkinä, että myös jo luodut taulut eivät välttämättä noudata normaalimuotoja. Tällöin myös ne tulisi tarkastella sääntöjen mukaan ja tarvittaessa pilkkoa tiedon perusteella omiksi kokonaisuuksiksi.

Otetaan vielä lopuksi tilanne, joka vie kohti normaalimuotoja henkilöiden kohdalla. Tehdään seuraavanlainen rakenne tietokantaan.

![Esimerkki - henkilot taulut](/files/-Lp5JIGSnqYskyWYrKIb)

Esimerkin ero edelliseen on, että henkilöt on lisätty omaan tauluunsa. Henkilöt voivat toimia eri rooleissa kuten pääosassa ja vastaavina. Näille on luotu omat liitostaulunsa ja edetessä **luojat** -taulu voitaisiin muuttaa samanlaiseksi liitostauluksi. Tällä hetkellä tietoa olisi kopiona ja toistuvana kyseisessä taulussa.

Tällä tavoin myös eri henkilöiden tieto voidaan saada päivitettyä sujuvammin. Tietokannan rakenne tosin taas muuttuu hieman monimuotoisemmaksi, jos jokaiselle eri tehtävälle teemme liitostaulun. Riippuen juuri tilanteesta, väärää vastausta ei ole. Voimme myös ensin yhden esimerkin kautta löytää paremman ratkaisun.

Mikäli vielä kävisimme tietoja läpi niin esimerkin tapauksessa voisi olal myös esimerkiksi **televisiosarja\_tehtava** ja **tehtavat** taulut. Tällöin voitaisiin päästä rakenteeseen, jossa liitostaulu sisältäisi seuraavat tunnisteet: **tv-sarja, henkilo ja tehtävä**. **Tehtävä** -taulussa puolestaan olisi lueteltu erilaisia tehtäviä missä henkilö on voinut toimia kuten vastaavana tuottajana, pääosan esittäjänä jne. Tällainen rakenne voisi siis yhtä hyvin toimia, koska silloin jokainen henkilö voidaan asettaa useampaan eri tehtävään mutta heidän omat tietonsa ei toistu. Myös liitosten määrä vähenee taulujen välillä, joka tarkoittaa yksinkertaisempia kyselyjä.

## Lähteet

{% embed url="<https://www.w3schools.in/dbms/database-normalization/>" %}

{% embed url="<https://en.wikipedia.org/wiki/Database_normalization>" %}

{% embed url="<https://tietokantojen-perusteet.github.io/>" %}

{% embed url="<https://www.guru99.com/database-normalization.html>" %}

{% embed url="<https://gerardnico.com/data/modeling/normalization>" %}

{% embed url="<https://tietokantojen-perusteet-19.mooc.fi/osa-4/1-tietokannan-normalisointi>" %}


# SQL View

View on niin sanotusti virtuaalinen taulu, joka muodostetaan halutusta kyselystä.

Tutustu aiheeseen lisää osoitteessa <http://www.mysqltutorial.org/mysql-views-tutorial.aspx>

## Hyötyjä

### 1. Monimutkaisten hakujen "tallentaminen"

Relaatiotietokannoissa taulujen tietoja yhdistetään JOIN komennoilla. Kun tauluja on useampia, voi kyselystä tulla monimutkainen. Tällainen kysely voidaan tallentaa omaksi **"näkymäkseen"**, jolloin seuraavan kerran voidaan haku tehdä luotuun näkymään. Näkymä on siis virtuaalinen taulu, johon `SELECT` haku voidaan osoittaa.

### 2. Logiikan yhtenäistäminen

Voidaan ajatella tilanne, jossa luot esimerkiksi raportin tietokannan tiedoista. Raportti sisältäisi joitakin laskukaavoja mitkä on vaikea muistaa tai kirjoittaa hakuihin. Tähän tarpeeseen voidaan myös luoda näkymä, joka sisältää tällaiset laskukaavat, jotta jatkossa samojen tietojen hakeminen on yksinkertaisempaa.

Suppose you have to repeatedly write the same formula in every query.  Or you have a query that has complex business logic. To make this logic consistent across queries, you can use a view to store the calculation and hide the complexity.

### 3. Tietoturvan lisääminen

Kaikkea tietoa ei aina tule näyttää tietokannan käyttäjille. Tällaista arkaluonteista tietoa voidaan suodattaa pois hakukyselyllä ja muodostaa näkymä, joka ei sisällä arkaluonteista tietoa. Tietokannoissa voidaan sitten antaa näkymään oikeudet vain tietyille käyttäjille eikä heitä päästetä tekemään hakuja kaikista tauluista.

### 4. Yhteensopivuus vanhojen ohjelmien kanssa

Tietokannat muuttuvat ohjelman päivitysten yhteydessä. Usein tulee uusia tauluja tai vanhoista halutaan päästä eroon. Näkymät toimivat myös tällaisessa tilanteessa, että voidaan luoda esimerkiksi väliaikainen näkymä, joka muistuttaa vanhan version taulua. Tässä tilanteessa ohjelma saattaisi toimia normaalisti erilaisten päivitystöiden jälkeen, koska ohjelmalle ei ole väliä minkälaisesta taulusta tieto on haettu.

## Lähteet

{% embed url="<http://www.mysqltutorial.org/mysql-views-tutorial.aspx>" %}


# Tehtävä 001 Tietokannan suunnittelu

## **Tehtävän tavoite**

Tietokannat ovat usein osa tietojärjestelmää ja ratkaisevat jonkin ongelman. Usein ongelmaan liittyy liiketoiminta minkä tueksi ratkaisua tehdään. Tehtävän tavoitteena on oppia tietokannan suunnittelun perusteita toimeksiannon ratkaisemiseksi.<br>

## Asiakkaan tarve

Riihimäen Lukutoukat Ry **(jäljempänä Lukutoukat)** on perustamassa pientä kirjalainaamoa jäsenilleen. Tässä he tarvitsevat apuasi sopivan järjestelmän tietokannan mallintamiseen.\
\
Lukutoukat ovat ajatelleet tarvitsevan pienen lainausjärjestelmän. Tietojärjestelmälle haetaan tukirahoja mutta sitä varten heillä tulisi olla tieto millainen palvelu tulee olemaan.&#x20;

Lukutoukat ovat kuulleet, että tietokanta on tässä isossa osassa ja pyytävät sinulta apua suunnittelemaan heidän tarpeisiinsa sopivan tietokantaratkaisun.

\
**Tietojärjestelmän tulisi pystyä toteuttamaan seuraavanlaisia asioita:**

* Pitämään yksinkertaista kirjarekisteriä jäsenien kirjoista.&#x20;
* Jäsenien tulee pystyä merkitsemään kirjasta siihen kuuluvat perustiedot, jotta näillä tiedoilla voidaan myös hakea kirjoja.&#x20;
* Kaikkia järjestelmään merkittyjä kirjoja voi lainata.
* Lainausjärjestelmän avulla tulisi tietää kuka omistaa kirjan ja kenellä se on kyseisellä hetkellä lainassa.
* Jäsenet voivat lainata useita kirjoja kerrallaan ja heidän pitää pystyä myös tietämään kirjat, jotka ovat heillä lainassa ja milloin ne pitää palauttaa.&#x20;
* Lukutoukat ovat päättäneet, että kirja saa olla lainaushetkestä lähtien enintään 30 päivää lainassa.&#x20;
* Kirjoista tulisi myös nähdä niiden lainaushistoria eli milloin ne ovat lainattu.
* Jos kirja on lainassa ja ei ole sillä hetkellä saatavissa niin jäsenen pitäisi pystyä ilmoittamaan itsensä varausjonoon.

Lukutoukat palkitsevat jäseniä aktiivisesta lainaustoiminnasta. He ovat kiinnostuneet myös seuraavanlaisista yhteenvedoista, jotka tulisi saada selville tietokannan avulla.

* TOP 10 lista lainatuista kirjoista ja teoksista koko järjestelmän olemassaolon ajalta.
* Kirjoje ja teoksien määrä tietokannassa sekä erottelu moniko niistä on lainassa tai vapaana.
* Lista erääntyneistä kirjojen ja teoksien palautusajankohdista sekä kenellä kirja on sillä hetkellä lainassa.\ <br>


# Indeksointi

Mitä tarkoitetaan tietokantojen indeksoinnilla.

Indeksillä tarkoitetaan tiedon rakennetta, jonka tarkoituksena on nopeuttaa relaatiotietokantojen hakuja, jotta järjestelmä palauttaa haetut tiedot nopeammin. Vaikuttaa myös tietokannan suorituskykyyn. Käytännössä indeksi on uudelleen järjestettyä tietoa, joka vastaa paremmin haluttuun hakuun. Tietokanta ei kuitenkaan tallenna samaa tietoa uudelleen vaan käyttää viittauksia alkuperäiseen tietoon.

![https://d117h1jjiq768j.cloudfront.net/images/default-source/default-album/tutorialimages-album/odbc-album/ruseindxa.gif?sfvrsn=1](/files/-LqqrPUN18g44dRsRsxp)

## Esimerkki

{% embed url="<https://www.essentialsql.com/what-is-a-database-index/>" %}

## Algoritmit

{% embed url="<https://dev.mysql.com/doc/refman/5.5/en/index-btree-hash.html>" %}

### B-tree (B-puu)

![https://en.wikipedia.org/wiki/B-tree#/media/File:B-tree.svg](/files/-LqqtAIHay_PPtZqnwM1)

## Käytännön esimerkki

Testitietokanta ladattavissa <https://github.com/nyluntu/test_db> ja siihen liittyvää dokumentointia <https://dev.mysql.com/doc/employee/en/>.

Seuraavia asioita voit kokeilla, jos luot itsellesi testitietokannan githubissa olevien ohjeiden mukaisesti. Testitietokannassa on miljoonia rivejä, joten se on hieman suurempi kuin muut esimerkit.

### Mitä indeksejä tietokannassa on?

Jos et tunne käsiteltävää tietokantaa. Seuraava SQL kysely auttaa sinua löytämään kaikki siinä käytössä olevat indeksit.

```sql
SELECT DISTINCT TABLE_NAME, INDEX_NAME 
FROM INFORMATION_SCHEMA.STATISTICS 
WHERE TABLE_SCHEMA = 'employees' -- employees on siis tietokannan nimi tässä.

-- Yhden taulun indeksit voi hakea seuraavalla komennolla:
SHOW INDEX FROM employees;
```

![Employees tietokannan indeksit](/files/-LqqvNIdvAWR25VcIu2C)

Kun käytetään `SELECT` hakua, se suoritetaan yksi komento kerrallaan. Hakujen nopeuteen vaikuttavat useat siinä esiintyvät avainsanat. `(join order, group, where jne)` Mysql pyrkii käyttämään apuna indeksejä, joilla se voi rajata jo alussa pois rivejä mitä ei tarvitse käydä läpi. Usein `WHERE` ehdossa esitellyt ehdot ovat tärkeimpiä haun nopeuteen liittyen. Väärällä tavalla kirjoitetut haut voivat olla raskaita tietokannalle ja niiden suorittaminen vie aikaa.

### Esimerkki 01

```sql
-- Haetaan työntekijöiden suurin palkka niiltä
-- joiden työnimike on Technique Leader sekä
-- etunimi tai sukunimi alkaa Emi -merkeillä.
SELECT 
    em.emp_no, 
    MAX(sa.salary),
    em.first_name,
    em.last_name
FROM salaries as sa
LEFT JOIN employees as em USING(emp_no)
LEFT JOIN titles as ti using(emp_no)
WHERE ti.title like 'Technique Leader'
and (em.first_name like 'Emi%' or em.last_name like 'Emi%')
GROUP BY em.emp_no

-- Sama kysely käyttäen EXPLAIN komentoa
EXPLAIN SELECT 
    em.emp_no, 
    MAX(sa.salary),
    em.first_name,
    em.last_name
FROM salaries as sa
LEFT JOIN employees as em USING(emp_no)
LEFT JOIN titles as ti using(emp_no)
WHERE ti.title like 'Technique Leader'
and (em.first_name like 'Emi%' or em.last_name like 'Emi%')
GROUP BY em.emp_no
	
-- Komentojen indeksien luontiin
ALTER TABLE `employees`.`employees` ADD INDEX `ix_employees_firstname` (`first_name`);
ALTER TABLE `employees`.`employees` ADD INDEX `ix_employees_lastname` (`last_name`);

```

## Lähteet

{% embed url="<https://en.wikipedia.org/wiki/Database_index>" %}

{% embed url="<https://www.essentialsql.com/what-is-a-database-index/>" %}


# Hitaat hakukyselyt

Luku pohjustaa asiaa miksi indeksit, taulujen osiointi ja muut vastaavat tavat ovat eduksi tietokantoja suunnitellessa.

## Olipa kerran ...

vaatemyymälä, jonka yhdestä toimipisteestä on päästy laajenemaan useampaan kaupunkiin. Toimintatapoja on yhtenäistetty ja mukaan on otettu kassajärjestelmä, jonne myynnit merkitään. Tämä on mahdollistanut myös uusia tapoja tarjota palveluita asiakkaille. Kanta-asiakas voi esimerkiksi tilata vaatteensa verkkokaupasta ja käydä noutamassa tuotteet myymälöistä.

Asiakkaan saapuessa myymälään, on varmistettava hänen henkilöllisyytensä. Myymälän tiskillä on yksi kone, josta asiakaspalvelija hakee asiakkaan nimellä hänen tilauksensa. Järjestelmä kertoo mitkä tilaukset tai tuotteet ovat noutamatta. Annettuaan tuotteet asiakkaalle, merkitsee asiakaspalvelija kyseiset tuotteet noudetuksi.

Ajankohta sijoittuu suurimpiin juhlapyhiin ja monet asiakkaat ovat etsimässä vaatteita itselleen tai lahjaksi. Kyseisellä hetkellä myymälä oli normaalia ruuhkaisempi.

Palvellessaan nouto-asiakasta, hänen takanaan seisoi kaksi muuta asiakasta. Toisella oli mukanaan hänen valitsemansa vaatteet, toinen puolestaan etsi vaatteita lapsilleen. 6 min kuluttua jälkimmäinen asiakas poistui myymälästä.&#x20;

Poistunut asiakas tarkoittaa menetettyä myyntiä. Miksi näin tapahtui?

## Asiakaspalvelijan näkökulmasta ...

Myymälä on täynnä ja toinen asiakaspalvelija on jo varattu. Asiakas tulee kysymään ennalta maksettuja tuotteitaan, jotka on varannut. Asiakaspalvelija jättää sen hetkiset kesken ja siirtyy kohti tiskiä.

Tiskin takana on hyllykössä varatut tuotteet jo valmiiksi pakattuna. Ennen tuotteiden luovuttamista on ollut tapana, että kyseiset tuotteet tulee merkitä noudetuksi. Asiakas on asioinut usein kyseisessä vaatemyymäläketjussa ja hänellä on ollut useita varauksia.

Asiakaspalvelija kysyy asiakkaalta henkilökorttia. Asiakkaan varaukset haetaan kortissa mainitulla nimellä. Asiakaspalvelija kirjoittaa asiakkaan sukunimen hakukenttään. *Kassajärjestelmän haku kestää 15 (pitkää) sekuntia.*&#x20;

Sukunimi on kuitenkin kovin yleinen ja tarjoaa kymmeniä vaihtoehtoja. Asiakaspalvelija pyrkii tarkentamaan hakua ja tekee uuden käyttäen suku- ja etunimeä. *Kassajärjestelmän haku kestää 16 (pitkää) sekuntia.*&#x20;

Asiakas katselee ympärilleen ja ottaa hieman tukea tiskistä. Asiakaspalvelija huomaa tehneen virheen etunimeä kirjoittaessa ja tekee uuden haun. *Kassajärjestelmän haku kestää 16 (pitkää) sekuntia.*

Vihdoin! Asiakaspalvelija huomaa, että samalla nimellä löytyy useita tilauksia. Valitettavasti tilauksesta ei heti näe tuotteita joita tilauksessa on. Tilaukset pitää aukaista yksitellen. Asiakaspalvelija kysyy vielä puhelinnumeroa varmistaakseen, että on kyse oikeasta asiakkaasta. **Ei ollut!.** Asiakkaan taakse on tullut toinen asiakas vaatteet käsillään.

Tilauksista siirtyessä toiseen, ikävä kyllä järjestelmä tekee saman haun uudestaan. *Kassajärjestelmän haku kestää 16 (pitkää) sekuntia.*

Seuraava tilaus on oikea! Asiakaspalvelija noutaa oikean paketin ja luovuttaa sen asiakkaalle. Luovutus vahvistetaan asiakkaalle. *Kassajärjestelmän vahvistaessa noudon, siinä kestää 5 sekuntia.*&#x20;

Asiakas päättää vielä ostaa joitakin pareja tarjouksessa olevia sukkia, jotka näki odottaessaan tiskillä. Asiakaspalvelija tekee kassajärjestelmään myynnin. Myyntiä varten tarvitaan asiakkaan yhteystiedot. Asiakaspalvelija hakee asiakkaan nimellä tietoja. *Kassajärjestelmän haku kestää 10 (pitkää) sekuntia.*&#x20;

Tässä kohdin jo kolmas asiakas on tullut jonoon kysyäkseen neuvoa. Ensimmäinen asiakas on suorittamassa maksuaan. Ensimmäinen asiakas saa asiansa hoidettua ja asiakaspalvelija on sulkemassa hänen tilauksiaan sekä valmistautumassa ottamaan seuraavan asiakkaan... kunnes hän kuulee seuraavat sanat.

> Ai niin! Sattuikohan minulla olla mitään muuta täällä varattuna?

Asiakaspalvelija hakee jälleen kerran asiakkaan nimellä hänen tilauksensa. *(16 sekuntia)* Tilauksia löytyy nimellä noin 20 kpl. Löytääkseen noudettavia tuotteita, joutuu asiakaspalvelija käymään läpi nämä kaikki varmistaakseen asian.

Kolmas asiakas lähtee myymälästä pois.

##

&#x20;


# Esimerkkitietokannan käyttöönotto

{% embed url="<https://www.youtube.com/watch?v=R-oLcggocvM&list=PL3iay_FdAzV_DrpXk7csd90fyUitBQEEK&index=2>" %}


# Mysql perusteet 101

Harjoitustietokanta https\://dev.mysql.com/doc/sakila/en/

**Selitä omin sanoin alla olevat tietokantoihin liittyvät käsitteet.**

* Tietokanta (database)
* Taulu (table)
* Sarake (column)
* Rivi (row)
* Päällekkäisyys/Toistuvuus (Redundancy)
* Pääavain (Primary key, lue myös [*pääavaimista*](/relaatiotietokannat/paeae-ja-viiteavaimet).)
* Uniikki/Yksilöllinen avain (Unique key)
* Kooste avain (compound key, composite key)
* Viiteavain (Foreign key, lue myös [*viiteavaimista*](/relaatiotietokannat/paeae-ja-viiteavaimet#viiteavain).)
* Indeksi (Index, lue myös [indeksoinnista](/relaatiotietokannat/indeksointi).)
* Viite-eheys (Referential Integrity)
* Asiakas-Palvelin arkkitehtuuri (Client/Server Architecture)
* ER -kaavio (Entity–Relationship model, lue myös [*ER-kaavioista*](/relaatiotietokannat/er-kaaviot).)&#x20;

**Yhdistä edellä mainitut käsitteet alla olevaan kuvaan.**

![](/files/-LpdZfh7z4-7pG1dZIo8)


# Mysql perusteet 102

Harjoitustietokanta https\://dev.mysql.com/doc/sakila/en/

Kirjoita SQL kyselyt, jotka vastaavat alla oleviin kysymyksiin. Yhteen kysymykseen voi liittyä yksi tai useampia SQL lauseita, joten ratkaisutavalla ei sinällään ole väliä kunhan siinä on käytetty SQL -kyselyitä.

Vältä vastausten katsomista etukäteen mutta ne auttavat, jos muuten jää jossakin kohdin jumiin.

Jos vastausta ei silti löydy, niin yritä silloin selittää itsellesi vastauksen SQL kysely ja selvittää mitä se varsinaisesti teki. Esimerkiksi vieraat SQL komennot.

{% content-ref url="/pages/-MFVqNDic41iqISQA8lU" %}
[mysql-perusteet-102-vastaukset](/sql-harjoitukset-ja-esimerkit/mysql-perusteet-102/mysql-perusteet-102-vastaukset)
{% endcontent-ref %}

**1. Montako riviä on Sakila tietokannan tauluissa? (jokaisen taulun rivien määrä erikseen, ei tarvitse olla yhteenlaskettua summaa kaikkien taulujen osalta.)**

**2. Keitä eri näyttelijöitä on merkitty tietokantaan? Etu- ja sukunimi riittävät.**

**3. Missä eri kaupunginosissa asiakkaat ovat? Yksilölliset kaupunginosien nimet ovat tärkeitä ja montako kpl yhteensä eri yksilöllisiä kaupunginosia on?**&#x20;

**4. Elokuvista tarvitaan listaus verkkosivulle, jossa esiintyy niiden nimi, kuvaus, vuokrausajan kesto, vuokran hinta, elokuvan pituus ja luokitus.**

**5. Inventaariota varten tarvitaan tieto montako kopiota (inventory taulu) elokuvista on yhteensä olemassa? Ei tarvitse erotella sitä onko elokuva tällä hetkellä vuokrattu vai ei. Riittää kokonaismäärä.**

{% hint style="info" %}
Vinkki tehtävään 5. Lue sakila tietokannan kuvauksesta mikä on inventory taulun tarkoitus. <https://dev.mysql.com/doc/sakila/en/sakila-structure-tables-inventory.html>
{% endhint %}

**6. Montako erilaista kielivaihtoehtoa elokuville on olemassa?**

**7. Montako eri kategoriaa elokuville on olemassa?**

**8. Tulevaa pääsiäistä varten on suunnitteilla kampanja lapsiperheille. Kampanjaa varten tarvitaan tieto siitä monta elokuvaa on olemassa, joiden genreksi on merkitty animaatio, lapsille tai perheille.**

**9. Edellistä kampanjaa tarvitaan myös lista elokuvien nimestä, vuokran hinnasta ja luokituksesta tulevalle verkkosivulle. Elokuvien genreksi pitää olla merkitty siis animaatio, lapsille tai perheille.**

**10. Järjestelmä näyttää virhettä elokuvalle, jonka tunniste on 453? Mikä on tämän elokuvan nimi?**


# mysql-perusteet-102-vastaukset

Jos vastausta ei silti löydy, niin yritä silloin selittää itsellesi vastauksen SQL kysely ja selvittää mitä se varsinaisesti teki. Esimerkiksi vieraat SQL komennot.

**1. Montako riviä on Sakila tietokannan tauluissa? (jokaisen taulun rivien määrä erikseen, ei tarvitse olla yhteenlaskettua summaa kaikkien taulujen osalta.)**

Vastaukseksi soveltuu myös yksinkertaisempi SELECT count(\*) FROM film tyylinen komento. Silloin jokaisen taulun nimi pitää erikseen määritellä. Alla kuitenkin vaihtoehtoinen tapa selvittää yhden tietokannan kaikkien taulujen rivimäärät.

![](/files/-MFVXxroTXQ-ZgIAZdsM)

**2. Keitä eri näyttelijöitä on merkitty tietokantaan? Etu- ja sukunimi riittävät.**

![](/files/-MFVZIPCNDFqrDMLEe8l)

**3. Missä eri kaupunginosissa asiakkaat ovat? Yksilölliset kaupunginosien nimet ovat tärkeitä ja montako kpl yhteensä eri yksilöllisiä kaupunginosia on?**&#x20;

Kuvan sijaan myös seuraava haku on mahdollinen: `SELECT DISTINCT district FROM address;`

![](/files/-MFVZpLBMiOSRXO6YcEz)

**4. Elokuvista tarvitaan listaus verkkosivulle, jossa esiintyy niiden nimi, kuvaus, vuokrausajan kesto, vuokran hinta, elokuvan pituus ja luokitus.**

![](/files/-MFV_CjDH4FlLuN0KRk4)

**5. Inventaariota varten tarvitaan tieto montako kopiota (inventory taulu) elokuvista on yhteensä olemassa? Ei tarvitse erotella sitä onko elokuva tällä hetkellä vuokrattu vai ei. Riittää kokonaismäärä.**

{% hint style="info" %}
Vinkki tehtävään 5. Lue sakila tietokannan kuvauksesta mikä on inventory taulun tarkoitus. <https://dev.mysql.com/doc/sakila/en/sakila-structure-tables-inventory.html>
{% endhint %}

Aiemmassa esimerkkivastauksessa ollut tässä virhe. Vastauksen kysymykseen saa esimerkiksi kyselyllä: `SELECT COUNT(*) FROM inventory;`

Vastaus tulee siis siitä, että dokumenttia lukemalla selviää, että inventory taulussa on yksi rivi per vuokrattavan elokuvan kopio. Kopio tässä tarkoittaa fyysistä dvd-levyä.

**6. Montako erilaista kielivaihtoehtoa elokuville on olemassa?**

![](/files/-MFV_i3nD0g5dJVsQQ5v)

**7. Montako eri kategoriaa elokuville on olemassa?**

![](/files/-MFV_x126JX8CMXlxFYu)

**8. Tulevaa pääsiäistä varten on suunnitteilla kampanja lapsiperheille. Kampanjaa varten tarvitaan tieto siitä monta elokuvaa on olemassa, joiden genreksi on merkitty animaatio, lapsille tai perheille.**

![](/files/-MFVaW-4KVzxrsEWjo8N)

**9. Edellistä kampanjaa tarvitaan myös lista elokuvien nimestä, vuokran hinnasta ja luokituksesta tulevalle verkkosivulle. Elokuvien genreksi pitää olla merkitty siis animaatio, lapsille tai perheille.**

![](/files/-MFVagkx6woL0cVcJeSj)

**10. Järjestelmä näyttää virhettä elokuvalle, jonka tunniste on 453? Mikä on tämän elokuvan nimi?**

![](/files/-MFVaqicQgMDacXXF46Q)


# Mysql perusteet 103

Harjoitustietokanta https\://dev.mysql.com/doc/sakila/en/

Kirjoita SQL kyselyt, jotka vastaavat alla oleviin kysymyksiin. Yhteen kysymykseen voi liittyä yksi tai useampia SQL lauseita, joten ratkaisutavalla ei sinällään ole väliä kunhan siinä on käytetty SQL -kyselyitä.

Vältä vastausten katsomista etukäteen mutta ne auttavat, jos muuten jää jossakin kohdin jumiin.

Jos vastausta ei silti löydy, niin yritä silloin selittää itsellesi vastauksen SQL kysely ja selvittää mitä se varsinaisesti teki. Esimerkiksi vieraat SQL komennot.

{% content-ref url="/pages/-MFVbl6yfU0xbbS2SqBu" %}
[mysql-perusteet-103-vastaukset](/sql-harjoitukset-ja-esimerkit/mysql-perusteet-103/mysql-perusteet-103-vastaukset)
{% endcontent-ref %}

#### 1. Markkinointia varten tarvitaan lista kaikkien niiden asiakkaiden tunnisteesta, etunimestä, sukunimestä ja sähköpostista, joiden nimessä esiintyy *Angela*.

**2. Tulevaa viikonlopun kampanjaa varten tarvitaan lista niiden elokuvien nimistä, vuokran hinnasta ja luokituksesta, joiden kuvauksessa mainitaan sana&#x20;*****amazing*****? Tee kysely käyttäen LIKE ja REGEXP operaattoreita.**

**3. Tulevaa viikonlopun kampanjaa varten tarvitaan lista niiden elokuvien nimistä, vuokran hinnasta ja luokituksesta, joiden nimi alkaa merkeillä&#x20;*****pri?*****&#x20;Tee kysely käyttäen LIKE ja REGEXP operaattoreita.**

**4. Montako näyttelijää tietokannassa on, joiden sukunimi loppuu&#x20;*****son?*****&#x20;Tee kysely käyttäen LIKE ja REGEXP operaattoreita.**

**5. Listaa kaikki asiakkaiden tiedoista löytyvät kaupunkien nimet aakkosjärjestyksessä, jossa kaupunkien nimi loppuu&#x20;*****r*****&#x20;-kirjaimeen.**

**6. Listaa seuraavien lueteltujen maiden tunniste ja nimi sekä järjestä lopputulos aakkosjärjestykseen:  Lithuania, Finland, Austria (Käytä IN operaattoria)**

**7. Listaa ne näyttelijät sukunimen mukaan aakkosjärjestyksessä, joiden sukunimi esiintyy kaksi kertaa tai useammin?**

#### **8**. Tulevaa kauppiaspalaveria varten tarvitaan tieto montako elokuvan nimikettä on per kategoria/genre? Tuloksessa pitää näkyä elokuvan kategorian tunniste sekä määrä sen perässä. Järjestä tulokset suurimmasta pienimpään määrän perusteella.

**9. Ryhmiteltynä elokuvien suositusmääritysten (rating) perusteella, mikä on keskimääräinen vuokrahinta ja elokuvan kesto?**

**10. Uusien elokuvien ostamista varten myymälä 2 (store\_id) tarvitsee listan nykyisistä kopioiden määristä varastossa, joka sisältää top 30 elokuvaa varastossa olevien määrän mukaan, järjestettynä suurimmasta  pienimpään. Elokuvasta riittää elokuvan tunniste ja niiden määrä.**

&#x20;&#x20;


# mysql-perusteet-103-vastaukset

#### 1. Markkinointia varten tarvitaan lista kaikkien niiden asiakkaiden tunnisteesta, etunimestä, sukunimestä ja sähköpostista, joiden nimessä esiintyy *Angela*.

![](/files/-MFVcMIRoySuEwo_N94Z)

**2. Tulevaa viikonlopun kampanjaa varten tarvitaan lista niiden elokuvien nimistä, vuokran hinnasta ja luokituksesta, joiden kuvauksessa mainitaan sana&#x20;*****amazing*****? Tee kysely käyttäen LIKE ja REGEXP operaattoreita.**

![](/files/-MFVcPH53YETwzmWoo-t)

![](/files/-MFVcT6eoS_4pnOwkMdp)

**3. Tulevaa viikonlopun kampanjaa varten tarvitaan lista niiden elokuvien nimistä, vuokran hinnasta ja luokituksesta, joiden nimi alkaa merkeillä&#x20;*****pri?*****&#x20;Tee kysely käyttäen LIKE ja REGEXP operaattoreita.**

![](/files/-MFVcgNvq4LELwKP-MPC)

![](/files/-MFVcjh3E5jPAykatybQ)

**4. Montako näyttelijää tietokannassa on, joiden sukunimi loppuu&#x20;*****son?*****&#x20;Tee kysely käyttäen LIKE ja REGEXP operaattoreita.**

![](/files/-MFVdNGPbp90FMVm7d54)

![](/files/-MFVdJvNkOnOcmOGhSjb)

**5. Listaa kaikki asiakkaiden tiedoista löytyvät kaupunkien nimet aakkosjärjestyksessä, jossa kaupunkien nimi loppuu&#x20;*****r*****&#x20;-kirjaimeen.**

![](/files/-MFVdaN-m1FM0GWjv49u)

**6. Listaa seuraavien lueteltujen maiden tunniste ja nimi sekä järjestä lopputulos aakkosjärjestykseen:  Lithuania, Finland, Austria (Käytä IN operaattoria)**

![](/files/-MFVdlwSFvOwCawWufZY)

**7. Listaa ne näyttelijät sukunimen mukaan aakkosjärjestyksessä, joiden sukunimi esiintyy kaksi kertaa tai useammin?**

![](/files/-MFVdxFn3qLcZbOj2Rf8)

#### **8**. Tulevaa kauppiaspalaveria varten tarvitaan tieto montako elokuvan nimikettä on per kategoria/genre? Tuloksessa pitää näkyä elokuvan kategorian tunniste sekä määrä sen perässä. Järjestä tulokset suurimmasta pienimpään määrän perusteella.

![](/files/-MFVe7FlMH84_jsO1GEF)

**9. Ryhmiteltynä elokuvien luokituksen (rating) perusteella, mikä on keskimääräinen vuokrahinta ja elokuvan kesto?**

![](/files/-MFVeLcCEAL2La3pWFh_)

**10. Uusien elokuvien ostamista varten myymälä 2 (store\_id) tarvitsee listan nykyisistä kopioiden määristä varastossa, joka sisältää top 30 elokuvaa varastossa olevien määrän mukaan, järjestettynä suurimmasta  pienimpään. Elokuvasta riittää elokuvan tunniste ja niiden määrä.**

![](/files/-MFVfEcUm0nrCoIjKFah)


# Mysql perusteet 104

Harjoitustietokanta https\://dev.mysql.com/doc/sakila/en/

Kirjoita SQL kyselyt, jotka vastaavat alla oleviin kysymyksiin. Yhteen kysymykseen voi liittyä yksi tai useampia SQL lauseita, joten ratkaisutavalla ei sinällään ole väliä kunhan siinä on käytetty SQL -kyselyitä.

Vältä vastausten katsomista etukäteen mutta ne auttavat, jos muuten jää jossakin kohdin jumiin.

Jos vastausta ei silti löydy, niin yritä silloin selittää itsellesi vastauksen SQL kysely ja selvittää mitä se varsinaisesti teki. Esimerkiksi vieraat SQL komennot.

{% content-ref url="/pages/-MFVmmcseL27HQVw5o4X" %}
[mysql-perusteet-104-vastaukset](/sql-harjoitukset-ja-esimerkit/mysql-perusteet-104/mysql-perusteet-104-vastaukset)
{% endcontent-ref %}

#### 1. Elokuvista tarvitaan listaus verkkosivulle, järjestettynä nimen mukaan aakkosjärjestyksessä, jossa esiintyy elokuvan nimi, kuvaus, vuokra-ajan kesto, vuokran hinta, elokuvan pituus, luokitus, kategorian nimi. (**käytä joineja**)

**2. Listaa elokuvista nimi ja siinä olevien näyttelijöiden määrä, järjestettynä näyttelijöiden määrän mukaan suurimmasta pienimpään. (käytä joineja)**

**3. Kuinka paljon eri myyjät (henkilökunta) ovat tehneet myyntiä Heinäkuussa 2005 maksusuoritusten perusteella? Listaa myyjän nimi ja sen perässä summa myynnistä. (taulut payment ja staff, käytä joineja)**

**4. Listaa kaikkien työntekijöiden koko nimi ja koko katuosoite siten, että nimi sekä katuosoite ovat yksittäisiä kenttiä (Concat, käytä joineja)**

**5. Kuinka monta kopiota on olemassa elokuvasta 'DRACULA CRYSTAL' varastossa? Ei tarvitse välittää onko lainassa vai ei. Tulokseen täytyy tulostaa elokuvan nimi sekä kopioiden määrä (käytä joineja)**

**6. Sähköpostimarkkinointia varten tarvitaan lista top 100 lista kaikista eniten maksaneista asiakkaista. Tulosteessa pitää näkyä asiakkaan etunimi, sukunimi, sähköposti sekä summa paljonko asiakas on maksanut koko ostohistorian aikana. Järjestä tulokset suurimmasta pienimpään kokonaissumman perusteella. (käytä joineja)**

**7. Sähköpostimarkkinointia varten tarvitaan lista kaikista Ukrainassa (Ukraine) olevista asiakkaista osoitetiedon perusteella. Listaa asiakkaista etunimi, sukunimi ja sähköposti. (käytä tauluja customer, address, city, country)**

**8. Markkinoinnista vastaavaa henkilöä kiinnostaa tietää top 3 genreä/kategoriaa myynnin perusteella. (tarvitset useampia tauluja tämän tekemiseen, category, film\_category, inventory, payment, rental). Listaa tulokset myynnin mukaan suurimmasta pienimpään siten, että tuloksessa näkyy kategorian nimi ja myynti.**&#x20;


# mysql-perusteet-104-vastaukset

#### 1. Elokuvista tarvitaan listaus verkkosivulle, järjestettynä nimen mukaan aakkosjärjestyksessä, jossa esiintyy elokuvan nimi, kuvaus, vuokra-ajan kesto, vuokran hinta, elokuvan pituus, luokitus, kategorian nimi. (**käytä joineja**)

![](/files/-MFVnp6BfRzJrvxwlquC)

![](/files/-MFVnl5NqJSubrnfuMl5)

**2. Listaa elokuvista nimi ja siinä olevien näyttelijöiden määrä, järjestettynä näyttelijöiden määrän mukaan suurimmasta pienimpään. (käytä joineja)**

![](/files/-MFVo406LyPMPR_kgnt7)

![](/files/-MFVo74w-SUy9JpnHMw4)

**3. Kuinka paljon eri myyjät (henkilökunta) ovat tehneet myyntiä Heinäkuussa 2005 maksusuoritusten perusteella? Listaa myyjän nimi ja sen perässä summa myynnistä. (taulut payment ja staff, käytä joineja)**

![](/files/-MFVoWUjFWe1QqJ_ACBX)

![](/files/-MFVoYyZhL7BtZ0m-gDF)

**4. Listaa kaikkien työntekijöiden koko nimi ja koko katuosoite siten, että nimi sekä katuosoite ovat yksittäisiä kenttiä (Concat, käytä joineja)**

![](/files/-MFVouzSjlFnAKtDS6mA)

![](/files/-MFVp8qbxF3i4h_QpC2Z)

**5. Kuinka monta kopiota on olemassa elokuvasta 'DRACULA CRYSTAL' varastossa? Ei tarvitse välittää onko lainassa vai ei. Tulokseen täytyy tulostaa elokuvan nimi sekä kopioiden määrä (käytä joineja)**

![](/files/-MFVpT69JxGKxkshHIy1)

![](/files/-MFVpWWlMt_OjW84fQpU)

**6. Sähköpostimarkkinointia varten tarvitaan lista top 100 lista kaikista eniten maksaneista asiakkaista. Tulosteessa pitää näkyä asiakkaan etunimi, sukunimi, sähköposti sekä summa paljonko asiakas on maksanut koko ostohistorian aikana. Järjestä tulokset suurimmasta pienimpään kokonaissumman perusteella. (käytä joineja)**

![](/files/-MFVppJ8VDpBh3cnzE-R)

![](/files/-MFVpsZg69nS-1CpRknC)

**7. Sähköpostimarkkinointia varten tarvitaan lista kaikista Ukrainassa (Ukraine) olevista asiakkaista osoitetiedon perusteella. Listaa asiakkaista etunimi, sukunimi ja sähköposti. (käytä tauluja customer, address, city, country)**

![](/files/-MFVq1kqT94CXr9-mX63)

![](/files/-MFVq4LM1eY6i_xfXrFC)

**8. Markkinoinnista vastaavaa henkilöä kiinnostaa tietää top 3 genreä/kategoriaa myynnin perusteella. (tarvitset useampia tauluja tämän tekemiseen, category, film\_category, inventory, payment, rental). Listaa tulokset myynnin mukaan suurimmasta pienimpään siten, että tuloksessa näkyy kategorian nimi ja myynti.**&#x20;

![](/files/-MFVqEYWq4dsvpRZTQvv)

![](/files/-MFVqHhEDsMRHJwev7Iz)


# Mysql perusteet 105

Harjoitustietokanta https\://dev.mysql.com/doc/sakila/en/

Kirjoita SQL kyselyt, jotka vastaavat alla oleviin kysymyksiin. Yhteen kysymykseen voi liittyä yksi tai useampia SQL lauseita, joten ratkaisutavalla ei sinällään ole väliä kunhan siinä on käytetty SQL -kyselyitä.

Vältä vastausten katsomista etukäteen mutta ne auttavat, jos muuten jää jossakin kohdin jumiin.

Jos vastausta ei silti löydy, niin yritä silloin selittää itsellesi vastauksen SQL kysely ja selvittää mitä se varsinaisesti teki. Esimerkiksi vieraat SQL komennot.

{% content-ref url="/pages/-MFVq\_flNblC1M60vKl4" %}
[mysql-perusteet-105-vastaukset](/sql-harjoitukset-ja-esimerkit/mysql-perusteet-105/mysql-perusteet-105-vastaukset)
{% endcontent-ref %}

#### 1. Näyttelijän Liza Bergman manageri ilmoitti, että hänen etunimensä on kirjoitettu väärin. Etunimi kuuluisi olla muodossa Elizabeth.. Millä komennoilla voit korjata virheen? Sisällytä kaikki vaiheet mitä tarvitset ratkaisun selvittämiseksi sekä todentamiseksi, että nimi on vaihdettu.

#### 2. Lisää tietokantaan yksi uusi elokuva, [*Teit meistä kauniin*](https://fi.wikipedia.org/wiki/Teit_meist%C3%A4_kauniin_\(elokuva\))*.* Ota mallia lähdetiedoista ja lisää niitä käyttäen elokuva listalle, tarvittaessa luo sitä varten eri riippuvuudet. Sisällytä kaikki vaiheet mitä tarvitset ratkaisun selvittämiseksi sekä todentamiseksi.

#### 3. Lisää Teit meistä kauniin -elokuvaan liittyvät pääosien näyttelijät. Sisällytä kaikki vaiheet mitä tarvitset ratkaisun selvittämiseksi sekä todentamiseksi.

**4. Teit meistä kauniin -elokuvan kopioita on ostettu yhteensä 15 kappaletta siten, että 9 niistä on lähetetty &#x20;*****Lethbridgen*****&#x20;myymälään. Loput kopiot sijaitsevat&#x20;*****Woodridgen*****&#x20;myymälässä. Kirjoita kaikki vaiheet millä tavoin saat lisättyä kopiot tietokantaan sekä ratkaisun todentamiseksi.**&#x20;

**5. Elokuvan Rainbow Shock näyttäminen on lopetettu tekijänoikeusrikkomusten vuoksi. Poista elokuva ja siihen liittyvät tiedot tietokannasta. Sisällytä kaikki vaiheet mitä tarvitset ratkaisun selvittämiseksi sekä todentamiseksi.**

**6. Lisää itsesi uudeksi asiakkaaksi asiakasrekisteriin. Osoitteen voit keksiä päästä mutta sen pitää olla jokin uusi osoite eikä mikään olemassaolevista. Sisällytä kaikki vaiheet mitä tarvitset ratkaisun selvittämiseksi sekä todentamiseksi.**

**7. Kotikaupunkiisi avataan uusi elokuvavuokraamo. Lisää tämä uusi myymälä tietokantaan sekä sille uusi myymälävastaava (manageri). Sisällytä kaikki vaiheet mitä tarvitset ratkaisun selvittämiseksi sekä todentamiseksi.**

**8. Päivitä edellä luomasi asiakkaan asiakastietoihin, että hänen pääasiallinen myymälänsä on edellisessä kohdassa luotu myymälä. Lisää myös 5 kappaletta&#x20;*****Teit meistä kauniin*****&#x20;-elokuvan kopioita tälle uudelle myymälälle.**

**9. Vuokraat&#x20;*****Teit meistä kauniin*****&#x20;-elokuvan asiakkaana, jona sinut on merkitty tietokantaan. Katso malli elokuvan vuokraamisesta seuraavasta lähteestä ja muokkaa komentoja siten, että ne soveltuvat tähän esimerkkiin:** [**https://dev.mysql.com/doc/sakila/en/sakila-usage.html#sakila-usage-rent-a-dvd**](https://dev.mysql.com/doc/sakila/en/sakila-usage.html#sakila-usage-rent-a-dvd)

**10.&#x20;*****Teit meistä kauniin*****&#x20;täytti kaikki odotuksesi. Palautat elokuvan. Katso esimerkki elokuvan palauttamisesta seuraavasta lähteestä ja muokkaa komentoja siten, että ne soveltuvat tähän esimerkkiin:** [**https://dev.mysql.com/doc/sakila/en/sakila-usage.html#sakila-usage-return-a-dvd**](https://dev.mysql.com/doc/sakila/en/sakila-usage.html#sakila-usage-return-a-dvd)


# mysql-perusteet-105-vastaukset

#### 1. Näyttelijän Liza Bergman manageri ilmoitti, että hänen etunimensä on kirjoitettu väärin. Etunimi kuuluisi olla muodossa Elizabeth.. Millä komennoilla voit korjata virheen? Sisällytä kaikki vaiheet mitä tarvitset ratkaisun selvittämiseksi sekä todentamiseksi, että nimi on vaihdettu.

![](/files/-MFVrzwN9pBXclBs0bzz)

#### 2. Lisää tietokantaan yksi uusi elokuva, [*Teit meistä kauniin*](https://fi.wikipedia.org/wiki/Teit_meist%C3%A4_kauniin_\(elokuva\))*.* Ota mallia lähdetiedoista ja lisää niitä käyttäen elokuva listalle, tarvittaessa luo sitä varten eri riippuvuudet. Sisällytä kaikki vaiheet mitä tarvitset ratkaisun selvittämiseksi sekä todentamiseksi.

Ensiksi pitää luoda uusi rivi `languages` tauluun, jotta se voidaan lisätä elokuvaan viitteeksi.

![](/files/-MFVw88ntOrQwHidkI-h)

![](/files/-MFVwAcFeHmzWr7FUJt2)

####

#### 3. Lisää Teit meistä kauniin -elokuvaan liittyvät pääosien näyttelijät. Sisällytä kaikki vaiheet mitä tarvitset ratkaisun selvittämiseksi sekä todentamiseksi.

Ensin lisätään näyttelijät. Kun nämä on lisätty niin hae tietokannan taulusta näyttelijät, jotta tiedät mitkä ovat niiden rivien pääavaimet jälkimmäistä kyselyä varten. Esimerkissä pääavaimet ovat numerot 201, 202, 203 ja nämä voivat olla eri sinun tietokannassa.

![](/files/-MFVxKbaKrscotAuW8SX)

![](/files/-MFVxOyI5vxpV-NogzZo)

**4. Teit meistä kauniin -elokuvan kopioita on ostettu yhteensä 15 kappaletta siten, että 9 niistä on lähetetty &#x20;*****Lethbridgen*****&#x20;myymälään. Loput kopiot sijaitsevat&#x20;*****Woodridgen*****&#x20;myymälässä. Kirjoita kaikki vaiheet millä tavoin saat lisättyä kopiot tietokantaan sekä ratkaisun todentamiseksi.**&#x20;

![](/files/-MFVyTk48WcT9m3l9EO1)

**5. Elokuvan Rainbow Shock näyttäminen on lopetettu tekijänoikeusrikkomusten vuoksi. Poista elokuva ja siihen liittyvät tiedot tietokannasta. Sisällytä kaikki vaiheet mitä tarvitset ratkaisun selvittämiseksi sekä todentamiseksi.**

![](/files/-MFVydneW7DFMWfxQ_LT)

**6. Lisää itsesi uudeksi asiakkaaksi asiakasrekisteriin. Osoitteen voit keksiä päästä mutta sen pitää olla jokin uusi osoite eikä mikään olemassaolevista. Sisällytä kaikki vaiheet mitä tarvitset ratkaisun selvittämiseksi sekä todentamiseksi.**

![](/files/-MFVzmkR7ITcMTGpOvJj)

**7. Kotikaupunkiisi avataan uusi elokuvavuokraamo. Lisää tämä uusi myymälä tietokantaan sekä sille uusi myymälävastaava (manageri). Sisällytä kaikki vaiheet mitä tarvitset ratkaisun selvittämiseksi sekä todentamiseksi.**

Tässä vastaus on monivaiheinen, joten mieti ensin, että mitä tietokantaan pitää lisätä ja mihinkä tauluihin. Tässä vaiheittain mitä pitää hoitaa.

* *Luodaan kaupalle osoite*
* *Luodaan työntekijälle osoite*
* *Luodaan kauppias*
* *Luodaan kauppa ja määritetään sinne juuri luotu kauppias*
* *Varmistetaan että kauppiaalla on oikea myymälä vastuulla*

**8. Päivitä edellä luomasi asiakkaan asiakastietoihin, että hänen pääasiallinen myymälänsä on edellisessä kohdassa luotu myymälä. Lisää myös 5 kappaletta&#x20;*****Teit meistä kauniin*****&#x20;-elokuvan kopioita tälle uudelle myymälälle.**

Katso mallia aiemmasta tehtävästä, jossa jo lisättiin vuokrattavia elokuvia myymälään.

**9. Vuokraat&#x20;*****Teit meistä kauniin*****&#x20;-elokuvan asiakkaana, jona sinut on merkitty tietokantaan. Katso malli elokuvan vuokraamisesta seuraavasta lähteestä ja muokkaa komentoja siten, että ne soveltuvat tähän esimerkkiin:** [**https://dev.mysql.com/doc/sakila/en/sakila-usage.html#sakila-usage-rent-a-dvd**](https://dev.mysql.com/doc/sakila/en/sakila-usage.html#sakila-usage-rent-a-dvd)

Tässä katso linkin esimerkki ja kokeile miten se toimii.

**10.&#x20;*****Teit meistä kauniin*****&#x20;täytti kaikki odotuksesi. Palautat elokuvan. Katso esimerkki elokuvan palauttamisesta seuraavasta lähteestä ja muokkaa komentoja siten, että ne soveltuvat tähän esimerkkiin:** [**https://dev.mysql.com/doc/sakila/en/sakila-usage.html#sakila-usage-return-a-dvd**](https://dev.mysql.com/doc/sakila/en/sakila-usage.html#sakila-usage-return-a-dvd)

Tässä katso linkin esimerkki ja kokeile miten se toimii.


# Mysql perusteet 106

Harjoitustietokanta https\://dev.mysql.com/doc/sakila/en/

Kirjoita SQL kyselyt, jotka vastaavat alla oleviin kysymyksiin. Yhteen kysymykseen voi liittyä yksi tai useampia SQL lauseita, joten ratkaisutavalla ei sinällään ole väliä kunhan siinä on käytetty SQL -kyselyitä.

Vältä vastausten katsomista etukäteen mutta ne auttavat, jos muuten jää jossakin kohdin jumiin.

Jos vastausta ei silti löydy, niin yritä silloin selittää itsellesi vastauksen SQL kysely ja selvittää mitä se varsinaisesti teki. Esimerkiksi vieraat SQL komennot.

#### 1. DVD -formaattien vuokraus on laskemaan päin. Myymälöihin on tarkoitus alkaa ostaa myös Blu-ray sekä 3D Blu-ray elokuvia. Kirjoita komennot mitä tarvitset luodaksesi taulun jakeluformaateille kun sen sisältö ja rakenne on alla kuvatun mukainen.

Taulun nimeksi tulee **format\_type** ja sen sarakkeet ovat:

* **type\_id**, pääavain, nouseva kokonaisluku, ei voi olla tyhjä, täytyy olla uniikki.
* **name**, merkkijono, sisältää jakelutyypin, esimerkiksi DVD, Blu-ray, 3D Blu-ray jne.
* **information\_url**, merkkijono, sisältää linkin jakeluformaatin lisätietoihin, esimerkiksi <https://fi.wikipedia.org/wiki/Blu-ray>

**2. Muuta taulun film -rakennetta siten, että lisäät siihen alla olevan kuvan mukaisen kentän. Kirjoita tarvittavat komennot. Selitä myös minkä tyyppinen viittaus (relaatio) tässä on kyseessä. (lue myös** [**ER -kaaviosta**](/relaatiotietokannat/er-kaaviot)**)**

* uusi kenttä on nimeltään **type\_id**.
* kentän pitää toimia viiteavaimena edellisessä vaiheessa luomaasi "format\_type" tauluun.
* oletusarvon pitää viitata DVD -jakeluformaattiin.
* kun teet muutoksen niin kaikkien aiempien elokuvien formaatiksi voit asettaa DVD.
* Muuta yhden elokuvan formaatiksi Blu-ray ja toisen elokuvan formaatiksi 3D Blu-ray.

**3. Kehittäjänä huomaat ongelman, että elokuville voi asettaa vain yhden jakeluformaatin. yhdellä elokuvalla voi kuitenkin olla useita eri jakeluformaatteja, joten tarvitsemme liitostaulun. Kirjoita tarvittavat komennot taulun luomista varten. Selitä myös minkä tyyppinen viittaus (relaatio) tässä on kyseessä. (lue myös** [**ER -kaaviosta**](/relaatiotietokannat/er-kaaviot)**)**

Taulun nimeksi tulee **film\_types** ja sen sarakkeet ovat:

* **film\_id**, tauluun film viittaava arvo, yksi osa pääavainta.
* **type\_id**, tauluun format\_type viittaava arvo, toinen osa pääavainta.
* Huomaa, että edelliset sarakkeet yhdessä ovat taulun pääavain.

**4. Liitostaulun myötä edellä luotua&#x20;*****film*****&#x20;taulun&#x20;*****type\_id*****&#x20;-saraketta ei enää tarvita. Kirjoita komennot, jolla voit poistaa kyseisen sarakkeen ja sitä ennen päivittää uuteen&#x20;*****film\_types*****&#x20;-tarvittavat tiedot.**

**5. Millä komennoilla saat kumottua edellisissä vaiheissa tehdyt muutokset? Kirjoita siis komennot, joilla voit poistaa&#x20;*****format\_type*****&#x20;ja&#x20;*****film\_types*****&#x20;taulut kaikkine tietoineen.**


# mysql-perusteet-106-vastaukset

#### 1. DVD -formaattien vuokraus on laskemaan päin. Myymälöihin on tarkoitus alkaa ostaa myös Blu-ray sekä 3D Blu-ray elokuvia. Kirjoita komennot mitä tarvitset luodaksesi taulun jakeluformaateille kun sen sisältö ja rakenne on alla kuvatun mukainen.

Taulun nimeksi tulee **format\_type** ja sen sarakkeet ovat:

* **type\_id**, pääavain, nouseva kokonaisluku, ei voi olla tyhjä, täytyy olla uniikki.
* **name**, merkkijono, sisältää jakelutyypin, esimerkiksi DVD, Blu-ray, 3D Blu-ray jne.
* **information\_url**, merkkijono, sisältää linkin jakeluformaatin lisätietoihin, esimerkiksi <https://fi.wikipedia.org/wiki/Blu-ray>

```sql
-- Luodaan tehtävänannon mukainen taulu.
CREATE TABLE format_type(
    type_id SMALLINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    NAME VARCHAR(32),
    information_url VARCHAR(100)
)

-- Asetetaan luotuun tauluun malliksi kolme erilaista levyformaattia.
INSERT INTO format_type(type_id, name, information_url)
VALUES 
( NULL, 'DVD', 'https://fi.wikipedia.org/wiki/DVD' ),
( NULL, 'Blu-ray', 'https://fi.wikipedia.org/wiki/Blu-ray' ),
(  NULL, '3D Blu-ray', 'https://en.wikipedia.org/wiki/List_of_Blu-ray_3D_releases' );
```

**2. Muuta taulun film -rakennetta siten, että lisäät siihen alla olevan kuvan mukaisen kentän. Kirjoita tarvittavat komennot. Selitä myös minkä tyyppinen viittaus (relaatio) tässä on kyseessä. (lue myös** [**ER -kaaviosta**](/relaatiotietokannat/er-kaaviot)**)**

* uusi kenttä on nimeltään **type\_id**.
* kentän pitää toimia viiteavaimena edellisessä vaiheessa luomaasi "format\_type" tauluun.
* oletusarvon pitää viitata DVD -jakeluformaattiin.
* kun teet muutoksen niin kaikkien aiempien elokuvien formaatiksi voit asettaa DVD.
* Muuta yhden elokuvan formaatiksi Blu-ray ja toisen elokuvan formaatiksi 3D Blu-ray.

```sql
-- Lisätään uusi sarake vanhaan olemassaolevaan film-tauluun
-- ja oletusarvoksi määritetään 1.
ALTER TABLE film ADD type_id SMALLINT DEFAULT 1

-- Sarakkeen luomisen jälkeen luodaan viiteavain edellisen tehtävän
-- format_type ja film -taulun välille. Käytetään siinä type_id-saraketta.
ALTER TABLE film
ADD CONSTRAINT FK_type_id
FOREIGN KEY(type_id) REFERENCES format_type(type_id)

-- Malliksi päivitetään kahdelle eri elokuvan nimikkeelle tämä eri formaatit.
-- type_id viitaa tässä format_type-taulun pääavaimeen.
UPDATE film SET type_id = 2 WHERE film_id = 1003
UPDATE film SET type_id = 3 WHERE film_id = 1
```

**3. Kehittäjänä huomaat ongelman, että elokuville voi asettaa vain yhden jakeluformaatin. yhdellä elokuvalla voi kuitenkin olla useita eri jakeluformaatteja, joten tarvitsemme liitostaulun. Kirjoita tarvittavat komennot taulun luomista varten. Selitä myös minkä tyyppinen viittaus (relaatio) tässä on kyseessä. (lue myös** [**ER -kaaviosta**](/relaatiotietokannat/er-kaaviot)**)**

Taulun nimeksi tulee **film\_types** ja sen sarakkeet ovat:

* **film\_id**, tauluun film viittaava arvo, yksi osa pääavainta.
* **type\_id**, tauluun format\_type viittaava arvo, toinen osa pääavainta.
* Huomaa, että edelliset sarakkeet yhdessä ovat taulun pääavain.

```sql
-- Luodaan uusi film_types taulu ja samalla sille viiteavaimet
-- film ja format_type -taulujen kanssa.
CREATE TABLE film_types ( film_id SMALLINT UNSIGNED, type_id SMALLINT, PRIMARY KEY(film_id, type_id), 
CONSTRAINT FK_film_id FOREIGN KEY (film_id) REFERENCES film(film_id) on UPDATE CASCADE, 
CONSTRAINT FK_type1_id FOREIGN KEY (type_id) REFERENCES format_type(type_id) on UPDATE CASCADE);

```

**4. Liitostaulun myötä edellä luotua&#x20;*****film*****&#x20;taulun&#x20;*****type\_id*****&#x20;-saraketta ei enää tarvita. Kirjoita komennot, jolla voit poistaa kyseisen sarakkeen ja sitä ennen päivittää uuteen&#x20;*****film\_types*****&#x20;-tarvittavat tiedot.**

```sql
-- Film-taulusta poistetaan ensin viitevain, joka on luotu edellisissä vaiheissa.
ALTER TABLE film DROP FOREIGN KEY FK_type_id;

-- Kun viiteavain on poistettu, voidaan poistaa type_id -sarake.
ALTER TABLE film DROP type_id;

-- Voidaan asettaa edellisen kohdan uudelle taululle myös oletusarvo
-- levyformaatiksi. Tämä ei ole pakollinen mutta toisaalta helpottaa 
-- asioita.
ALTER TABLE film_types  ALTER type_id SET DEFAULT 1;

-- Lisätään kaksi eri elokuvaa uuteen tauluun. Näille tulee oletuksena
-- DVD formaatti type_id -sarakkeen arvoksi.
INSERT INTO film_types (film_id) VALUES (3),(4);

-- Tässä yhdelle elokuvan nimikkeelle on määritetty kaksi eri levyformaattia.
-- Eli Blu-ray ja 3D Blu-ray. Film_id on tässä arvoltaan 5.
INSERT INTO film_types (film_id, type_id) VALUES (5,3),(5,2);
```

**5. Millä komennoilla saat kumottua edellisissä vaiheissa tehdyt muutokset? Kirjoita siis komennot, joilla voit poistaa&#x20;*****format\_type*****&#x20;ja&#x20;*****film\_types*****&#x20;taulut kaikkine tietoineen.**

```sql
-- Poistetaan film_types taulu.
DROP TABLE film_types;

-- Poistetaan format_type taulu.
DROP TABLE format_type;
```


# SQL hakukyselyjä (VANHAT)

Sivulle on kerätty harjoituksina tehtyjä kyselyjä. Kaikkia kyselyjä ei ole tarkistettu, joten niissä voi olla joitakin virheitä.

## Esimerkkikyselyjä

{% hint style="warning" %}
**Huom!** Seuraavat esimerkkikyselyt ovat tehty <https://www.mysqltutorial.org/mysql-sample-database.aspx> harjoitustietokantaa kohden vanhemmissa harjoituksissa. Uudemmissa tehtävissä käytetään Sakila tietokantaa.
{% endhint %}

Kuinka monta kertaa asiakkaat ovat tehneet tilauksia keskimäärin koko tilaushistorian ajalta?

```sql
SELECT customerNumber,
       COUNT(*)
FROM orders
GROUP BY customerNumber;

--kuinka monta kertaa yksittäinen asiakas on tilannut

SELECT customerNumber,
       COUNT(*)
FROM orders
WHERE status = "Shipped"
GROUP BY customerNumber;

--sama mutta näyttää vain ne jotka on shipped

SELECT AVG(d.c) AS keskiarvo
FROM
  (SELECT customerNumber,
          COUNT(*) AS c
   FROM orders
   WHERE status = "Shipped"
   GROUP BY customerNumber)AS d;
```

Päivissä kerrottuna, mikä on toistuvia tilauksia tehneiden asiakkaiden keskimääräinen tilausaika? Ostaako asiakas siis viikoittain, kuukausittain vai vuosittain tuotteita?&#x20;

```sql
SELECT customerNumber, (MAX(orderDate) - MIN(orderDate)) / (COUNT(*) – 1
FROM orders
GROUP BY customerNumber
HAVING COUNT(*) > 1;
```

Ketkä ovat asiakkaista ovat kärjessä tilauksien määrän mukaan järjestettynä koko tilaushistorian ajalta?

```sql
SELECT customerNumber,
       COUNT(*)
FROM orders
GROUP BY customerNumber
ORDER BY COUNT(*) DESC
LIMIT 3;
```

Montako tilausriviä tilaukset keskimäärin sisältävät koko tilaushistorian ajalta?

```sql
SELECT count(orderLineNumber) / count(DISTINCT orderNumber) AS orders
FROM orderdetails;
```

Tilauksien kokonaissummaa euroissa tarkasteltuna, mikä on kertaostosten keskimääräinen summa, maksimi ja minimi?

```sql
SELECT MAX(total),
       MIN(total),
       AVG(total)
FROM
  (SELECT orderNumber,
          SUM(quantityOrdered * priceEach) AS total
   FROM orderdetails
   GROUP BY orderNumber) AS x;
```

Mikä on keskimääräinen myynti kuukausittain lähetettyjen myyntien osalta koko tilaushistorian ajalta?

```sql
SELECT MONTH(orderDate) AS MONTH,
       YEAR(orderDate) AS YEAR,
       avg(quantityOrdered * priceEach) AS AVG
FROM orders
INNER JOIN orderdetails USING (orderNumber)
WHERE status = 'shipped'
GROUP BY YEAR,
         MONTH WITH ROLLUP;
```

Mikä on keskimääräinen toimitusaika tilauksen saapumisen ja lähettämisen välillä koko tilaushistorian ajalta?

```sql
SELECT round(avg(datediff(shippedDate, orderDate)))
FROM orders
WHERE status = 'shipped';
```

Ketkä asiakkaista ovat parhaiten maksavia asiakkaita, jotka ovat hoitaneet maksunsa?

```sql
SELECT contactFirstName,
       contactLastName,
       city,
       country,
       amount
FROM customers
INNER JOIN payments
ORDER BY `payments`.`amount` DESC;
```

Ketkä asiakkaista ovat parhaiten tilaavia eli ovat tehneet useimpia tilauksia?

```sql
SELECT contactFirstName,
       contactLastName,
       city,
       country,
       quantityOrdered
FROM customers
INNER JOIN orderdetails
ORDER BY `orderdetails`.`quantityOrdered` DESC;
```

Mitkä tuotteet ovat myyneet parhaiten koko tilaushistorian aikana?

```sql
SELECT productName,
       sum(quantityOrdered)
FROM products
INNER JOIN orderdetails ON products.productCode = orderdetails.productCode
GROUP BY productName
ORDER BY sum(quantityOrdered) DESC
LIMIT 10;
```

Pienoismallin koon mukaan laskettuna, mitkä tuotteista ovat myyneet parhaiten tilaushistorian aikana?

```sql
SELECT productScale,
       sum(quantityOrdered) AS "Total orders",
       sum(quantityOrdered*priceEach) AS "Total sales"
FROM products
INNER JOIN orderdetails ON products.productCode = orderdetails.productCode
GROUP BY productScale
ORDER BY sum(quantityOrdered) DESC;
```

Keskittyen vain muutamaan parhaiten myyvään tuotteeseen niin mihin maihin kyseisiä tuotteita myydään?

```sql
SELECT country,
       city,
       productCode,
       sum(quantityOrdered*priceEach) AS total
FROM orderdetails
INNER JOIN orders ON orderdetails.orderNumber = orders.orderNumber
INNER JOIN customers ON customers.customerNumber = orders.customerNumber
WHERE productCode IN ("S700_4002",
                      "S18_3232",
                      "S18_1342")
GROUP BY country,
         city,
         productCode
ORDER BY `total` DESC;
```

Mitkä tuoteryhmistä ovat parhaiten myyviä koko tilaushistorian aikana?

```sql
SELECT productLine,
       sum(quantityOrdered*priceEach)
FROM products
INNER JOIN orderdetails ON products.productCode = orderdetails.productCode
GROUP BY productLine
ORDER BY sum(quantityOrdered*priceEach) DESC;
```

Ketkä ovat TOP10 huippumyyjää koko tilaushistorian ajalta?

```sql
SELECT salesRepEmployeeNumber,
       firstName,
       lastName,
       officeCode,
       SUM(quantityOrdered * priceEach) sales
FROM customers
INNER JOIN orders USING (customerNumber)
INNER JOIN orderdetails USING (ordernumber)
INNER JOIN employees ON employeeNumber = salesRepEmployeeNumber
INNER JOIN offices USING (officeCode)
GROUP BY salesRepEmployeeNumber
ORDER BY sales DESC
LIMIT 10;
```

Mitkä toimipaikoista ovat parhaiten myyviä niiden myynnin mukaan järjestettynä?

```sql
SELECT officeCode,
       offices.city,
       SUM(quantityOrdered * priceEach) sales
FROM customers
INNER JOIN orders USING (customerNumber)
INNER JOIN orderdetails USING (ordernumber)
INNER JOIN employees ON employeeNumber = salesRepEmployeeNumber
INNER JOIN offices USING (officeCode)
GROUP BY officeCode
ORDER BY sales DESC;
```

Mihin kaupunkeihin huippumyyjät myyvät eniten? Kun siis tiedämme ensin TOP10 huippumyyjää niin mihin kaupunkeihin he pääasiassa myyvät.

```sql
SELECT c.city, 
       Sum(o2.quantityordered * o2.priceeach) sales 
FROM   (SELECT salesrepemployeenumber, 
               Sum(quantityordered * priceeach) sales 
        FROM   customers 
               INNER JOIN orders USING (customernumber) 
               INNER JOIN orderdetails USING (ordernumber) 
        GROUP  BY salesrepemployeenumber 
        ORDER  BY sales DESC 
        LIMIT  10) salestop10 
       INNER JOIN customers c 
               ON c.salesrepemployeenumber = salestop10.salesrepemployeenumber 
       INNER JOIN orders o1 
               ON o1.customernumber = c.customernumber 
       INNER JOIN orderdetails o2 
               ON o2.ordernumber = o1.ordernumber 
GROUP  BY c.city
ORDER BY city
```


# SQL harjoitukset syksy 2021

Harjoitukset on tehty itsenäiseen harjoitteluun. Tehtäviin on annettu malliksi SQL kyselyjä, jotka antavat halutun vastauksen. Saman vastauksen voi saada aikaiseksi myös eri muotoisilla kyselyillä, joka on ihan oikein. Yhtä tapaa ei aina ole.

Harjoitukset koskevat Sakila -tietokantaa, josta lisätietoa löytyy alla olevasta sivustosta.&#x20;

{% embed url="<https://dev.mysql.com/doc/sakila/en/>" %}

## Yksinkertaiset haut

{% hint style="info" %}
Seuraavat hakukyselyt koostuvat yhden taulun tietojen käytöstä.
{% endhint %}

Hae tietokannasta sen elokuvan tiedot, jonka tunniste on 351.

Hae tietokannasta elokuvan tunniste, nimi, julkaisuvuosi, pituus ja luokitus, jonka tunniste on 633.

Tee edellinen haku uudelleen mutta nimeä uudelleen haettujen tulosten sarakkeiden nimet suomeksi englannin sijaan siten, että tuloksessa lukee **elokuvan tunniste, elokuvan nimi, julkaisuvuosi, pituus, luokitus**.

Hae elokuvat, joiden pituus on yli 60 minuuttia. Näytä vain ensimmäiset 10 tulosta.

Tee edellinen haku uudelleen mutta tarkenna hakuehtoa vielä siten, että etsit vain PG-13 luokituksen saaneita elokuvia.

Hae 15 elokuvaa järjestettynä niiden keston mukaan pisimmästä lyhyimpään.

Hae 10 elokuvaa järjestettynä keston mukaisesti pisimmästä lyhyimpään, jotka kuuluvat PG-13 tai R -luokitukseen.

Tee edellinen haku uudestaan mutta aseta hakuehdoiksi luokitukset G ja NC-17. Toteuta hakuehto käyttäen **IN** operaattoria.

Hae lista kaikista elokuvista, joiden kesto on välillä 40 - 80 minuuttia. Järjestä pituuden mukaan pisimmästä lyhyimpään. (yhteensä tuloksia tulisi olla 253 kpl)

Tee edellinen haku uudelleen mutta aseta hakuehdoksi 30-60 minuuttia. Toteuta hakuehto käyttäen **BETWEEN** operaattoria. (yhteensä tuloksia tulisi olla 104 kpl)

Mikä on kaikkien elokuvien keskimääräinen kesto? Entä lyhimmän elokuvan kesto? Entä pisimmän elokuvan kesto?

Hae uudelleen elokuvien keskimääräinen kesto mutta pyöristä luku kokonaisluvuksi.

Ryhmittele elokuvat luokituksen mukaan, jotta saat selville elokuvien määrän eri luokituksissa.

Tee edellinen haku uudelleen mutta näytä tulokset pienimmästä suurimpaan.

Etsi niiden asiakkaiden tiedot, joiden etunimi alkaa **"carol"**.

Tee edellinen haku uudelleen mutta yhdistä tuloksessa asiakkaan etunimi ja sukunimi yhdeksi sarakkeeksi **"nimi"**.

Etsi niiden asiakkaiden tiedot, joiden sähköpostissa esiintyy merkit **"martin"**.

Etsi niiden elokuvien määrä, joiden kuvauksessa esiintyy sana **"amazing"**.

## Haastavammat haut

{% hint style="info" %}
Seuraavissa hakukyselyissä tarvitaan edellisten kohtien oppeja. Tulosten hakemiseen tarvitaan myös JOIN -operaattorin käyttöä.
{% endhint %}

Selvitä asiakkaan, jonka tunniste on 85, kokonimi, sähköposti ja hänen osoitetiedoissaan oleva kadunnimi.&#x20;

Tee edellinen haku uudelleen mutta lisää vielä tulokseen mukaan asiakkaan postinumero, kaupunki ja maa.

Muuta edellisen haun ehtoja. Tarkenna hakua ja etsi kaikki ne asiakkaat, joiden maa on Saksa (germany).&#x20;


# Vastaukset SQL harjoitukset syksy 2021

## Yksinkertaiset haut

{% hint style="info" %}
Seuraavat hakukyselyt koostuvat yhden taulun tietojen käytöstä.
{% endhint %}

Hae tietokannasta sen elokuvan tiedot, jonka tunniste on 351.

![](/files/-Mj4xPW2TN8e0kWB2U68)

Hae tietokannasta elokuvan tunniste, nimi, julkaisuvuosi, pituus ja luokitus, jonka tunniste on 633.

![](/files/-Mj4xVv-3S4E3EHLHhJ3)

Tee edellinen haku uudelleen mutta nimeä uudelleen haettujen tulosten sarakkeiden nimet suomeksi englannin sijaan siten, että tuloksessa lukee **elokuvan tunniste, elokuvan nimi, julkaisuvuosi, pituus, luokitus**.

![](/files/-Mj4xcxu7bMxbvccDJ_z)

Hae elokuvat, joiden pituus on yli 60 minuuttia. Näytä vain ensimmäiset 10 tulosta.

![](/files/-Mj4xkKIhwFQRn-vRUfO)

Tee edellinen haku uudelleen mutta tarkenna hakuehtoa vielä siten, että etsit vain PG-13 luokituksen saaneita elokuvia.

![](/files/-Mj4xpp-kvxraS_dUsYN)

Hae 15 elokuvaa järjestettynä niiden keston mukaan pisimmästä lyhyimpään.

![](/files/-Mj4xuArsFScwtgOCTDq)

Hae 10 elokuvaa järjestettynä keston mukaisesti pisimmästä lyhyimpään, jotka kuuluvat PG-13 tai R -luokitukseen.

![](/files/-Mj4y-leilQkl3KmY2JY)

Tee edellinen haku uudestaan mutta aseta hakuehdoiksi luokitukset G ja NC-17. Toteuta hakuehto käyttäen **IN** operaattoria.

![](/files/-Mj4y754Sx6iTxeJNEBl)

Hae lista kaikista elokuvista, joiden kesto on välillä 40 - 80 minuuttia. Järjestä pituuden mukaan pisimmästä lyhyimpään. (yhteensä tuloksia tulisi olla 253 kpl)

![](/files/-Mj4yAlcZQ_A_4-YEcHT)

Tee edellinen haku uudelleen mutta aseta hakuehdoksi 30-60 minuuttia. Toteuta hakuehto käyttäen **BETWEEN** operaattoria. (yhteensä tuloksia tulisi olla 104 kpl)

![](/files/-Mj4yFrqTPG1XCgEP_hk)

Mikä on kaikkien elokuvien keskimääräinen kesto? Entä lyhimmän elokuvan kesto? Entä pisimmän elokuvan kesto?

![](/files/-Mj4yJzT5D_CbB2qnAqr)

![](/files/-Mj4yOMTz8OpghgP2u_i)

![](/files/-Mj4yWgVril0xDnFvKdb)

Hae uudelleen elokuvien keskimääräinen kesto mutta pyöristä luku kokonaisluvuksi.

![](/files/-Mj4ydcrKVaIGaj6yl6c)

Ryhmittele elokuvat luokituksen mukaan, jotta saat selville elokuvien määrän eri luokituksissa.

![](/files/-Mj4yhQQirPy-1XkNq2G)

Tee edellinen haku uudelleen mutta näytä tulokset pienimmästä suurimpaan.

![](/files/-Mj4ykOn_5l_Sw4Rodpf)

Etsi niiden asiakkaiden tiedot, joiden etunimi alkaa **"carol"**.

![](/files/-Mj4yoVLokiEERsYNVmk)

Tee edellinen haku uudelleen mutta yhdistä tuloksessa asiakkaan etunimi ja sukunimi yhdeksi sarakkeeksi **"nimi"**.

> *Mallikuvassa nimi -sarake on nimetty väärin sukunimi -sarakkeeksi.*

![](/files/-Mj4yrh3PZSSW_kivpCw)

Etsi niiden asiakkaiden tiedot, joiden sähköpostissa esiintyy merkit **"martin"**.

![](/files/-Mj4yyRH387IxZHBmc1L)

Etsi niiden elokuvien määrä, joiden kuvauksessa esiintyy sana **"amazing"**.

![](/files/-Mj4z2Yx2uVmIdu0tcz0)

## Haastavammat haut

{% hint style="info" %}
Seuraavissa hakukyselyissä tarvitaan edellisten kohtien oppeja. Tulosten hakemiseen tarvitaan myös JOIN -operaattorin käyttöä.
{% endhint %}

Selvitä asiakkaan, jonka tunniste on 85, kokonimi, sähköposti ja hänen osoitetiedoissaan oleva kadunnimi.&#x20;

![](/files/-Mj4z719V7i0dtxg1lEM)

Tee edellinen haku uudelleen mutta lisää vielä tulokseen mukaan asiakkaan postinumero, kaupunki ja maa.

![](/files/-Mj4z9fWIiH-K6ep9Hon)

Muuta edellisen haun ehtoja. Tarkenna hakua ja etsi kaikki ne asiakkaat, joiden maa on Saksa (germany).&#x20;

![](/files/-Mj4zBvTifqBj12-mthI)


# TL;DR

## Mitä on ohjelmistokehityksen ostaminen?

* Maksat asiasta, jota ei voi haistaa, maistaa, kuulla, koskea, tuntea tai nähdä.
* Ohjelmistokehitys terminä käsittää kaikki työtehtävät ohjelman käyttöönottoon ja ylläpitämiseen asti.
* Ostat henkilön osaamista ja kokemusta.
* Lopputuloksena syntyy ohjelman lähdekoodi, jos ei synny niin kyse ei ole ohjelmistokehityksestä.
* Syntynyt lähdekoodi on se juttu, joka mahdollistaa liiketoiminnan. Lähdekoodi kirjoitetaan aina toiselle henkilölle, ei tietokoneelle.
* Lähdekoodi syntyy luovan prosessin lopputuloksena.

![Ohjelmistokehityksen vaiheistaminen](/files/-LmsQ_UxGmzj3kc92tCN)

## Miten ohjelmistokehityksen ostaminen eroaa ns. valmiin verkkopalvelun ostamisesta?

* Valmiilla ohjelmistolla tarkoitan esimerkiksi palveluita, jotka ovat keskittyneet johonkin yrityksen liiketoiminnan alueeseen. (kirjanpito, markkinointi, verkkokauppa, projektinhallinta, työajanseuranta. jne.)
* Valmiin verkkopalvelun alkukustannukset ja käyttö voivat olla alhaisia.
* Valmiin verkkopalvelun ostamisen yhteydessä mieti, onko liiketoimintasi oikeasti niin uniikki vai ei?
* Valmiin verkkopalvelun kohdalla taivuttelet sen toimintojen mukaisesti.
* Valmiin verkkopalvelun kohdalla ylläpito ei ole sinun huolehdittavana.
* Ohjelmistokehityksen ostamisessa puolestaan ei ole tarkoitus tehdä kaikkea itse, voidaan keskittyä yhteen tärkeään osa-alueeseen.
* Valmiin verkkopalvelun ostaminen on kuitenkin hankinta, joten ohjelmistokehityksen kaikista vaiheista jäljelle jää usein käyttöönotto.

## Miten arvioin sijoitukseni kannattavuutta?

* Ohjelma ei tuota arvoa heti vaan alkukustannukset voivat olla suuria. Vertaa tätä ravintolan perustamiseen.
* Arvoa ohjelma voi tuottaa vasta kun pienikin osa siitä on julkaistu. Ennen sitä kaikki tehty on lähinnä arvaus mikä voisi tyydyttää tarpeet mutta arvoa se tuottaa vasta julkaistaessa. **Älä venytä julkaisua.**
* Muista pitää aina tavoitteet kirkkaana. **Tavoite ei saa olla €€**. Tavoitteen pitää olla mitattavissa. Eurot ovat seuraus tavoitteeseen pääsemisestä. Lue aiheesta [Impact Mapping](https://www.impactmapping.org/book.html)
* Laske kuinka nopeasti voit teoriassa saada sijoituksen takaisin (päivässä, viikossa, kuukaudessa, vuodessa)
* Laske minkälaista arvoa ohjelma tuottaa.
* **Älä tee, jos et pysty laskemaan arvoa.**

### Joitakin tavoitteita, joista sitten soveltaa miten niihin päästään.

* Kun ominaisuus X valmistuu, se lisää asiakkaiden kertaostosten loppusumma Y%.
* Kun ominaisuus X valmistuu, se lisää asiakkaiden ostojen toistuvuutta Y%.
* Kun ominaisuus X valmistuu, se lisää asiakkaiden määrää Y%
* Kun ominaisuus X valmistuu, se säästää työtehtävään käytettävästä ajasta 5min joka päivä. (5min x 226 päivää x 5 henkilöä = 94h 10min)

{% hint style="info" %}
Käännä edelliset tavoitteet ympäri eli aloita kysymällä **"Miten?"**
{% endhint %}

![](/files/-LmsPRich0P_kcORthoU)

![](/files/-LmsPn0XxYZF2_FenkjU)

![](/files/-LmsPrW0KcrWtTgGhz7z)

![https://www.impactmapping.org/drawing.html](/files/-LmurUN_dH5vmqPQnKEk)

![](/files/-LmuyhQiivO2ZRjAiaXn)

## Mitä asioita minun tulisi huomioida ennen ohjelmistokehityksen ostamista?

* Varaa riittävästi aikaa. 1 työpäivä vähintään viikossa, mieluiten enemmän joskus.
* Älä arkaile asiasi esille tuomisessa, ei ole suurta pelkoa ideoiden varastamisesta.
* Yritä jäsentää asia ja tavoitteet. Kokeile piirtää oma visiosi ohjelmasta ulkonäöllisesti tai käytettävyyden näkökulmasta.
* Kysy tarjouksia eri lähteistä. Eroja on huomattavasti. Tämä ei tarkoita, että halpa on hyvä.
* Mieti pienin mahdollinen osuus, joka tuo arvoa ja pysy siinä.
* Kustannuksia tulee kun työmäärät ovat useita kuukausia, varmista siis mitä rahalla saa.
* Ohjelman ensimmäinen versio, keneltä tahansa ostettuna, tee se kiinteällä summalla. Tuntihinnalla kustannukset nousevat helposti.
* Muista neuvotteluvara, katso alla oleva kolmio. (usein aika ja raha ovat rajallisia, joten jousta sisällöstä, vain kaksi kulmaa voidaan valita.)
* Älä niinkään peljästy kustannuksia. Yritä saada kuva mitä ne ovat ja tarkista tavoitteesi. Muista, että tämä on sijoitus.
* Älä seuraa isompia. Tee omaa juttuasi.&#x20;
* Ulkoasu maksaa myös.
* Kun palaveeraat niin kysy mukaan ohjelmoija (tai se henkilö, joka oikeasti kirjoittaa lähdekoodin)
* Tutustu aiheeseen. Ohjelmoijat yrittävät opetella puhumaan "asiakasta". Opettele puhumaan "ohjelmoijaa". Viestintä on suuressa osassa, että tavoitteisiin päästään.
* Lue [Getting Real](https://basecamp.com/books/getting-real)
* Lue [Shape up](https://basecamp.com/shapeup)

![](https://upload.wikimedia.org/wikipedia/commons/thumb/8/88/Project-triangle-en.svg/800px-Project-triangle-en.svg.png)

## Esimerkkejä mitä euroilla saa

* **0 - 5 000€** pienet ja keskisuuret verkkosivut, pienen verkkokaupan käyttöönotto. Valmiiden palveluiden vuosikustannukset. Pienet demot tai ideoiden kokeilu. Pienet integraatiotyöt kuten esimerkiksi kahden järjestelmän välinen keskustelu. Verkko- tai luottokorttimaksujen toteuttaminen.
* **5 000€ - 10 000€** Kauniimmat verkkosivut, pienen verkkokaupan käyttöönotto ja räätälöidyt ulkoasut. Valmiiden palveluiden vuosikustannukset. Hyvin mahdollisesti jo pienen räätälöidyn verkkosovelluksen ensimmäinen versio mutta hyvin rajattu.
* **10 000€ - 15 000€** Mahdollisesti pienen verkkopalvelun alkukustannukset, rajatuilla ominaisuuksilla. Erilaiset järjestelmien väliset integraatiotyöt. Pienen mobiilisovellukset toteuttaminen rajatuin ominaisuuksin.
* **15 000€ - 25 000€** Mobiilisovellus, jossa myös verkkopalvelun osuus mukana. Rajattu sellainen ja todennäköisin summa ensimmäisestä versiosta. Usein toteutuksissa tarvitaan muitakin järjestelmiä eli verkkomaksujen käyttöönottoa jne.
* **+25 000€** Puhutaan jo sellaisesta työmäärästä, että tekemistä on paljon ja kustannukset nousevat. Riippuen kustannuksista, voi tarkoittaa 1-6kk työtä eli eroa on paljon. Toimittajia on monenlaisia eri lähtöön.
* Esimerkit on mietitty siitä näkökulmasta, että asiakkaana on jotakin liiketoimintaa harjoittava yritys. Ei niinkään Startup -kuviot. Tottakai samat lait pätevät näissä, että isompaa tuottoa odottaessa, kustannukset ovat suuremmat.


# Toimeksianto 2019/01

Aiheiden opiskeluun suunniteltu toimeksianto. Sisältö vastaa esimerkkiä työelämään tehdystä toimeksiannosta.

{% hint style="warning" %}
***Huom! Opiskelijoille suunnatuissa projekteissa heidän arviointinsa ja palautettavat dokumentit on kuvattu tarkemmin heidän omalla oppimisalustallaan.***
{% endhint %}

## Vaatimukset toimeksiannon ohjelmalle

Ohjelmointikieli on C#.

Ohjelman pitää olla konsolisovellus. Ei tehdä niin sanottua "graafista käyttöliittymää". Konsolisovelluksen käyttöliittymä saa puolestaan olla niin monipuolinen kuin kehitystiimi itse tahtoo.

Ohjelman tulee toiminnaltaan toteuttaa alla olevat minimivaatimukset. Näiden lisäksi kehitystiimillä on mahdollisuus toteuttaa lisäominaisuuksia. Ainoa rajoite on annettu aika, joten projektin palautus ei saa myöhästyä lisäominaisuuksien takia.

Ohjelman ominaisuudet liittyvät erilaisia tuotteita myyvän asiakkaan tilausjärjestelmän toteuttamiseen. Tilausjärjestelmällä tarkoitetaan sellaista ohjelmaa, jolla voidaan luoda tilaus ja käsitellä tilaus asiakkaan tarpeiden mukaan.

Esimerkkinä tilausjärjestelmästä voidaan pitää verkkokauppaa. Verkkokaupassa tuotteen tilaaja voi luoda tilauksen. Tilausjärjestelmän omistaja puolestaan voi käsitellä vastaanotetun tilauksen.

Ennen toimeksiannon aloittamista kannattaa tutustua vanhaan projektitoimeksiantoon, jossa on samankaltaista sisältöä.&#x20;

{% content-ref url="/pages/-LK6cKHCNfhRAW8LCuac" %}
[Projekti 2018/01](/toimeksiannot-2018-01/projekti-2018-01)
{% endcontent-ref %}

**Tilausjärjestelmän minimivaatimukset:**

* Tilausjärjestelmän käyttäjän pitää pystyä luomaan uusi tilaus.
* Tilausjärjestlemän käyttäjän pitää pystyä merkitsemään tilaus käsitellyksi.
* Tilausjärjestlemän käyttäjän pitää pystyä merkitsemään tilaus lähetetyksi.
* Tilausjärjestelmän pitää pystyä listaamaan uudet saapuneet tilaukset.
* Tilausjärjestelmän pitää pystyä listaamaan käsitellyt tilaukset.
* Tilausjärjestlemän pitää pystyä listaamaan lähetetyt tilaukset.

**Tekniset vaatimukset**

* Ohjelmoinnissa pitää olla käytetty olio-ohjelmointiin liittyviä käsitteitä.
* Tilausjärjestelmässä pitää olla jonkinlainen valintarakenne eri toiminnoille.
* Tilausjärjestlemän pitää tallentaa tietoa vähintään tekstitiedostoon tai muulla tavalla, jonka kehitystiimi voi itse valita.
* Kun tilausjärjestelmä aukaistaan uudelleen, sen pitää pystyä säilyttämään tieto entisistä tilauksista, joten tiedot eivät saa hukkua kun ohjelma lopetetaan.

## Kehitystiimin työskentely

Katso alla mainittu sivu, jossa kerrottu käytänteistä ja menetelmistä, joita toimeksiannon aikana harjoitellaan.

{% content-ref url="/pages/-LKBFgkhytEk0K06sZtM" %}
[Käytänteet ja menetelmät](/toimeksiannot-2019-01/projekti-2018-01-kaeytaenteet)
{% endcontent-ref %}

## Tarvittavat ohjelmistot

Alla on kuvattu tarvittavia työkaluja ohjelmia. Mikään ei estä käyttämästä muita vastaavia, esimerkiksi projektissa ei ole väliä mikä Visual Studion versio on käytössä kunhan se on vähintään vuoden 2017 version julkaisu.

Osa työkaluista on voitu määrittää pakollisiksi työskentelyn seuraamista varten, esimerkiksi Gitlab palvelu.

### Palvelut ja ohjelmistot

{% embed url="<https://git-scm.com/>" %}
Versionhallintatyökalu
{% endembed %}

{% embed url="<https://gitlab.com>" %}
Projektinhallintaan sekä versionhallintaan tarkoitettu palvelu
{% endembed %}

### Muut palvelut ja ohjelmistot

{% embed url="<https://visualstudio.microsoft.com/vs/>" %}
C# ohjelman tekemiseen
{% endembed %}


# Käytänteet ja menetelmät

Luvussa on listattu ne käytänteet, joita tulisi hyödyntää toimeksiannon tekemisen aikana.

Tuotteen kehityksen aikana kehitystiimin tulee näyttää osaavansa soveltaa opetettuja käytänteitä ja menetelmiä. Luvussa on kuvattu ne käsitteet, käytänteet, menetelmät ja periaatteet, joita kehitystiimin tulisi noudattaa. Kyseisiä osa-alueita arvioidaan tuotteen kehityksen etenemisen aikana sekä myös lopputulosta arvioidessa.

Menetelmät on pyritty kuvaamaan siinä järjestyksessä kuin ne toistuisi ajallisesti. Tämä on vain tehty sisällön hahmottamista varten mutta todellisuudessa eri menetelmät ja vaiheet voivat tapahtua limittäin. Osa asioista on myös kuvattu vain vinkkeinä ja ohjeistuksina, joita kehitystiimi voi hyödyntää tuotteen kehityksen aikana. Tällaisia asioita voivat olla mm. ajankäyttöön liittyvät tavat.

## Sprintin aikana tapahtuvat tehtävät

Sprintti on termi, joka tulee Agile sanastosta. Alla on lueteltu niitä tehtävänosia, joita tuotteen kehittämisen aikana tulisi noudattaa. Lista on tehty vain tämän tuotteen kehittämistä varten ja on hyvä muistaa, että se ei ole kiveen lyöty ratkaisu.&#x20;

Tarvittaessa kehitystiimi saa muuttaa työskentelytapojaan mutta ne tulee perustella hyvin miksi jokin vaihe jää pois tai mitä uutta on tullut tilalle. Pääsääntönä on, että vähintään seuraavat vaiheet tulisi käydä läpi tuotteen kehittämisen aikana.

Sprintin kestoksi on ennalta määritetty **1 viikko** ellei toisin mainita.

## Määrittely

***Tapahtuu aina joka sprintin alussa.***

Määrittelyssä tarkoitus on määrittää alkavalle sprintille tulevat tehtävät. Määrittelyä tehdään aina sen kautta tulisi ymmärtää syvemmin ratkaistavaa ongelmaa. Tähän osallistuu aina tuotteen omistaja, kehitystiimi sekä tarvittaessa muut asiaakn kuuluvat henkilöt. Tarkoitus ei ole suunnitella kaikkea etukäteen vaan pyritään tekemään suunnitelma 1-2 viikon päähän.

### Käyttäjätarinat

Käytämme käyttäjätarinoihin Role-Feature-Reason tapaista kuvausta. Syvempi kuvaus ei ole tässä kohdin tärkeä vaan yritetään ensin muodostaa ymmärrettävä lause, joka muodostuu mallin mukaisesti.

Usein tarkempi määrittely ja kuvaus voidaan kirjoittaa ennen tarinan toteuttamista tai jopa ennen sitä suunnitteluvaiheessa, jossa mukana on henkilö, joka tuntee tämän tarinan sisällön. Liian tarkkaan ei tarvitse määritellä vaan pystyä tekemään kuvaus, jolla priorisoidaan tarve. Käyttötapauksia voidaan hyödyntää toteuttamisvaiheen alussa ja tehdä tarkempi suunnitelma miten ominaisuudet toimivat.

Muun käytetyn materiaalin lisäksi katso seuraavat linkit.

* ​[User Stories](https://www.agilealliance.org/glossary/user-stories)​
* ​[Advantages of User Stories for Requirements](http://www.mountaingoatsoftware.com/articles/advantages-of-user-stories-for-requirements)​
* ​[Role-Feature-Reason](https://www.agilealliance.org/glossary/role-feature/)​
* [INVEST sääntö](https://www.agilealliance.org/glossary/invest/)

### Käyttötapauskuvaukset

Käyttötapaus on dokumentti mikä voidaan kirjoittaa esimerkiksi käyttäjätarinan perusteella. Huomaa lähteissäkin, että ne pyrkivät kertomaan mikä ero on käyttäjätarinalla ja käyttötapauksella. Lyhyesti, käyttötapaus voidaan nähdä tarkempana määritelmänä miten ohjelma kommunikoi eri osapuolten kanssa ja toteuttaa halutun tavoitteen.

Muun käytetyn materiaalin lisäksi katso seuraavat linkit.

* Kts. User Stories linkki
* ​[Requirements 1010: User Stories vs. Use Cases](http://www.stellman-greene.com/2009/05/03/requirements-101-user-stories-vs-use-cases/)​
* ​[User Stories Versus Use Cases](https://www.scrumalliance.org/community/articles/2015/october/user-stories-vs-use-cases)​
* ​[Basic Use Case template, Alistair Cockburn](http://alistair.cockburn.us/Basic+use+case+template)​

### Tuotteen tehtävälistan määritys

Tuotteen tehtävälista on dokumentti, joka ohjaa kehitystä. Se muuttuu aika ajoin ja pääasiassa tuotteen omistaja huolehtii siitä. Kehitystiimi kuitenkin osallistuu tähän myös tarvittaessa ja varsinkin kun tehtäviä otetaan seuraavaan sykliin.

Muun käytetyn materiaalin lisäksi katso seuraavat linkit.

* ​[Backlog](https://www.agilealliance.org/glossary/backlog/)​
* ​[Product Backlog](http://www.scrumguides.org/scrum-guide.html#artifacts-productbacklog)​
* ​[Grooming Backlog](https://www.agilealliance.org/glossary/backlog-grooming/)​

### Sprintin tehtävälistan määritys

Syklin tehtävälista on dokumentti, johon on valittu ne tehtävät mitkä kehitystiimi "lupaa" tehdä. Tarkoitus on, ettei valita liikaa vaan voidaan melko tarkasti sanoa, että ne toteutuvat. Tehtäviä katsotaan läpi aina syklien lopussa ja siivotaan sekä korjataan olettamuksia.

Muun käytetyn materiaalin lisäksi katso seuraavat linkit.

* ​[Sprint Backlog](http://www.scrumguides.org/scrum-guide.html#artifacts-sprintbacklog)​

## Ohjelmointi

Ohjelmointi on osa työtehtäviä. Joskus sen määrä on suurempi kuin muiden työtehtävien määrä mutta on hetkiä, jolloin sprintti voi sisältää vähän ohjelmointia. Tällöin kyseessä voi olla esimerkiksi enemmänkin tutkiva sprintti, jossa haetaan pohjaa seuraavan sprintin aloittamiseen.

Alla on lueteltu niitä kohtia, joita olisi hyvä ottaa huomioon ohjelmoinnin aikana.

### Versionhallinta

Kts. Versionhallinan perusteet

### TDD (testivetoinen kehitys)

Kts. yksikkötestauksen perusteet

Kts. yksikkötestauksen perusteet

### Dokumentointi

Ohjelmiston tulisi sisältää myös siihen liittyvä dokumentaatio. Välttämättä kaikki dokumentaatio ei kulje lähdekoodin mukana mutta on hyvä kirjoittaa vähintään ylös miten uusi kehittäjä voi päästä alkuun tuotteen kehittämisessä.

## Sprintin lopetus

Lyhyesti tarkoitetaan sitä, että kehitystiimi on lisännyt tuotteeseen ominaisuuksia, jotka tarvittaessa tuotteen omistajan hyväksymisen jälkeen voidaan julkaista. Julkaisu ei ole pakollinen vaan isompi julkaisu voidaan tehdä useammassa syklissä. Tärkeintä on, että tuote on aina julkaisuvalmis tarvittaessa, koska välttämättä kaikkien ominaisuuksien ei tarvitse olla valmiita. Tämä on ketterän ohjelmistokehityksen tavoite. Tehdä vähän, julkaista ja oppia tuotteesta. Tällöin riskit voidaan rajat esimerkiksi 2 viikon jaksoihin kuukausien sijasta.

### Sprintin katselmointi

* ​[Sprint Review](http://www.scrumguides.org/scrum-guide.html#events-review)​

### Tuoteversio (Increment)

* Kts. Scrum guide ja etsi sana increment.

### Sprintin retrospektiivi

* [Sprint Retrospective](http://www.scrumguides.org/scrum-guide.html#events-retro)​

**Tuoteversio (Increment)**

* Kts. Scrum guide ja etsi sana increment.
* ​[Sprint Review](http://www.scrumguides.org/scrum-guide.html#events-review)​
* ​[Sprint Retrospective](http://www.scrumguides.org/scrum-guide.html#events-retro)​

## Sprint 0

Sprint 0 ei ole oikeasti olemassa vaan se voi tapahtua jo ennen tuotekehityksen alkua, jolloin varsinaisia kehityskohteita ei ole vielä oikein määritetty. Toisinaan kyseinen vaihe voi olla myös otettu osaksi tuotteen kehitystä. Sprint 0 tarkoittaa usein seuraavia toimenpiteitä, jotta kehitystyö voidaan aloittaa.

* Valmistellaan työasemat
* Valmistellaan yhteisiä työtapoja
* Valmistellaan versionhallintaan liittyvät asiat kuten esimerkiksi palvelujen käyttöönotto
* Valmistellaan tarvittavat ohjelmistot ja muut tekniset asiat

Tavoite on vain tehdä ne toimenpiteet, että voidaan aloittaa tuotteen kehitys. Ylläoleville kohdilla pääsee alkuun mutta se voi sisältää myös paljon muita asioita riippuen kehitettävästä tuotteesta ja kehitystiimistä.

## Muut käsitteet

Muita hyödyllisiä tapoja, menetelmiä tai käsitteitä, jotka auttavat työskentelyssä sekä keskittymisessä. Mainitut asiat on hyvä tuntea, koska niillä on aina oma paikkansa ja kun opit esimerkiksi hallitsemaan omaa ajankäyttöäsi, sillä on suuri vaikutus työskentelyn laatuun.

### Pomodoro

Ajankäyttöä parantava tekniikka. Suosittelen kokeilemaan ja ottamaan käyttöön omaan tekemiseen. Lyhyen opettelun ja tutustumisen jälkeen huomaat paljon paremmin keskittyväsi työskentelyyn ja et häiriinny keskeytyksistä.

{% embed url="<https://en.wikipedia.org/wiki/Pomodoro_Technique>" %}
Wikipedian artikkeli aiheesta
{% endembed %}

{% embed url="<https://pomodoro-tracker.com/>" %}
Pomodoro ajastin
{% endembed %}

### SOLID -periaatteet

SOLID on akronyymi viidelle tekniikalle, joiden avulla voit kirjoittaa laadullisempaa lähdekoodia. Kyseinen aihe ei liity projektin suorittamiseen mutta on isossa osassa aidoissa asiakasprojekteissa. Hyvä lähtökohta ohjelmoijille, jotka haluavat kehittyä kirjoittamaan laadukkaampaa lähdekoodia. Kyseiset tekniikat ovat vain yksi monista taidoista, joiden kautta taidot kehittyvät.

{% embed url="<https://en.wikipedia.org/wiki/SOLID>" %}
Yleinen kuvaus tekniikoista.
{% endembed %}

{% embed url="<https://www.codeproject.com/Articles/703634/SOLID-architecture-principles-using-simple-Csharp>" %}
Esimerkkejä C# ohjelmointikielellä.
{% endembed %}

{% embed url="<https://www.youtube.com/watch?v=TMuno5RZNeE>" %}
Robert C. Martinin luento SOLID säännöistä. Henkilö on nämä tekniikat alunperin kerännyt yhteen.
{% endembed %}

{% embed url="<https://williamdurand.fr/2013/07/30/from-stupid-to-solid-code/>" %}
SOLID sääntöjä esittelevä artikkeli.
{% endembed %}

<br>

<br>

<br>


# Konsoliohjelman refaktorointia

## Katso videosarja konsoliohjelman rakenteesta

Videoissa käydään läpi esimerkki miten Switch-Case rakennetta voidaan muuttaa käyttäen olioita ja listoja hyödyksi. Lisäksi puhutaan yleisesti luokkien käytöstä ja muusta hyödyllisestä.

Video tehty perjantain 15.2 huomioiden perusteella mitenkä ryhmät ovat lähestyneet ohjelmointia. Vinkkejä siis paljon, joten kannattaa katsoa läpi.

Linkki koodeihin: <https://github.com/nyluntu/projekti-2019-01-esimerkki>

Muut linkit:

* <https://docs.microsoft.com/en-us/dotnet/csharp/how-to/concatenate-multiple-strings>

{% embed url="<https://www.youtube.com/playlist?list=PL3iay_FdAzV_zYBOdDv1zqLqkuRXCu5Bo>" %}


# Harjoitustyön sisältö

## Harjoitustyön toimeksianto

**Lue** [**harjoitustyön toimeksianto täältä**](/scrum-harjoitustyoe-2020-01/harjoitustyoe-matkalasku)

Sen jälkeen tutustu alla olevaan ohjeistukseen mitä sinun tulee tehdä.

## Huomiot harjoitustyön tekemisessä

Harjoitustyön avulla on tarkoitus näyttää opittua osaamista sekä myös syventää sitä. Aikaa on rajoitetusta käytössä ja **tavoitteena ei ole suoriutua kaikista** toimeksiannon vaatimuksista.

Tekemisen aikana **sinun tulee priorisoida työntekoasi**. Kuten työelämässä, aina ei ole mahdollista saada kaikkia ominaisuuksia valmiiksi annetussa ajassa. Priorisointi tapahtuu SCRUM mallisesti käyttäen tuotteen- ja sprintin kehitysjonoa.

Kun olet saanut **kehitysjonon (tehtävälista)** valmiiksi, priosioi siis tärkeimmät ominaisuudet ensimmäiseksi ja mieti aina mitä voit saada yhdessä sprintissä aikaiseksi.

**Sprintin tavoitteita pohtiessa,** mieti mikä olisi pienin mahdollinen asia, jonka voit saada valmiiksi ja esitellä asiakkaalle. Sen ei tarvitse olla aina täydellinen vaan tarkoitus on oppia näyttämään myös lyhyet edistykset.

## Harjoitustyön aihealueet&#x20;

[**Projektinhallinta (SCRUM)**](https://www.scrumguides.org/scrum-guide.html)

SRUM soveltamisessa keskitytään toimintamalliin kuinka harjoitustyön tavoitteet ja tehtävät suunnitellaan.

**Lataa suomenkielinen** versio SCRUM oppaasta täältä: [SCRUM opas suomeksi](https://www.scrumguides.org/docs/scrumguide/v2017/2017-Scrum-Guide-Finnish.pdf).

[**Versionhallinta**](/versionhallinta/opas-gitin-perusteisiin)

Versionhallinnan käyttöä hyödynnetään lopullisen harjoitustyön palauttamisessa sekä myös ohjelman kehityksen aikana.

[**Yksikkötestaus**](/yksikkoetestaus/ohjelmistotestauksen-periaateet)

Yksikkötestien käytössä keskitytään niiden soveltamiseen harjoitustyössä.

## Harjoitustyön palautettavat tuotokset

Ohjaaja tarkistaa seuraavat osa-alueet arvioinnin yhteydessä.

**Githubissa oltava:**

* **README -tiedosto**, jossa tekijöiden nimet ja lyhyt kuvaus ohjelman tarkoituksesta. Lisäksi voit lisätä kaiken oleellisen tiedon mikä auttaa ohjaajaa tarkistamisen yhteydessä. (README tiedosto näkyy oikein tehty Githubin repositoryn etusivulla, esimerkki <https://github.com/nyluntu/hacksummit-forecast>)
* **Tuotteen kehitysjono** (Github Issues on hyvä vaihtoehto)
* **Sprinttien kehitysjonot** (Github Issues ominaisuudella voi vaikka merkitä sprintin tai vaihtoehtoisesti käyttää Projects välilehteä)
* **Ohjelman lähdekoodit** (Kerro README tiedostossa mistä löytää harjoitustyön, jos Github repository sisältää useita eri harjoituksia)

**Ohjelman sisällön osalta ohjaaja tarkastaa:**&#x20;

* Ohjelman toimivuutta.
* Versionhallinnan käyttöä tekemisen aikana.
* Yksikkötestien soveltamista ohjelman tekemisen aikana.

**Lyhyt video (Max 10min),** jossa näytät harjoitustyön aikana syntyneen lopputyön tilanteen. Lisää linkki README tiedostoon, josta videon voi katsoa.

Tuo esille seuraavia asioita:

* Missä onnistuit?
* Mikä oli haastavinta?
* Miten jatkaisit nykyisestä pisteestä ohjelman tekoa, jos käytössä olisi enemmän aikaa?
* Saitko hyödynnettyä testejä ohjelman teossa? Jos kyllä niin miten?

Kuvaruutuvideon tekotavalla ei ole väliä. Jos et tiedä mistä lähteä liikkeelle niin ilmainen versio [Screencast O Matic-ohjelmasta](https://screencast-o-matic.com/) on ihan pätevä.

Videon voit jakaa Onedriven, Dropboxin, Google Driven tai muun vastaavan avulla. Käytä haluamaasi ohjelmaa.

##


# Harjoitustyö: Matkalasku

Harjoitustyö ohjelmistokehityksen taitojen syventämiseen.

## Matkalasku

Kirjanpitäjänä (jäljempänä *Asiakas*) toimiva henkilö laskee usealle yritykselle heidän työntekijöiden matkakorvauksia. Työ on alkanut käymään toistuvaksi puurtamiseksi ja asiakas on miettinyt matkalaskujen hoitamista sähköisesti. Ensimmäiseksi asiakas haluaisi päästä kokeilemaan matkalaskujen luomiseen luotua ohjelmaa. Asiakas on antanut seuraavat lähtötiedot ohjelman ensimmäisistä vaatimuksista.

**Matkalaskun sisältö on seuraavanlainen:**

* Matkan lähtö- ja paluuaika.
* Matkan tarkoitus ja lisätiedot.
* Matkakorvauksen saaja.
* Ajankohta, jolloin matkalasku on luotu.
* Reitin kuvaus ja välimatka (km)
* Matkustajien lukumäärä.

**Annettujen tietojen perusteella ohjelman tulisi laskea:**

* Kilometrikorvaus auton käytöstä (<https://www.veronmaksajat.fi/Palkka-ja-elake/Kilometrikorvaukset/kilometrikorvaukset-2020/#3c29c31d>)
* Kilometrikorvauksesta tulisi nähdä sen erittely eli mistä kokonaiskorvaus muodostuu. (kilometrit, henkilöiden lkm., laskemiseen käytetty korvauksen määrä per kilometri)
* Päivärahat matkan keston perusteella. (<https://www.veronmaksajat.fi/Palkka-ja-elake/Paivarahat/kotimaan-paivarahat-2020/#3c29c31d>)
* Päivärahasta tulee nähdä määrä, yksikköhinta ja päivärahojen kokonaiskorvaus.
* Lopuksi ohjelman tulee laskea edellisten tietojen pohjalta kokonaiskorvaus.&#x20;

Asiakas on vaatimaton ensimmäisen version suhteen kunhan hän pääsee kokeilemaan vain ideaansa.

**Jotta ohjelma olisi käyttökelpoinen**, tulisi sen myös tallentaa muodostetut matkalaskut. Ohjelman avulla voidaan siis tarkastella jo muodostettuja matkalaskuja.

**Ohjelman ei tarvitse tukea** useiden eri korvaustyyppien laskemista vaan riittää, että puhutaan aluksi oman auton käytöstä ja päivärahoista.&#x20;

Malli matkalaskun sisällöstä, jonka asiakas on antanut vaatimusten tueksi.

![Esimerkki matkalaskusta](/files/-M-edfYxodYYyNHUY0Jh)

## Ohjelman toimintojen lisätoiveet

* Matkalaskun laskemiseen käytettyjä korvausmääriä voi vaihtaa.
* Matkalaskuun voi merkitä myös auton lisäksi muita kulkuneuvoja.
* Matkalaskuista saisi yhden yhteenvedon kaikista luoduista matkalaskuista.
* Matkalaskun voi merkitä **Maksetuksi** -tilaan.
* Matkalaskuja voi luoda usealle eri henkilöille.

## Harjoitustyön rajaukset

Ohjelman pitää olla konsoliohjelma (esimerkki alla mikä on konsoliohjelma).

Ohjelmointikielenä pitää olla C#.

Harjoitustyössä ei tarvitse tulostaa laskun kuvaa vaan riittää, että konsoliohjelmasta näkee kaikki tiedot.

![Esimerkki konsoliohjelmasta](/files/-LnakB39ae-U1wSWx-hM)

## Vinkkejä

Lyhyt soittolista, jossa tehdään pieni ohjelma missä hyödynnetään tekstitiedostoja tallennusmekanismina. Videolla puhutaan myös Luokkien ja Listojen käytöstä, jotka ovat osa olio-ohjelmoinnin perusrakenteita.

{% embed url="<https://www.youtube.com/playlist?list=PL3iay_FdAzV_EDcg7lLR1iJgZf6ObTsfE>" %}

{% embed url="<https://www.youtube.com/playlist?list=PL3iay_FdAzV_7GzGYkoO1msZPSLl1vIaz>" %}

{% embed url="<https://github.com/hamk-ohjelmointi-intip19x6/hamk-development-team-00/issues>" %}
Esimerkki Githubin Issues listan käytöstä.
{% endembed %}

{% embed url="<https://www.mountaingoatsoftware.com/agile/user-stories>" %}


# Toimeksianto 2019/02

Toimeksiannon kuvaus syksyn opetusta varten.

{% hint style="warning" %}
**Huom!** Opiskelijoille suunnatuissa projekteissa heidän arviointinsa ja palautettavat dokumentit on kuvattu tarkemmin heidän omalla oppimisalustallaan.
{% endhint %}

## Tekniset rajaukset toimeksiannon ohjelmalle <a href="#vaatimukset-toimeksiannon-ohjelmalle" id="vaatimukset-toimeksiannon-ohjelmalle"></a>

* Ohjelmointikielenä C#.
* Ohjelmoinnissa pitää olla sovellettu olio-ohjelmointiin liittyviä käsitteitä, koska näitä on opetettu toisessa osuudessa.
* Ohjelma on ns. konsolisovellus.
* Esimerkkejä alapuolella. Käyttöliittymän toteuttaminen tällaiselle ohjelmalle on vapaasti ryhmän päätettävissä miten sen haluaa toimivan.
* Ohjelman tulee tallentaa ja lukea tietoa vähintään tekstitiedostosta. Muut tallennustavat ryhmän päätettävissä taitotasoon nähden.
* Kun tilausjärjestelmä aukaistaan uudelleen, sen pitää pystyä säilyttämään tieto entisistä tilauksista, joten tiedot eivät saa hukkua kun ohjelma lopetetaan.

![Esimerkki: Käyttäjän valinta](/files/-LnakB39ae-U1wSWx-hM)

![Esimerkki: Toimintojen valinta](/files/-LnakFfrH6gZtF0c1bRT)

![Esimerkki: Tuotelista](/files/-LnakIlx2YMv9Sl-ZKUB)

## Vähimmäisvaatimukset ominaisuuksille

Ohjelman tulee toiminnaltaan toteuttaa alla olevat vähimmäisvaatimukset. Näiden lisäksi kehitystiimillä on mahdollisuus toteuttaa lisäominaisuuksia. Ainoa rajoite on annettu aika, joten projektin palautus ei saa myöhästyä lisäominaisuuksien takia. **Kehitystiimin tulee siis priorisoida tavoitteensa.**

Ohjelman ominaisuudet liittyvät erilaisia tuotteita myyvän asiakkaan tilausjärjestelmän toteuttamiseen. Tilausjärjestelmällä tarkoitetaan sellaista ohjelmaa, jolla voidaan luoda tilaus ja käsitellä tilaus asiakkaan tarpeiden mukaan.

Esimerkkinä tilausjärjestelmästä voidaan pitää verkkokauppaa. Verkkokaupassa tuotteen tilaaja voi luoda tilauksen. Tilausjärjestelmän omistaja puolestaan voi käsitellä vastaanotetun tilauksen.

Ennen toimeksiannon aloittamista kannattaa tutustua vanhaan projektitoimeksiantoon, jossa on samankaltaista sisältöä.

**Tilausjärjestelmän minimivaatimukset:**

* Tilausjärjestelmän käyttäjän pitää pystyä luomaan uusi tilaus.
* Tilausjärjestlemän käyttäjän pitää pystyä merkitsemään tilaus käsitellyksi.
* Tilausjärjestlemän käyttäjän pitää pystyä merkitsemään tilaus lähetetyksi.
* Tilausjärjestelmän pitää pystyä listaamaan uudet saapuneet tilaukset.
* Tilausjärjestelmän pitää pystyä listaamaan käsitellyt tilaukset.
* Tilausjärjestlemän pitää pystyä listaamaan lähetetyt tilaukset.

## Kehitystiimin työskentely <a href="#kehitystiimin-tyoeskentely" id="kehitystiimin-tyoeskentely"></a>

Toimeksiannon aikana on tarkoitus oppia myös työskentelytavoista. Kyseisiä asioita otetaan esille lähituntien yhteydessä sekä ryhmiä ohjattaessa. Pääasiassa käsittelemme seuraavia asioita: [Agile esimerkki](/ketterae-ohjelmistokehitys/agile-esimerkki-sykli)

## Palvelut ja ohjelmistot <a href="#tarvittavat-ohjelmistot" id="tarvittavat-ohjelmistot"></a>

{% embed url="<https://github.com/>" %}

​


# Projekti 2018/01

Lukuun on luotu alustava kuvaus toteutettavasta ohjelmasta. Toimeksianto on harjoitusprojekti, johon sisältyy ajankohtaisista asiakasprojekteista poimittuja tilanteita.

{% hint style="warning" %}
**Projektin toimeksianto on seuraava**

Kehitystiimin tulee lukea projektin kuvaus ja asiakkaan tarpeet läpi. Projektia on aloitettu jo työstämään yhdessä, jotta sen konteksti olisi tutumpi. Kun kehitystiimi aloittaa ohjelman jatkokehittämisen itsenäisesti, tulee heidän omatoimisesti näyttää, että osaavat soveltaa opetettuja ohjelmistokehitykseen liittyviä menetelmiä ja käytänteitä.

Kehitystiimi itse päättää projektin suunnan ja heillä on sitä varten olemassa ohjaaja, joka arvioi lopputuloksen. Projektissa pitää esiintyä kehitystiimin oma syventyminen ongelmaan, joten ennalta määritettyä lopputulosta ei ole. Omalla aktiivisuudellaan ja työskentelyllään kehitystiimi näyttää osaavansa asiat.

Ohjaaja arvioi projektin aikana syntyneitä dokumentteja mihin sisältyy mm. tehtävälista, käyttäjätarinat, käyttötapauskuvaukset, ohjelmakoodi, ohjelman valmis versio. Tämän lisäksi arvioihin voi olla muita vaikuttavia tekijöitä mutta nämä asiat on kerrottu selkeästi kehitystiimille.

***Huom! Opiskelijoille suunnatuissa projekteissa heidän arviointinsa ja palautettavat dokumentit on kuvattu tarkemmin heidän omalla oppimisalustallaan.***
{% endhint %}

## Tuotteen nimi / Projektin nimi

Verkkokaupan tilauksen vastaanottaminen ja käsittely

## Asiakkaan kuvaus tarpeista

Asiakkaalla on autojen varaosien myyntiin keskittynyt liiketoiminta. Nykyinen liiketoiminta tapahtuu pääsääntöisesti myymälöiden kautta yksityisasiakkaille. Liiketoiminnan kasvattamiseksi asiakas on päättänyt kasvattaa yrityksille ja muille yhteistyökumppaneille suunnattua myyntiä.

Yrityksille suunnattuja palveluita on olemassa mutta tilaukset on otettu vastaan puhelimitse tai sähköpostitse. Tilauksien määrän kasvattamiseksi asiakas tarvitsee pienen ohjelmiston, joka vastaanottaa tilauksia ja käsittelee yleisimmät tilaukseen liittyvät vaiheet.

Asiakas on ajatellut työkalun olevan eräänlainen verkkokauppa, joka on suunnattu vain yritysasiakkaille. Tilausta tehdessä pitäisi olla mahdollista kertoa ostajan yhteystiedot tai muulla tapaa tunnistaa kuka tilauksen on tehnyt. Yritysasiakkaille on mahdollista olla tehty erilaisia sopimuksia, jotka määrittävät ostoksen kokonaissumman.

Tilaukseen tulisi pystyä valitsemaan ennalta määritettyjä tuotteita ja tilauksen vahvistamisen jälkeen, asiakkaalla pitää olla tapa nähdä uudet tulleet tilaukset sekä pystyä merkitsemään ne lähetetyksi ostajalle.

Koska kyse on autojen varaosista, ei asiakkaalla aina ole kyseisiä tuotteita varastossa ja hän joutuu tehdä siitä erillisen toimitus/tilauspyynnön maahantuojille. Tällöin tilausta tehdessä ostajalle pitäisi ilmoittaa, että varaosien toimituksessa voi kestää normaalia pidempään.

## Tuotteen tehtävälista

Tuotteen tehtävälista koostuu pääosin alla mainituista kokonaisuuksista, joita on tarkennettu myöhemmin käyttäjätarinoiden ja käyttötapausten avulla.

* Tuotteiden lisääminen ja hallinta
* Tilauksen luominen, hyväksyntä ja hallinta
* Asiakkaan lisääminen ja hallinta
* Asiakkaan erikoishintojen lisääminen ja hallinta
* Varaston hallinta tilausten perusteella

### Käyttäjätarinat

Eri rooleille tai käyttäjäryhmille on tehty oma listauksensa heille tarkoitetuista ominaisuuksista. Listaukset eivät ole täydellisiä tai niihin ei ole otettu mukaan kaikkia ominaisuuksia. Tarkoituksena on pitää listat esimerkkien vuoksi yksinkertaisina.

#### Yritysasiakkaan käyttäjätarinat

| As a/an          | I want to...                                                                                                          | so that                                                     |
| ---------------- | --------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| Yritysasiakkaana | tahdon pystyä poimimaan tilaukseen haluamani tuotteita                                                                | voin luoda haluamani tilauksen.                             |
| Yritysasiakkaana | tahdon pystyä poistamaan tilauksestani tuotteita ennen sen vahvistamista                                              | voin välttyä tilaamasta varaosia, joita en tarvitse.        |
| Yritysasiakkaana | tahdon nähdä tilauksen yhteenvedon yhteydessä maininnan toimitusajasta tuotteiden osalta joita ei ole heti saatavilla | voin tietää tulevatko kaikki tuotteet samassa lähetyksessä. |
| Yritysasiakkaana | tahdon saada tilauksesta tilausvahvistuksen                                                                           |                                                             |
| Yritysasiakkaana | tahdon saada tilauksesta lähetysvahvistuksen                                                                          | voin tietää milloin toimitus on lähetetty toimittajalta.    |
| Yritysasiakkaana | tahdon nähdä tilauksen kokonaissumman ennen sen vahvistamista                                                         |                                                             |

#### Verkkokaupan ylläpitäjän (toimittaja eli tässä varsinainen projektin asiakas) käyttäjätarinat

| As a         | I want to...                                                                                | so that                                                              |
| ------------ | ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| Toimittajana | tahdon nähdä listan uusista käsittelemättömistä tilauksista                                 | voin tietää mitkä tilaukset minun tulisi käsitellä ja lähettää.      |
| Toimittajana | tahdon saada tilauksesta keräilylistan                                                      | voin pakata yhden tilauksen tuotteet.                                |
| Toimittajana | tahdon pystyä vaihtamaan tilattujen tuotteiden yksikkömääriä                                | voin korjata inventaarivirheistä johtuvat virhetilanteet.            |
| Toimittajana | tahdon nähdä listan kaikista tehdyistä tilauksista                                          | voin tarkistaa tilauksien tiedot myöhemmin sen lähettämisen jälkeen. |
| Toimittajana | tahdon pystyä muodostamaan ja lähettämään laskun asiakkaalle tilauksen lähettämisen jälkeen | asiakkailtani perittävät myyntisaamiset tulevat hoidettua nopeammin. |
| Toimittajana | tahdon saada yhteenvedon varastosta loppuneista tuotteista                                  | osaan tilata tuotteita lisää varastooni jo valmiiksi.                |

### Käyttötapaukset

Käyttötapauksien kohdalla yksi käyttäjätarina pilkotaan tarkemmin vaiheisiin ja tapahtumiin mistä se koostuu. Käyttötapauksia ei ole kirjoitettu kaikista käyttätarinoista valmiiksi vaan niitä luodaan sen mukaan kuinka projekti etenee.

## Tarvittavat ohjelmistot

Alla on kuvattu tarvittavia työkaluja ohjelmia. Mikään ei estä käyttämästä muita vastaavia, esimerkiksi projektissa ei ole väliä mikä Visual Studion versio on käytössä kunhan se on vähintään vuoden 2017 version julkaisu.

Osa työkaluista on voitu määrittää pakollisiksi työskentelyn seuraamista varten, esimerkiksi Gitlab palvelu.

### Pakolliset palvelut ja ohjelmistot

{% embed url="<https://git-scm.com/>" %}
Versionhallintatyökalu
{% endembed %}

{% embed url="<https://gitlab.com>" %}
Projektinhallintaan sekä versionhallintaan tarkoitettu palvelu
{% endembed %}

### Muut palvelut ja ohjelmistot

{% embed url="<https://visualstudio.microsoft.com/vs/>" %}
C# ohjelman tekemiseen
{% endembed %}


# Projekti 2018/01 Perjantaille 14.9

Kuvattu tehtävä tunneille, josta lähdetään liikkeelle.

## Ominaisuus

Verkkokaupasta tehdyn tilauksen vastaanottaminen

## Käyttäjätarina(t)

Alla on kopioitu alkuperäisestä toimeksiannosta käyttäjätarinat. Nämä on määritetty tässä kohdin tärkeimmiksi, jotta projektissa päästään alkuun ja voidaan kokeilla ensimmäistä versiota.

Käyttäjätarinoita oli valittujen lisäksi monia muita, jotka "rikastavat" ohjelman ominaisuuksia. Näitä ei kuitenkaan koettu vielä tärkeäksi vaan voidaan sinnitellä ilman niitä.&#x20;

Kokonaisuutena ominaisuus ei välttämättä ole valmis valittujen käyttäjätarinoiden jälkeen mutta ohjelman julkaisu on asiakkaan päätettävissä. Ensimmäisessä versiossa on tarkoitus kokeilla vain tilauksen tekeminen kokonaisuutena ja seuraavissa vaiheissa lisätä ominaisuuksia.

Käyttäjätarinoiden kulkua on tarkennettu alla käyttötapausten avulla.

| Tunniste  | As a/an          | I want to...                                                | so that                                                         |
| --------- | ---------------- | ----------------------------------------------------------- | --------------------------------------------------------------- |
| Tarina 01 | Yritysasiakkaana | tahdon pystyä poimimaan tilaukseen haluamani tuotteita      | voin luoda haluamani tilauksen.                                 |
| Tarina 02 | Toimittajana     | tahdon nähdä listan uusista käsittelemättömistä tilauksista | voin tietää mitkä tilaukset minun tulisi käsitellä ja lähettää. |

## Käyttötapauskuvaukset

### Tarina 01

Yritysasiakkaana (jäljempänä asiakas) tahdon pystyä poimimaan tilaukseen haluamani tuotteita, jotta voin luoda haluamani tilauksen

Alla kuvattu eri tapaukset käyttäjätarinaan liittyen.

{% tabs %}
{% tab title="TAPAUS 01" %}

#### TAPAUS 01

**Tavoite**

Verkkokauppaohjelmistoa käyttävä asiakas saa lisättyä vahvistamattomaan tilaukseena tuotteita.

**Esiehdot**

* Ohjelmassa on oltava saatavilla olevia tuotteita, joita asiakas voi valita.

**Onnistunut lopputulos**

Asiakas näkee tilauksessaan tuotteen, jonka hän on toiminnon aikana valinnut.

**Virheellinen lopputulos**

Asiakkaan valitsema tuote ei näytä tilauksessa. Ohjelma ei kaadu mikäli virhe sattuu vaan ilmoittaa virheellisestä toimenpiteestä.

**Kuvaus käyttötapauksesta**

1. Asiakas saa listan valittavista tuotteista.
2. Asiakas valitsee tuotteen listalta ja hyväksyy sen tilaukseen.
3. (järjestelmä lisää tässä kohdin tuotteen tilaukseen)
4. (järjestelmä ilmoittaa asiakkaalle, että tuote on lisätty tilaukseen)

**Kuvaus virheellisestä käyttötapauksesta**

**Kohdassa 3** tuotteen lisäys tilaukseen ei onnistu. **Kohdan 4** sijaan ohjelman tulisi ilmoittaa asiakkaalle, että tuotetta ei voitu lisätä tilaukseen.
{% endtab %}

{% tab title="TAPAUS 02" %}

#### TAPAUS 02

**Tavoite**

Verkkokauppaohjelmistoa käyttävä asiakas saa vahvistettua tilauksen.

**Esiehdot**

* Ohjelmassa on oltava saatavilla olevia tuotteita, joita asiakas voi valita.
* Asiakkaan on täytynyt lisätä tilaukseen vähintään yksi tuote.

**Onnistunut lopputulos**

Asiakas näkee ohjelmassa ilmoituksen onnistuneesta tilauksen luomisesta.

**Virheellinen lopputulos**

Järjestelmä ilmoittaa, ettei tilausta saada luotua. Tilaus ei jää talteen.

**Kuvaus käyttötapauksesta**

1. Asiakas valitsee vahvistettavan tilauksen.
2. Asiakas täyttää yhteystietonsa.
3. Asiakas näkee tilauksesta yhteenvedon.
   1. Katso välilehti (**tilauksen yhteenveto**)
4. Asiakas vahvistaa tilauksen.
5. (järjestelmä käsittelee tilauksen)
6. (järjestelmä ilmoittaa asiakkaalle onnistuneen tilauksen luomisesta)

**Kuvaus virheellisestä käyttötapauksesta**

**Kohdassa 5** tilauksen vahvistaminen ei onnistu jostakin seuraavista syistä ja ilmoittaa siitä asiakkaalle:

* Tilauksessa ei ole tuotteita.
* Asiakas ei ole antanut yhteystietoja, kaikki kentät pakollisia.
  {% endtab %}

{% tab title="Tilauksen yhteenveto" %}

* Tuotteet erotettu tuoteriveihin.
* Tuotteiden määrät kerrottu tuoteriveittäin sekä yhteensä.
* Tuotteiden hinnat kerrottu tuoteriveittäin sekä tilauksen kokonaissumma.
* Hinnoista kerrottu kaksi eri hintaa, arvonlisäveron kanssa (24%) sekä ilman arvonlisäveroa (0%)
* Asiakkaan yhteystietoihin kuuluu:
  * Etunimi, Sukunimi, Toimitusosoite, y-tunnus, puhelinnumero, sähköposti.
    {% endtab %}
    {% endtabs %}

### Tarina 02

Toimittajana tahdon nähdä listan uusista käsittelemättömistä tilauksista, jotta voin tietää mitkä tilauksen minun tulisi käsitellä ja lähettää.

Alla kuvattu eri tapaukset käyttäjätarinaan liittyen.

{% tabs %}
{% tab title="TAPAUS 01" %}
**TAPAUS 01**

**Tavoite**

Saapuneiden tilauksien käsittelijänä minun tulisi pystyä näkemään lista uusista tilauksista.

**Esiehdot**

* Yritysasiakas on tehnyt vähintään yhden onnistuneen tilauksen järjestelmään.

**Onnistunut lopputulos**

Tilauksen käsittelijä näkee listan yritysasiakkaiden tekemistä vahvistetuista tilauksista.

**Virheellinen lopputulos**

Tilauksen käsittelijä ei näe vahvistettuja tilauksia.

**Kuvaus käyttötapauksesta**

1. Tilauksen käsittelijä valitsee "uudet tilaukset"
2. (järjestelmä hakee vahvistetut tilaukset ja näyttää listan tilauksen käsittelijälle)
   1. Katso välilehti (**tilauksien listaus**)

**Kuvaus virheellisestä käyttötapauksesta**

**Kohdassa 2** jos jostain syystä tilauksia ei saada luettua, tulisi ohjelman ilmoittaa siitä tilauksen käsittelijälle sopivalla viestillä.
{% endtab %}

{% tab title="TAPAUS 02" %}
**TAPAUS 02**

**Tavoite**

Saapuneiden tilauksien käsittelijänä minun tulisi pystyä yksittäisen tilauksen yhteenveto.

**Esiehdot**

* Yritysasiakas on tehnyt vähintään yhden onnistuneen tilauksen järjestelmään.

**Onnistunut lopputulos**

Tilauksen käsittelijä näkee saapuneesta tilauksesta yhteenvedon.

**Virheellinen lopputulos**

Tilauksen käsittelijä ei näe tilauksen yhteenvetoa.

**Kuvaus käyttötapauksesta**

1. Tilauksen käsittelijä valitsee saapuneen tilauksen.
2. Tilauksen käsittelijä näkee tilauksesta yhteenvedon.
   1. Katso välilehti edellisestä tarinasta (**tilauksen yhteenveto**)

**Kuvaus virheellisestä käyttötapauksesta**

**Kohdassa 2** jos jostain syystä tilausta ei saada luettua, tulisi järjestelmän ilmoittaa siitä viestillä tilauksen käsittelijälle.
{% endtab %}

{% tab title="Tilauksien listaus" %}
Saapuneiden tilauksien listassa tulisi näkyä seuraavat tiedot.

* Tilauspäivämäärä
* Asiakkaan nimi
* Asiakkaan puhelinnumero
* Tilauksessa olevien tuotteiden kokonaismäärä
* Tilauksen kokonaissumma. (alv24 ja alv0)
  {% endtab %}
  {% endtabs %}

## Tehtävän tavoitteita

{% hint style="warning" %}
Harjoituksessa on rajattu toteutusvaihtoehtoja seuraavasti:

* Käyttöliittymä sovellukselle on konsolipohjainen.&#x20;
* Ohjelmointikieli on C#
* Työkaluna toteutukselle Visual Studio 2017, myös Mac versio käy. Valitse siis sieltä projektiksi Console Project.

Tehtävä tehdään ryhmissä. Ryhmien tulee tehdä tehtävän osia käyttäen versionhallintaa ja Gitlab palvelua.&#x20;

Gitlab palvelussa pyritään pitämään myös projektin etenemiseen liittyvät dokumentit eli käyttäkää issue ja board toimintoja näyttääksenne projektin eri vaiheita ja se etenemistä.

Tehtävää tehdään niin pitkälle kuin mahdollista. Ohjaaja auttaa tunnilla.

Tehtävä toimii projektin aloituksena, joten tehkää jo heti alkuun siten, että ryhmän jäsenet tulevat jatkamaan tämän työn parissa seuraavat viikot. Tehtävää ei tulla aloittamaan uudelleen. Myöhemmin projektin edetessä ryhmä päättää joistakin tulevista tehtävistä mutta tämä lähtökohta pysyy kaikilla samana.
{% endhint %}


# Projekti 2018/01 Käyttötapauksesta työtehtäviin

Esitelty tapa tai enemmän se oma tapa lähteä purkamaan toimeksiantoa pienempiin konkreettisimpiin tehtäväkokonaisuuksiin.

## Valittu käyttäjätarina

**KOPIO** edellisistä esimerkeistä.

Yritysasiakkaana ***(jäljempänä asiakas)*** tahdon pystyä ***poimimaan tilaukseen*** haluamani ***tuotteita,*** jotta voin luoda haluamani tilauksen.

## Tarinan ensimmäinen käyttötapaus

**KOPIO** edellisistä esimerkeistä.

{% tabs %}
{% tab title="TAPAUS 01" %}

#### TAPAUS 01

**Tavoite**

Verkkokauppaohjelmistoa käyttävä ***asiakas*** saa lisättyä ***vahvistamattomaan tilaukseen*** tuotteita.

**Esiehdot**

* Ohjelmassa on oltava ***saatavilla olevia tuotteita***, joita asiakas voi valita.

**Onnistunut lopputulos**

Asiakas näkee tilauksessaan tuotteen, jonka hän on toiminnon aikana valinnut.

**Virheellinen lopputulos**

Asiakkaan valitsema tuote ei näytä tilauksessa. Ohjelma ei kaadu mikäli virhe sattuu vaan ilmoittaa virheellisestä toimenpiteestä.

**Kuvaus käyttötapauksesta**

1. Asiakas saa listan valittavista tuotteista.
2. Asiakas valitsee tuotteen listalta ja hyväksyy sen tilaukseen.
3. (järjestelmä lisää tässä kohdin tuotteen tilaukseen)
4. (järjestelmä ilmoittaa asiakkaalle, että tuote on lisätty tilaukseen)

**Kuvaus virheellisestä käyttötapauksesta**

**Kohdassa 3** tuotteen lisäys tilaukseen ei onnistu. **Kohdan 4** sijaan ohjelman ***tulisi ilmoittaa asiakkaalle, että tuotetta ei voitu lisätä tilaukseen***.
{% endtab %}
{% endtabs %}

## VAIHE 1: Käyttöliittymän luonnokset

Kun asia on vieras ja siitä on saatu kyseltyä kaikki mahdollinen, hyvä tapa lähteä liikkeelle on tehdä käyttöliittymä luonnoksia. Vastataan siis kysymykseen:&#x20;

*Miltä ohjelma tulisi näyttämään ja sen käyttö tuntumaan?*

{% hint style="info" %}
Helpoin tapa on paperi ja kynä, sitten erilaiset luonnosteluohjelmat jne. Mikä vain tuntuu luontevimmalta on aina hyvä lähtökohta. Alla esimerkki tähän harjoitukseen liittyen. Kuvat on tehty yksinkertaisesti tekstieditorilla ja otettu kuvakaappaukset.
{% endhint %}

### Kuvakaappaukset

![Ohjelman ensimmäinen näkymä tässä kohtaa sen historiaa.](/files/-LN4K79ArIKwzLlD9mhr)

![Ohjelman listaus tuotteista kun niitä on vain muutama kappale.](/files/-LN4KJ5w_rHu1UQ98s90)

## VAIHE 2: Ohjelman rakenteen luokkakaavio

{% file src="/files/-LN4Lytz1H-QbdIhQZkO" %}
Ohjelman rakenteen luonnos
{% endfile %}

Liitteesstä ***"Ohjelman rakenteen luonnos"*** on käyty läpi ohjelman rakennetta mitä se voisi olla teknisesti toteutettuna. Kyseessä on vain esimerkki omasta näkemyksestä ja se saa ja voi erota riippuen ohjelmoijasta.

Kaavioon on tuotu mukana olio-ohjelmoinnin piirteitä ja siksi siinä puhutaan luokista ja komponenteista. Kaavion tarkoitus ei ole kertoa miten ohjelmoida vaan taas tuoda erilainen näkökulma asiaan ja löytää lisää kysymyksiä mihin löytää vastaus... eli asioihin joita ei tiedetä.

## VAIHE 3: Analyysin jälkeen listatut työkokonaisuudet

Kun ohjelman rakennnetta ja vaatimuksia on käyty läpi, pitää vielä listata tehtäviä mistä lähdetään liikkeelle. Tässä tehtävät ovat vain listaus niistä asioista, josta ei tiedetä mitään ja ne pitää selvittää ennenkuin kokonaisuus saadaan tehtyä loppuun.

Seuraava kokonaisuus on taas hieman helpompi kun asia on tutumpi ja alun ongelmat ratkaistu.

### Käyttöliittymä

* Miten esitän tietoa käyttöliittymässä?
* Miten käyttöliittymän logiikka tai valintarakenne tulee toimimaan?
* Miten käyttöliittymän valintarakenne päivitetään?
* Miten otan käyttäjän antaman syötteen vastaan käyttöliittymästä?
* Miten määritän ohjelman tekemän toiminnon annetun syötteen perusteella?

### Ohjelman toiminnot

* Käytetäänkö luokkarakenteita vai ei?
* Mitä tietoja tai metodeita Tilaus-luokassa tulisi olla?
* Miten tilauksen luominen toimii kokonaisuudessaan?
* Miten tuotelistaus tulisi toimimaan?
* Onko tuotteet "kovakoodattu" vai luetaanko tiedostosta? (mitkä ovat näiden hyödyt ja haitat?)

### Tiedostojärjestelmä

* Miten tallennan yhden olion/luokan esimerkiksi tiedostoon?
* Käytetäänkö tekstitiedostoja, tietokantaa tai mitä tallennusratkaisua?
* Miten tallennan monimutkaisen olin/luokan esimerkiksi tiedostoon?
* Miten ohjelma lukee tallennetut tiedot kun se niitä tarvitsee?
* Missä tilanteissa ohjelma tallentaa tiedot?

## VAIHE 4: Ohjelmointi

Tässä kohdin on vain aloitettava ohjelmointi. Vasta sitten tiedetään oikeat ongelmakohdat ja puutteet tiedoissa. Sillä ei ole väliä miten tämä tulee tapahtumaan vaan yksi kerrallaan pyritään tekemään työkokonaisuus ja oppia sen kautta.

{% hint style="info" %}
Kun ohjelmoidaan, se ei tarkoita, että kaikki asiat pitää tietää ja osata. Sellaista tilannetta ei olekaan. On paljon tärkeämpää tunnistaa osa-alueet, joista ei tiedä mitään ja mitkä ovat haastavia, koska silloin niitä on tarkoitus osa-alueita on tarkoitus parantaa.
{% endhint %}

## Videot

Soittolista tähän liittyvistä asioista. Esittelee omia ajatuksia miten näihin työtehtäviin on päästy.

{% embed url="<https://www.youtube.com/playlist?list=PL3iay_FdAzV_7GzGYkoO1msZPSLl1vIaz>" %}


# Projekti 2018/01 Ohjelmoinnin aloittaminen

Sisältö tuotettu tukemaan projektin aikana kohdattuja hidasteita. Keskittyy lähinnä ohjelmoinnin käsitteisiin ja perusteisiin. Oletamme, että näitä rakenteita on jo käyty läpi esimerkein.

## Videoita ohjelman rakentamisesta

Soittolista, joka sisältää muutaman videon ohjelman rakenteesta. Videoissa käyty läpi miten yksinkertainen sovellus toimisi aina tiedon tallentamiseen asti. Videoilla esitettyä tapaa voisi sitten toistaa eri ohjelman toiminnoissa.

Lähdekoodit löytyvät alla olevasta liitetiedostosta. Kyseessä on ohjelman viimeinen versio, joten se näyttää erilaiselta kuin alussa.

{% embed url="<https://www.youtube.com/playlist?list=PL3iay_FdAzV_EDcg7lLR1iJgZf6ObTsfE>" %}

{% file src="/files/-LO9Ae4l0wRXUuBZjmAu" %}
Videossa esiintyvän ohjelman lähdekoodit
{% endfile %}

## Konsoliohjelman rakenne ja elinkaari

Ensimmäinen kuva on yksinkertainen esitys siitä miten konsolisovellus toimii ja mikä on sen elinkaari. Ohjelmilla on aina alku- ja lopputila. Sama kaava toistuu puhutaan sitten kokonaisesta ohjelmasta tai ohjelmassa olevista metodeista.

Ohjelma toistaa itseään niin kauan kuin on tarpeen tai ohjelmoija on tahtonut sen tekevän. Aina ohjelman ei tarvitse toistaa itseään vaan se voi toimia myös yksittäisenä kerta-ajona.

Toisessa kuvassa on sama tilanne kuvattu vain lähdekoodia käyttäen ilman toistorakenteita.

Kun ohjelma alkaa, se varaa itselleen käyttöönsä muistia. Määrä riippuu siitä paljonko asioita ohjelma yrittää tehdä ja usein ei harjoitusprojekteissa ole ongelma. On kuitenkin tärkeä ymmärtää, että muistissa olevat asiat ovat käytettävissä vain niin kauan kun ohjelma on käytössä. Pitempiaikaista tiedon tallennusta varten ohjelman pitää huolehtia sen tallentamisesta.

![Yleinen ja yksinkertainen kuva ohjelman rakenteesta.](/files/-LO8KX8O6FGiiiLxqRfM)

<div align="center"><img src="/files/-LO8KcusjkoTo5-HVAnG" alt="Ruutukaappaus konsolisovelluksen projektipohjasta."></div>

## Ohjelmoinnin logiikat ja rakenteet

Alla esimerkki ohjelman rakenteesta, jossa on vain muutamia ohjelmoinnin logiikkaan liittyviä rakenteita. Huomaa, että ohjelmaa toistetaan niin kauan kunnes annetaan syöte "0".

Ohjelmoinnissa on muutamia perusrakenteita, joilla vaikutetaan ohjelman kulkuun ja sen käyttäytymiseen. Ohjelmointikielistä riippumatta nämä ovat seuraavat:

* IF-THEN
* IF-THEN-ELSE
* WHILE
* DO-WHILE
* FOR
* FOREACH (ei kaikissa)

Rakenteiden hallinta on elintärkeää ohjelmoinnin kanssa. Niiden hahmottamista auttavat esimerkiksi vuokaaviot. Jos et tunne miten edellä mainitut ohjausrakenteet vaikuttavat ohjelman toimintaan, ota ensin niistä selvää eri esimerkkien kanssa.

![Esimerkki vuokaavioista.](/files/-LO8PiK8e4rcOvuigH9p)

Toinen tärkeä tunnettava asia on muuttujat ja niiden elinkaari. Ohjelmassa on usein globaaleja ja paikallisia muuttujia. Näiden erot ovat siinä miten ne näkyvät ja vaikuttavat ohjelman eri osissa kun se on päällä.

Alla olevassa esimerkissä `ohje` on staattinen muuttuja. Se on myös määritelty  `Main` ulkopuolella mikä tarkoittaa sitä, että se on käytettävissä `Main` metodin sisällä. Jos muuttuja olisi määritetty metodin sisällä kuten esimerkissä muuttuja `komento`,  niin sitä ei voi käyttää metodin ulkopuolella. Tällaisessa tilanteessa voidaan sanoa, että `ohje` on globaali muuttuja ja `komento` paikallinen muuttuja.

Edellä mainittu tilanne on vain yksi esimerkki ja tilanne voi vaihdella ohjelmointikielen ja tilanteen mukaan. Siksi näihin on tutustuttava aina ohjelmointikielen mukaan. Esimerkiksi voi olla käytössä `global` avainsanoja, mitkä voivat määrittää muuttujille erilaisia ominiasuuksia.

Alla olevassa esimerkissä on huomioitava myös se, että muuttujat ovat olemassa aina koko ohjelman elinkaaren ajan. Tällöin niihin tallennettu tieto pysyy tallessa niin kauan kunnes ne alustetaan uudelleen tai ohjelma loppuu.

{% code title="Paaohjelma\_esimerkki" %}

```csharp
class MainClass
    {
        static string ohje = "0.Lopetus\n1.Tuotteet\n2.Toiminto\n3.Toiminto\n4.Toiminto\n5.Toiminto";

        // Main metodia kutsutaan kun ohjelma käynnistyy. Tämä on ensimmäinen
        // metodi mitä siis ohjelma kutsuu ja josta kaikki alkaa.
        // 
        // "string[] args" tarkoittaa parametreja, jos niitä on annettu ohjelman
        // alkaessa esimerkiksi komentokehotteesta.

        public static void Main(string[] args)
        {
            // Varsinaisen ohjelman suoritus alkaa.

            Console.WriteLine(ohje);
            string komento = Console.ReadLine();
            while (!komento.StartsWith("0", StringComparison.Ordinal))
            {
                switch (komento)
                {
                    case "1":
                        Console.WriteLine("Tuoteet 1" + Environment.NewLine);
                        break;

                    case "2":
                        Console.WriteLine("Tuote 2" + Environment.NewLine);
                        break;
                    case "3":
                        Console.WriteLine("Tuote 3" + Environment.NewLine);
                        break;
                    case "4":
                        Console.WriteLine("Tuote 4" + Environment.NewLine);
                        break;
                    case "5":
                        Console.WriteLine("Tuote 5" + Environment.NewLine);
                        break;
                    default:
                        break;
                }

                Console.WriteLine(ohje);
                komento = Console.ReadLine();

                // Varsinaisen ohjelman suoritus loppuu.
            }
        }
    }
```

{% endcode %}

## Luokat ja niiden käyttö ohjelmassa

Luokat ovat olio-ohjelmoinnin tärkein käsite. Niillä pyritään tekemään kokonaisuuksia, joita ohjelmassa voidaan käyttää. Seuraavaksi on esitelty kaksi eri tapaa miten luokkia voidaan hyödyntää eri tarkoituksessa. Tapoja on muitakin mutta seuraavat ovat  tärkeitä ymmärtää tässä vaiheessa.

### Tiedon kantajat

Tässä kohdin tiedon kantajalla tarkoitetaan sellaista luokkaa, joka vain kuljettaa tietoa mukanaan. Esimerkkinä  alla `Tuote` luokka.

Tällaisen luokan tarkoitus on koostaa yksittäisiä muuttujia yhteen ymmärrettäväksi kokonaisuudeksi. Voidaan esimerkiksi ajatella, että nämä ovat oikean maailman asioita, esineitä jne.

Luokka voi myös osata tehdä omilla tiedoillaan jotain, esimerkiksi laskea sen pohjalta asioita tai muuttaa tietojaan.

{% code title="Tuote.cs" %}

```csharp
public class Tuote {

    // Luokan ominaisuudet eli sen omat muuttuja.
    // get jat set ovat C#:lle ominainen tapa luoda
    // muuttujille ns. getterit ja setterit tiedon
    // lukemista ja asettamista varten.
    public int Tuotenumero { get; set; }
    public string Nimi { get; set; }
    public int Määrä { get; set; }
    public double Hinta { get; set; }
    public double Alv { get; set; } // Muodossa 0.24 esimerkiksi.

    // Luokan parametriton rakentaja. Oletusrakentaja.
    public Tuote() {
        // Määritetään rakentajassa oletusarvot.
        this.Tuotenumero = 0;
        this.Nimi = "Tuntematon tuote";
        this.Määrä = 0;
        this.Hinta = 0;
        this.Hinta = 0;
    }

    // Luokan metodi. Toiminnallisuus mikä on tälle luokalle
    // tarkoitettu. Voidaan käyttää eri tarkoituksiin mutta tässä
    // esimerkiksi huolehtii verollisen hinnan laskemisesta.
    public double VerollinenHinta() {
        return Hinta * (1 + Alv);
    }

}
```

{% endcode %}

### Toiminnallinen luokka

Toiminnallisella luokalla tarkoitetaan tässä sellaista luokkaa, joka tekee asioita sille annetuilla parametreilla. Esimerkiksi edelliseen Tuote luokkaan viitaten, voidaan tehdä luokka, joka tulostaa sen tiedot haluttuun muottoon konsoliohjelmassa.

Alla olevassa esimerkissä luokka huolehtii konsoliin tulevista viesteistä. Huomaa `TulostaTuoterivi` metodin kohdalla, että sille annetaan `Tuote` luokan olio parametrina. Näin metodissa voidaan kertoa miltä tuloste näyttäisi.

{% code title="Tulostaja.cs" %}

```csharp
public class Tulostaja {

    public Tulostaja() {
        
    }

    public void TulostaTuoterivienOtsikkorivi() {
        
        string tulostettavaMerkkijono = $"Tuotenumero\tNimi\tVer.Hinta";

        Console.WriteLine(tulostettavaMerkkijono);
    }

    public void TulostaTuoterivi(Tuote tuote) {
        // Merkkijono joka alkaa $ on hyvä tietää. Sen avulla on mahdollista
        // muodostaa merkkijono muuttujien avulla esimerkin tapaa. 
        // Lauseen tai tulosteen muodostaminen on hieman.
        // Tällä ei ole eroa jos sitten tahtoo yhdistää merkkijonot + operaattorilla.
        string tulostettavaMerkkijono = $"{tuote.Tuotenumero}\t{tuote.Nimi}\t{tuote.VerollinenHinta()}";

        Console.WriteLine(tulostettavaMerkkijono);
    }

}

```

{% endcode %}

### Miksi teemme näin?

Edellisissä esimerkeissä Tuote luokka voisi yhtähyvin tulostaa itsensä samalla tavoin konsoliohjelmaan. On kuitenkin hyvä huomata, että luokkien avulla voidaan erottaa ohjelman eri osia. Siksi tässä on esimerkiksi erotettu tiedon tulostaminen itse tiedosta.

Kun kokonaisuuksia erotellaan, ohjelma on usein helpompi ymmärtää ja lukea sekä ylläpidettävämpi. Siksi on aina hyvä määrittää jonkinlainen tarkoitus luokalle... kysyä siis, että mikä on luokan tarkoitus tai mitä se yrittää tehdä.

Usein ei haittaa, että vaikka luokkia tulisi useampia. Aluksi se voi tuntua vaikeammalta mutta kyseiseen taitoon tottuu ajallaan.

Alla vielä esimerkki missä olemme käyttäneet näitä luokkia yhdessä.

{% code title="MainProgram.cs" %}

```csharp

public static void Main(string[] args)
{
    // Varsinaisen ohjelman suoritus alkaa.

    Tuote sytytystulppa = new Tuote();
    sytytystulppa.Tuotenumero = 100;
    sytytystulppa.Nimi = "Sytytystulppa, Model ZYV";
    sytytystulppa.Määrä = 10;
    sytytystulppa.Alv = 0.24;
    sytytystulppa.Hinta = 15.0;

    var tulostaja = new Tulostaja();

    tulostaja.TulostaTuoterivienOtsikkorivi();

    tulostaja.TulostaTuoterivi(sytytystulppa);

    // Varsinaisen ohjelman suoritus loppuu.
    }
}
```

{% endcode %}


# Projekti 2018/01 TDD esimerkki

## Videosarja aiheesta

{% file src="/files/-LP0sDR7emoGvpblqEP\_" %}
Ohjelman lopullinen versio, lähdekoodit
{% endfile %}

{% embed url="<https://www.youtube.com/playlist?list=PL3iay_FdAzV8TC3pmyHf7__d_MQxaRp8u>" %}

### Muu materiaali

![Projektin lisääminen Solutioniin](/files/-LP0hlZuCycoNqVaoSki)

![Testausikkunan (Pads) avaaminen](/files/-LP0hi3DjB8BxnT1HPW3)

<br>


# Käyttäjätarinat


# Pariohjelmointi


# Versionhallinta


# Testivetoinen kehitys


# Jatkuva integraatio


# Inkrementaalinen dokumentointi


