Continue writing report

This commit is contained in:
Marko Korhonen 2020-05-01 21:27:17 +03:00
parent 47ce0fc149
commit bc3fe77c93
No known key found for this signature in database
GPG key ID: 911B85FBC6003FE5
3 changed files with 195 additions and 12 deletions

View file

@ -38,8 +38,62 @@
@article{wiki:garbagecollection, @article{wiki:garbagecollection,
title = {Automaattinen roskienkeräys}, title = {Automaattinen roskienkeräys},
journal = {}, journal = {},
author = {Wikipedia contributors}, author = {Wikipedian kirjoittajat},
year = 2020, year = 2020,
url = {https://fi.wikipedia.org/wiki/Automaattinen_roskienker%C3%A4ys}, url = {https://fi.wikipedia.org/wiki/Automaattinen_roskienker%C3%A4ys},
lastchecked = {24. Huhtikuuta, 2020} lastchecked = {24. Huhtikuuta, 2020}
} }
@misc{rust:cargo,
title = {The Cargo Book},
url = {https://doc.rust-lang.org/cargo},
publisher = {},
author = {Rust Team},
year = 2020,
lastchecked = {1. Toukokuuta 2020},
}
@misc{rust:cratesio,
title = {The Rust community's crate registry},
url = {https://crates.io},
publisher = {}
author = {Rust Team},
year = 2020,
lastchecked = {1. Toukokuuta 2020},
}
@misc{jwt:home,
title = {JSON Web Tokens},
url = "https://jwt.io",
publisher = {},
author = {Auth0},
year = 2020,
lastchecked = {29. Huhtikuuta 2020},
}
@misc{yew:home,
title = {Yew Docs},
url = {https://yew.rs/docs},
publisher = {},
author = {Yew Team},
year = 2020,
lastchecked = {1. Toukokuuta 2020},
}
@misc{webassembly:stdweb,
title = {stdweb},
url = "https://docs.rs/stdweb/0.4.20/stdweb",
publisher = {},
author = {Rust team},
year = 2020,
lastchecked = {1. Toukokuuta 2020},
}
@misc{webassembly:web_sys,
title = {web_sys},
url = "https://docs.rs/web-sys/0.3.35/i686-unknown-linux-gnu/web_sys/",
publisher = {},
author = {Rust team},
year = 2020,
lastchecked = {1. Toukokuuta 2020},
}

View file

@ -1,7 +1,7 @@
\chapter{Kielet} \chapter{Kielet}
\section{Rust} \section{Rust}
Rust\cite{rust:lang} on Mozillan 2010 julkaisema ohjelmointikieli. Se on hyvin suorituskykyinen järjestelmätason ohjelmointikieli, muistuttaen monilta osin C ja C++ kieliä. Rustin tarkoituksena on säilyttää näiden vanhojen kielien suorituskyky, mutta kuitenkin tarjoten samalla muun muassa vahvan tyypityksen ja taatun turvallisen rinnakaisajon. Lisäksi tyypilliset C-kielien muistinhallintaongelmat on pyritty ratkaisemaan käytännöillä, jotka ovat samalla tehokkaita mutta myös helppoja käyttää ohjelmoijalle. Rust\cite{rust:lang} on Mozillan 2010 julkaisema ohjelmointikieli. Se on hyvin suorituskykyinen järjestelmätason ohjelmointikieli, muistuttaen monilta osin C ja C++ kieliä. Rustin tarkoituksena on säilyttää näiden vanhojen kielien suorituskyky, mutta kuitenkin tarjota samalla muun muassa vahva tyypitys ja taattu turvallinen rinnakaisajo. Lisäksi tyypilliset C-kielien muistinhallintaongelmat on pyritty ratkaisemaan käytännöillä, jotka ovat samalla tehokkaita suorituskyvyn näkökulmasta, mutta myös helppoja käyttää ohjelmoijalle.
\subsection{Muistinhallinta} \subsection{Muistinhallinta}
@ -9,7 +9,7 @@ Monissa korkean tason ohjelmointikielissä, esimerkiksi JavaScriptissä, on auto
Automaattiselle roskienkeruulle on aikaisemmin ollut vaihtoehtona vain manuaalinen muistinhallinta, missä ohjelmoija varaa ja vapauttaa muistia tarpeen mukaan. Tämä on taas verratuna automaattiseen roskien keruuseen melko työlästä ja virheherkkää. Automaattiselle roskienkeruulle on aikaisemmin ollut vaihtoehtona vain manuaalinen muistinhallinta, missä ohjelmoija varaa ja vapauttaa muistia tarpeen mukaan. Tämä on taas verratuna automaattiseen roskien keruuseen melko työlästä ja virheherkkää.
Rustin yhtenä pääominaisuutena on mainostettu sen uudenlaista näkökulmaa muistinhallintaan: omistajuutta\cite{rust:ownership}. Siinä jokaisella arvolla on omistaja, ja kun omistaja menee näkyvyysalueen ulkopuolelle, niin menevät myös sen omistamat arvotkin, eli ne vapautetaan muistista. Arvojen omistajuutta voi myös siirtää joko väliaikaisesti lainaamalla tai pysyvästi. Otetaan esimerkkinä seuraava yksinkertainen koodi: Rustin yhtenä pääominaisuutena on mainostettu sen uudenlaista näkökulmaa muistinhallintaan: omistajuutta\cite{rust:ownership}. Siinä jokaisella arvolla on omistaja, ja kun omistaja menee näkyvyysalueen ulkopuolelle, niin menevät myös sen omistamat arvotkin, eli ne vapautetaan muistista. Arvojen omistajuutta voi siirtää joko pysyvästi tai väliaikaisesti lainaamalla. Otetaan esimerkkinä seuraava yksinkertainen koodi:
\clearpage \clearpage
\begin{minted}{Rust} \begin{minted}{Rust}
@ -40,20 +40,123 @@ fn main() {
} }
\end{minted} \end{minted}
Tässä esimerkissä omistajuuden siirtäminen on korvattu lainauksella. Lainauksessa omistajuuden siirtäminen on väliaikainen ja omistajuus palautuu arvon lainanneelle funktiolle (tässä tapauksessa main) kun arvoa lainannut funktio poistuu näkyvyysalueelta. Arvon lainaaminen tehdään käyttämällä merkkiä ''\char`&''. Tässä esimerkissä omistajuuden siirtäminen on korvattu lainauksella. Lainauksessa arvon omistajuus säilyy nykyisellään ja lainaaja antaa itse arvon sijasta viitteen(eng. reference). Viite on osoitin, joka osoittaa samaan muistipaikkaan kuin missä alkuperäinen arvo on. Lainaaminen tehdään käyttämällä merkkiä ''\char`&''.
\clearpage
\subsection{Vahva tyypitys} \subsection{Vahva tyypitys}
Rust on vahvasti tyypitetty kieli, mikä tarkoittaa sitä, että kaikkien arvojen tyypit pitää olla tiedossa ohjelman kokoamisen aikana. Tähän sisältyy myös funktioiden parametrit ja paluuarvot. Usein Rustin kääntäjä osaa päätellä arvojen tyypit itse, varsinkin yksinkertaisissa tapauksissa:
\begin{minted}{Rust}
let name = "Marko"; // string slice
let age = 26; // integer
\end{minted}
Niissä tapauksissa joissa tyypille voi olla useita vaihtoehtoja, tai silloin jos arvon määrityksen yhteydessä tapahtuu konversio, ohjelmoijan tulee määrittää tyyppi. Tyypin voi määrittää näin:
\begin{minted}{Rust}
let name: &str = "Marko";
let age: u8 = 26;
\end{minted}
Valitsin arvolle ''age'' tyypin \code{u8}, koska se on pienin kokonaislukutyypeistä ja sen arvo voi olla välillä 0-255. Näin voi potentiaalisesti vähentää ohjelman muistin käyttöä. Lisäksi tyypeillä voi myös karkeasti rajata funktion parametrejen arvojen vaihteluväliä. Esimerkiksi jos on kirjoittamassa funktiota joka ottaa parametrina henkilön iän, \code{u8} on hyvä valinta koska ihmisen ikä ei voi olla negatiivinen ja ihmiset myös harvoin elävät yli 255 vuotta.
Edellä mainittu tyyppi \code{u8} on niin kutsuttu allekirjoittamaton kokonaisluku (eng. \textbf{u}nsigned). Allekirjoitetuissa kokonaisluvuissa (eng. signed) käytetään yksi bitti merkkaamaan sitä, onko luku positiivinen vai negatiivinen. Allekirjoittamattamattomissa luvuissa tätä ei tehdä, joten luku voi olla hieman isompi kuin allekirjoitettu luku, mutta se ei voi olla negatiivinen.
\begin{table}[h!]
\label{tab:table1}
\begin{center}
\begin{minipage}{2in}
\begin{tabular}{|c|c|c|}
\hline
\multicolumn{3}{|c|}{\textbf{Allekirjoittamaton}} \\
\hline
Tyyppi & Minimi & Maksimi \\
\hline
u8 & 0 & $2^{8}-1$\\
u16 & 0 & $2^{16}-1$\\
u32 & 0 & $2^{32}-1$\\
u64 & 0 & $2^{64}-1$\\
u128 & 0 & $2^{128}-1$\\
\hline
\end{tabular}
\end{minipage}
\begin{minipage}{2in}
\begin{tabular}{|c|c|c|}
\hline
\multicolumn{3}{|c|}{\textbf{Allekirjoitettu}} \\
\hline
Tyyppi & Minimi & Maksimi \\
\hline
i8 & $-2^{7}$ & $2^{7}-1$\\
i16 & $-2^{15}$ & $2^{15}-1$\\
i32 & $-2^{31}$ & $2^{31}-1$\\
i64 & $-2^{64}$ & $2^{63}-1$\\
i128 & $-2^{127}$ & $2^{127}-1$\\
\hline
\end{tabular}
\end{minipage}
\end{center}
\caption{\textit{Rustin kokonaislukutyypit ja niiden vaihteluvälit}}
\end{table}
Toisin kuin C- ja C++ -kielissä, Rustissa on oletuksena allekirjoittamattomien kokonaislukujen ylivuoto pois päältä. Tämä tarkoittaa sitä, että jos 8-bittisen allekirjoittamattoman kokonaisluvun arvo on esimerkiksi 256, siitä tulee 0. Rustin kääntäjä siis ei anna tällaisen tapahtua vaan kääntämisen yhteydessä tulee virheviesti:
\begin{minted}{shell}
error: literal out of range for `u8`
--> types.rs:2:19
|
2 | let age: u8 = 256;
| ^^^
|
= note: `#[deny(overflowing_literals)]` on by default
error: aborting due to previous error
\end{minted}
\subsection{Muuttumaton data} \subsection{Muuttumaton data}
Rustissa kaikki arvot ovat oletuksena muuttumattomia (engl. immutable). Jos muuttumattoman datan sijasta tarvitsee muuttujia (engl. mutable), voi käyttää avainsanaa ''mut'', esimerkiksi \code{let mut name = "Marko"}. Myös lainaukset suoritetaan oletuksena muuttumattomasti ja muuttuvan lainauksen voi tehdä samalla avainsanalla, esimerkiksi \code{say\char`_hello(\char`&mut name)}. Rustissa kaikki arvot ovat oletuksena muuttumattomia (engl.\ immutable). Jos muuttumattoman datan sijasta tarvitsee muuttujia (engl. mutable), voi käyttää avainsanaa ''mut'', esimerkiksi \code{let mut name = "Marko"}. Myös lainaukset suoritetaan oletuksena muuttumattomasti ja muutettavan lainauksen voi tehdä samalla avainsanalla, esimerkiksi \code{say\char`_hello(\char`&mut name)}.
Yleinen konsensus ohjelmoinnin maailmassa on se, että kaikki arvot mitä ei tarvitse muuttaa pitäisi nimenomaan määrittää muuttumattomana. Tämä on tuttua kaikille, jotka ovat tutustuneet funktionaalisiin ohjelmointikieliin. Muuttumaton data on myös todella tärkeää rinnakkaisajossa, missä useampi prosessi suorittaa samoja funktioita ja käsittelee samoja arvoja samaan aikaan. Yleinen konsensus ohjelmoinnin maailmassa on se, että kaikki arvot mitä ei tarvitse muuttaa pitäisi nimenomaan määrittää muuttumattomana. Tämä on tuttua kaikille, jotka ovat tutustuneet funktionaalisiin ohjelmointikieliin. Muuttumaton data on myös todella tärkeää rinnakkaisajossa, missä useampi prosessi suorittaa samoja funktioita ja käsittelee samoja arvoja samaan aikaan.
\subsection{Luotettavuus} \subsection{Luotettavuus}
Rustia kehitettäessä on aina ollut tavoitteena luotettavuus. Tämä tarkoittaa sitä, että ohjelman virheet huomataan jo koontivaiheessa, eikä vasta suorituksen aikana ohjelman tietyssä tilassa. Tämän mahdollistavat edellä mainitut omistajuusmalli ja vahva tyypitys. Omistajuusmalli varmistaa sen, että ohjelmoija joutuu koodia kirjoittaessaan miettimään arvojen eliniän, joka tekee muistivuodoista harvinaisia. Vahva tyypitys varmistaa taas sen, että data on kaikkialla ohjelmassa yhteensopivaa. Rustia kehitettäessä on aina ollut tavoitteena luotettavuus. Tämä tarkoittaa sitä, että ohjelman virheet huomataan jo koontivaiheessa, eikä vasta suorituksen aikana ohjelman tietyssä tilassa. Tämän mahdollistavat edellä mainitut omistajuusmalli ja vahva tyypitys. Omistajuusmalli varmistaa sen, että ohjelmoija joutuu koodia kirjoittaessaan miettimään arvojen eliniän, joka tekee muistivuodoista harvinaisia. Vahva tyypitys varmistaa taas sen, että data on kaikkialla ohjelmassa yhteensopivaa.
Myös Rustin kokoojaan on panostettu paljon, ja virheiden sattuessa se on todella hyvä työkalu ohjelmoijalle. Se alleviivaa ongelmakohdat ja selittää lyhyesti mistä ongelma johtuu. Jossain tapauksissa kokooja jopa antaa pieniä koodin pätkiä mistä voi olla apua ongelman ratkaisemisessa. Myös Rustin kääntäjään on panostettu paljon, ja virheiden sattuessa se on todella hyvä työkalu ohjelmoijalle. Se alleviivaa ongelmakohdat ja selittää lyhyesti mistä ongelma johtuu. Jossain tapauksissa kääntäjä jopa antaa pieniä koodin pätkiä mistä voi olla apua ongelman ratkaisemisessa.
\subsection{Paketinhallinta}
Rustin paketinhallinta on toteutettu Cargo-nimisellä ohjelmalla. Sitä voi käyttää koko ohjelmiston elinkaaren ajan aina projektin luomisesta sen julkaisemiseen. Cargon käsittelemiä paketteja kutsutaan laatikoiksi (eng. crate), jotka julkaistaan crates.io\cite{rust:cratesio} pakettirekisterissä. Laatikot voivat myös olla riippuvaisia toisista laatikoista.
Laatikon tiedot ja riippuvuudet määritetään \code{Cargo.toml} tiedostossa. Tässä esimerkki tämän opinnäytetyön yhteydessä tehdyn projektin palvelinpuolen \code{Cargo.toml}:
\begin{minted}{TOML}
[package]
name = "thesis-backend"
version = "0.1.0"
authors = ["Marko Korhonen <marko.korhonen@reekynet.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
actix-web = "2.0.0"
actix-rt = "1.0.0"
serde = { version = "1.0.104", features = ["derive"] }
diesel = { version = "1.4.3", features = ["mysql", "r2d2", "chrono"] }
dotenv = "0.15.0"
bcrypt = "0.6.2"
env_logger = "0.7.1"
r2d2 = "0.8.8"
crypto = "0.0.2"
jsonwebtoken = "7.1.0"
chrono = { version = "0.4.11", features = ["serde"] }
actix-cors = "0.2.0"
actix-identity = "0.2.1"
futures = "0.3.4"
actix-files = "0.2.1"
\end{minted}
Cargoon on saatavilla myös useita liitännäisiä, esimerkiksi \code{cargo-watch}, joka suorittaa halutun toiminnon aina kun projektin sisällä tapahtuu muutoksia ja tässäkin projektissa käytetty \code{cargo-web}, joka helpottaa WebAssembly-ohjelmien kehittämistä.
\subsection{Dokumentaatio ja yhteisö} \subsection{Dokumentaatio ja yhteisö}
Rust on tunnettu todella laajasta dokumentaatiostaan ja vahvasta yhteisöstään. Molemmista on paljon apua varsinkin aloittejioille. Rust on tunnettu todella laajasta dokumentaatiostaan ja vahvasta yhteisöstään. Molemmista on paljon apua varsinkin aloittejioille.
@ -63,4 +166,4 @@ Aloitin itsekin opiskelemaan Rustia vain hieman ennen tämän opinnäytetyön al
\section{WebAssembly} \section{WebAssembly}
WebAssembly on kehitteillä oleva asiakaspuolen ohjelmointikieli. Sitä on suunniteltu JavaScriptin seuraajaksi ja sen suurinpana etuna JavaScriptiin verrattuna on huomattavasti matalemman tason esitysmuoto, minkä ansiosta se on suorituskykyisempi. WebAssembly on kehitteillä oleva asiakaspuolen ohjelmointikieli. Sitä on suunniteltu JavaScriptin seuraajaksi ja sen suurinpana etuna JavaScriptiin verrattuna on huomattavasti matalemman tason esitysmuoto, minkä ansiosta se on suorituskykyisempi.
Kehittäjän ei ole tarkoitus kirjoittaa WebAssemblya suoraan, vaan käyttää työkaluja, joilla olemassa olevia ohjelmointikieliä voi koota WebAssemblyksi. Rust on tästä hyvä esimerkki, sillä WebAssembly on yksi sen kokoojan natiiveista "targeteista", samalla tavalla kuin vaikka x86-prosessorit. Kehittäjän ei ole tarkoitus kirjoittaa WebAssemblya suoraan, vaan käyttää työkaluja, joilla olemassa olevia ohjelmointikieliä voi koota WebAssemblyksi. Rust on tästä hyvä esimerkki, sillä WebAssembly on yksi sen kääntäjän natiiveista ''targeteista'', samalla tavalla kuin vaikka x86-prosessorit.

View file

@ -2,7 +2,8 @@
Tein opinnäytetyön yhteydessä fullstack-projektin, missä sekä palvelin- että asiakaspuolen ohjelmointi tehtiin Rustilla. Tarkoituksena ei ollut saada aikaiseksi mitään todella monimutkaista ohjelmaa, vaan puhtaasti arvioida Rustin soveltuvuutta web-ohjelmointiin. Tein opinnäytetyön yhteydessä fullstack-projektin, missä sekä palvelin- että asiakaspuolen ohjelmointi tehtiin Rustilla. Tarkoituksena ei ollut saada aikaiseksi mitään todella monimutkaista ohjelmaa, vaan puhtaasti arvioida Rustin soveltuvuutta web-ohjelmointiin.
\section{Palvelinpuoli} \section{Palvelinpuoli}
Palvelinpuolen rungoksi valikoitui Actix web. Se on käytännössä vastine JavaScript-maailman Express.js:lle, eli se hoitaa HTTP-palvelimen työtä ja reitittää GET ja POST pyynnöt ohjelman oikeille funktioille. \subsection{Kehys}
Palvelinpuolen kehykseksi valikoitui Actix web. Se on käytännössä vastine JavaScript-maailman Express.js:lle, eli se hoitaa HTTP-palvelimen työtä ja reitittää GET ja POST pyynnöt ohjelman oikeille funktioille.
Actix web on puolestaan rakennettu hyödyntämällä Actix frameworkiä, mikä on rakennettu löyhästi actor-mallin pohjalta. Actor-malli\cite{wiki:actor} on Carl Hewittin vuonna 1973 luoma matemaattinen ja tietotekninen malli rinnakkaisajosta. Tämän ansiosta Actix web on hyvin suorituskykyinen ja helposti skaalautuva ratkaisu rajapintoja rakennettaessa. Actix web on puolestaan rakennettu hyödyntämällä Actix frameworkiä, mikä on rakennettu löyhästi actor-mallin pohjalta. Actor-malli\cite{wiki:actor} on Carl Hewittin vuonna 1973 luoma matemaattinen ja tietotekninen malli rinnakkaisajosta. Tämän ansiosta Actix web on hyvin suorituskykyinen ja helposti skaalautuva ratkaisu rajapintoja rakennettaessa.
@ -32,16 +33,41 @@ Tällöin varmistutaan automaattisesti siitä, että kun asiakkaan POST-pyyntö
} }
\end{minted} \end{minted}
Koska tässä JSON-objektissa ''admin'' ei ole tyyppiä boolean, Actix vastaa ''400 Bad Request''. Koska tässä JSON-objektissa ''admin'' ei ole tyyppiä boolean, kun se saapuu palvelimelle, Actix huomaa väärän tyypin ja vastaa statuskoodilla ''400 Bad Request''.
Actix webin modulaarisuus mahdollisti myös helposti tarvittavien väliohjelmistojen sisällyttämisen ohjelman toimintaan. Actix identity -paketista löytyi tarvittavat palikat itse kirjoittamani sisäänkirjautumistoiminnallisuuden lisäämisen suojattuihin reitteihin. Siinä käytin JSON Web Tokeneita, jotka lähetettiin onnistumisen kirjautumisen jälkeen asiakkaalle, ja jotka asiakas sitten lähettää serverille suojattuja reittejä käytettäessä. \subsection{Todentaminen}
Actix webin modulaarisuus mahdollisti myös helposti tarvittavien väliohjelmistojen sisällyttämisen ohjelman toimintaan. Actix identity -paketista löytyi tarvittavat palikat joilla sain lisättyä itse kirjoittaman käyttäjän todentamistoiminnallisuuden suojaamaan haluttuja reittejä.
Todentamiseen päätin käyttää JSON Web Tokeneita. JSON Web Tokenit ovat standardoitu (RFC 7519\cite{jwt:home}) tunnistautumistapa verkossa. Tokenit ovat merkkijonoja, jotka sisältävät JavaScript objektin tekstimuodossa (JSON). Tässä esimerkkinä yhden tokenin sisältö tästä projektista:
\begin{minted}{JSON}
{
"sub": 5,
"name": "TestUser",
"admin": false,
"exp": 1588262665
}
\end{minted}
Tämä tokenin sisältö on kaikkien sen hallussapitäjien nähtävissä. Turvallisuus tulee siitä, että token on allekirjoitettu palvelinpuolella vain palvelimen tiedossa olevalla salasanalla niin, että jos tokenin sisältö muuttuu yhtään, palvelin näkee että se ei ole enää validi.
Eli esimerkiksi jos joku tämän sovelluksen käyttäjä, joka ei ole ylläpitäjä, koittaa tehdä itsestään ylläpitäjän muuttamalla tokenista parametrin \code{"admin = false"} sanomaan \code{true}, palvelimella ajettava JWT validointifunktio, joka tietää oikean salasanan, näkee että tämä tunniste ei ole validi.
Tokenin sisällön voi päättää kokonaan itse, vaikkakin joitakin standardeja kenttiä on määritetty, esimerkiksi: iss(issuer), sub(subject), exp(expiration time). Päätin sisällyttää tiedon siitä, että onko käyttäjä ylläpitäjä, koska tätä tietoa voi sitten käyttää asiakaspuolella esimerkiksi käyttöliittymän muokkaamiseen käyttäjän roolin perusteella. Usein myös käyttäjän nimi sisällytetään tokeniin. Tokenin sisältöä suunnitellessa kannattaa pitää mielessä että sen sisältö on nähtävissä kaikille, joten se ei ole oikea paikka tallettaa salaista tietoa, kuten vaikka käyttäjän salasana.
Päätin tallettaa edellä mainitun JSON Web Tokenin keksiin(eng. cookie), joka on standardi tapa tallettaa juuri tällaisia todentamiseen käytettäviä tietoja selaimiin. Keksien käyttämisen etu on se, että selain huolehtii sen tallettamisesta automaattisesti ilman lisätoimia kehittäjältä. Lisäksi selain sisällyttää sen seuraaviin kutsuihin automaattisesti.
\subsection{Tietokanta}
Tietokannaksi valikoitui itselleni tuttu MySQL. Relaatiotietokannan sai helposti yhdistettyä Rust-koodiini Diesel ORM:llä. Diesel on tähän mennessä käyttämistäni ORM-kirjastoista selkeästi mukavin käyttää. Tietokannaksi valikoitui itselleni tuttu MySQL. Relaatiotietokannan sai helposti yhdistettyä Rust-koodiini Diesel ORM:llä. Diesel on tähän mennessä käyttämistäni ORM-kirjastoista selkeästi mukavin käyttää.
Käytännöllisimmät ominaisuudet kehittäjän näkökulmasta olivat Dieselin mukana tuleva komentorivikäyttöliittymä ja migraatiot. Jokaiselle taululle luodaan uusi migraatio, esimerkiksi \code{diesel migration generate users}, jonka jälkeen dieselin luomaan hakemistoon kirjoitetaan up.sql ja down.sql tiedostot, eli ohjeet siitä, miten tämä taulu luodaan ja poistetaan. Taulu viedään tietokantaan komennolla \code{diesel migration run} ja taulun voi poistaa ja luoda uudelleen komennolla \code{diesel migration redo}. Tämä mahdollistaa myös samalla sen, että versiohallintaan voi tallentaa useita versioita samasta taulusta ja palata helposti takaisin vanhempaan versioon jos uudemman kanssa ilmenee ongelmia. Käytännöllisimmät ominaisuudet kehittäjän näkökulmasta olivat Dieselin mukana tuleva komentorivikäyttöliittymä ja migraatiot. Jokaiselle taululle luodaan uusi migraatio, esimerkiksi \code{diesel migration generate users}, jonka jälkeen Dieselin luomaan hakemistoon kirjoitetaan up.sql ja down.sql tiedostot, eli ohjeet siitä, miten tämä taulu luodaan ja poistetaan. Taulu viedään tietokantaan komennolla \code{diesel migration run} ja taulun voi poistaa ja luoda uudelleen komennolla \code{diesel migration redo}. Tämä mahdollistaa myös samalla sen, että versiohallintaan voi tallentaa useita versioita samasta taulusta ja palata helposti takaisin vanhempaan versioon jos uudemman kanssa ilmenee ongelmia.
Edellä mainitut työkalut helpottivat tietokannan kehitystä huomattavasti. Usein varsinkin projektin alkuvaiheilla tietokanta muuttuu jatkuvasti ja usein tulee tarve poistaa ja luoda tietokanta uudelleen. Monet pitävät kehittäjät juurikin tällaista Dieselin up.sql kaltaista tiedostoa versiohallinnassa ja tarpeen mukaan poistavat tietokannan käsin ja liittävät komennon tiedostosta tietokannan komentorivikäyttöliittymään. Edellä mainitut työkalut helpottivat tietokannan kehitystä huomattavasti. Usein varsinkin projektin alkuvaiheilla tietokanta muuttuu jatkuvasti ja usein tulee tarve poistaa ja luoda tietokanta uudelleen. Monet kehittäjät pitävät juurikin tällaista Dieselin up.sql kaltaista tiedostoa versiohallinnassa ja tarpeen mukaan poistavat tietokannan käsin ja liittävät komennon tiedostosta tietokannan komentorivikäyttöliittymään. Dieseliä käytettäessä tämä tulee tehtyä automaattisesti ja se tuntuu todella luontevalta.
\section{Asiakaspuoli} \section{Asiakaspuoli}
Projektin asiakaspuolen, eli selaimessa suoritettavan osan kehykseksi valitsin Yew:n. Yew\cite{yew:home} muistuttaa hyvin paljon JavaScript-maailmassa suosittua Reactia, eli sen on komponenttipohjainen. Tämä tarkoittaa sitä että kaikki ohjelman osien täytyy implementoida Yew:n Component-rajapintaa, jossa on funktiot create, change, update ja view. Näiden avulla funktioiden Yew pystyy orkestroimaan kullakin hetkellä näytettävien komponenttien tilaa.
Tämän projektin osan aloittaminen vaati aika paljon tutkimustyötä. Rust-koodi pitää kääntää WebAssemblyksi, johon on olemassa useita eri työkaluja. clearpage
\clearpage \clearpage