Kultainen koodi

.NET-osaajan ajatuksia paremmasta koodailusta

Archive for the tag “Visual Studio”

Visual Studio Live Unit Testing

Visual Studio 2017 RC julkisti seuraavan askeleen yksikkötestauksessa, live-tilan. Käytännössä VS ajaa jatkuvasti yksikkötestejä kirjoitettua koodia vastaan ja merkkaa onko koodiriviin osuva testi läpäisty, ei mene läpi tai puuttuuko se.

Silmäilin asiasta kertovan blogin läpi ja katsoin siihen liittyvän videon. Oli mielenkiintoista seurata intialaista kerrontaa. Se selvensi kuinka nopeasti testi heijastui koodiin. Pohdiskelin hetken, vaatiiko tekniikka paljon tehoa tietokoneelta?

Ominaisuus vaatii Enterprise-lisenssin, mikä on sääli. Se maksaa huiman summan, verrattuna tavallisesti käyttämääni pro-versioon.

Mieleeni juolahti vanha kuvio. Microsoft kopioi JetBrainsin ideoita. Tapahtuiko tämä kehitysaskel samoin?

Kyllä!

JetBrainsin dotCover tarjosi continuous testing -konseptin vuonna 2015. Se poikkeaa hieman VS:n natiivista. Se vain ajaa testejä jatkuvasti ja näyttää, menevätkö ne läpi. Tosin dotCoverin muut ominaisuudet näyttävät onko koodille yksikkötestejä.

Vanhaa kauraa siis. Kehittäjälle siis löytyy vaihtoehtoja reaaliaikaiseen testaukseen.

Pari vuotta sitten testasin dotCoveria ja tuolloin kaikilla mausteilla valittuna se hieman hidasti Visual Studiota. Olisi jännä testata onko dotCover ydintä optimoitu tuon jälkeen?

Pitää kokeilla!

Emacs työvälineenä

Kirjoitin clojurea syksyn emacsilla ja se sujui hyvin. Suurin osa ajastani menee siis koodin rakenteen ja toiminnan pohtimiseen. Saan näppärästi avattua haluamani tiedostot suoraan editoriin ja se tukee kohtuullisesti kirjoittamista.

Emacsin lisäksi pidän melko usein avoinna clojuren cheat sheet -sivua tai clojurescriptin vastaavaa.

Käyttö

Tavallisesti jaan ruudun kahteen tai kolmeen osaan. Yhdellä puolella näkyy koodi ja toisella yksikkötestit. Mikäli teen rajapintaan koodia, niin yhdellä puolella on tietenkin esim. palvelimen rajapinnat näkyvissä ja toisella puolella asiakas/web-sovelluksen puoli, joka kutsuu rajapintoja. Usein testaan koodin toimintaa myös REPL-ikkunassa.

Ikkunoiden ja tiedostojen välillä liikkuminen tapahtuu todella sujuvasti. Näppäinoikopolut purevat erittäin hyvin. Koodia saa siistittyä, leikattua ja liimattua vaivattomasti. Siihen emacs on tehty, kirjoittamiseen. Sen lisäksi yksikkötestit saa pyörimään jatkuvasti tai niitä voi pyöritellä komennoilla. Sekin toimii fantastisesti. Yksikkötestien ajaminen on paljon nopeampaa ja kätevämpää kuin Visual Studiolla, jota olen käyttänyt noin 10 vuotta.

Clojurea kirjoittaessani testaan usein koodia REPL-ikkunassa. Koodin namespacen saa ladattua näppärästi käyttöön ja voin ajaa haluamiani funktioita ”livenä”. Se helpottaa debuggausta, yksikkötestien suunnittelua ja funktion toiminnan testaamista.

Nähdäkseni emacsin valtteja ovat nopeus, koko ruudun tehokas käyttäminen ja laajennettavuus.

IDEn edut

IDE voittaa emacsin helposti koodin laadun tarkkailussa. Sekä Visual Studiosta, Eclipsestä ja InteeliJ:stä löytyy paljon lisäominaisuuksia, jotka helpottavat koodaamista.

Käyttömätön koodi nostetaan esiin paljon helpommin. IDEt yleensä ehdottavat (tai ainakin niihin lisätyt plugarit) kuinka koodia voisi parantaa. Koodausta helpottavat täydennystoiminnot ovat älykkäitä, toisin kuin emacsissa. Emacs tunnistaa aiemmin käytetyt funktiot, muttei osaa ehdottaa kirjastosta löytyviä vaihtoehtoja.

Sekä emacs että IDEt osaavat yhtä hyvin etsiä ja korvata tekstiä. Funktioiden tai metodien uudelleen nimeäminen sen sijaan onnistuu kunnolla vain IDEn kautta. Nimien tai nimiavaruuksien refaktorointi on ehdottomasti IDE-juttu.

Ohjelmakoodin rakenteen näkee IDEn olio tai sovellusrakenteesta, jos rakenne on yksinkertainen. Esimerkiksi MVVM tai simppeli Reactin dispatcher, subscriber -rakenne näkyy paremmin IDEstä kuin emacsista. Tosin kumpikaan ei pelasta jos kyseeseen tulee kompleksinen rakenne, kuten Prism tai laajalle levinnyt legacy-järjestelmä.

Kipeimmin emacsissa minua pistivät puuttuvat uudelleennimeämisominaisuudet, hyvän bookmark-järjestelmän puute ja heikko tuki koodin laadun tarkkailuun. Olisin kaivannut vihjeitä miten asiat koodataan. Projektissani asia korjaantui mob-koodauksessa ja pull request -arvioinneissa.

IDEssä käytettävien useiden näppäinten oikopolkujen sijaan emacsissa kirjoitetaan usea näppäinoikopolku peräkkäin. Esimerkiksi yksikkötestit voi ajaa komennolla (ctrl+c, ctrl+t, ctrl+n) IDEssä suositaan usean näppäimen samanaikaista painamista. IDEssä komennon voi siis käynnistää ”heti”.

Huomasin myös joidenkin emacsin lisäosien käytön vaativan järjettömiä näppäinoikopolkuja eli komennot menivät neljän tai useamman komennon syvyyteen. Se ei tuntunut käytettävältä. Niin pitkiä komentosarjoja ei edes pysty helposti muistamaan.

Lopuksi

Tuntui mukavalta kokeilla emacsia, mutta projektin laajentuessa jäin kaipaamaan useamman tiedoston refaktorointiin liittyviä ominaisuuksia. Halusin myös käyttää lyhyempiä näppäinoikopolkuja, mutta olenko valmis uhraamaan nopeuden käyttömukavuuden alttarille?

Windows Forms lokalisointi, Satellite Assemblies

Windows Forms -lokalisointi eli kieliversioiden tarjoaminen teksteille ei käy käden käänteessä. Teknisesti asia hoidetaan yksinkertaisesti. Luodaan yksi resurssitiedosto jokaiselle tarvittavalle kielelle ja merkkijonojen käännökset sijoitetaan näihin tiedostoihin. Uudemmilla tekniikoilla, kuten WPF, tämän voi automatisoida hyvin pitkälle esimerkiksi ReSharperilla.

Demoissa käytetty Microsoftin ”automaattinen” kieliversiointi luo jokaiselle lomakkeelle ja UserControllille omat resurssitiedostot. Esimerkiksi kymmenen formin ja viiden UserControllin projektissa tällöin kahdelle kieliversiolle tulisi kolmekymmentä resurssitiedostoa, joissa sama teksti toistuisi useaan kertaan. Ok- tai Peruuta-tekstit pitäisi kääntää jokaisen komponentin kohdalla erikseen ja muistaa tehdä muutokset jokaiseen resurssitiedostoon.

Windows forms -lokalisointi toimii näin:
1. Luodaan resurssitiedostot käytetyille kielille
2. Luodaan sovelluskohtainen ResourceManager
3. Asetetaan lomake tai UserControl lokalisoitavaksi
4. Tehdään lokalisointi koodin puolella
5. Luodaan lokalisoitavat tekstit resurssitiedostoihin
ja
6. Luodaan paikka, jossa voi vaihtaa kieliasetusta

Vaiheet 1 ja 2 tehtään kerran. Vaiheita 3-5 toistetaan jokaisen lokalisoitavan lomakkeen ja UserControllin kohdalla. Sovelluksesta riippuen, kieliversion vaihtaminen sijoitetaan sovelluksen mukaisesti joko aina nähtäville tai kertavalinnaksi.

Kieliversioitu testilomake

Yksinkertainen lomake Satellite Assembly -lokalisointia varten.

1. Luodaan resurssitiedostot käytetyille kielille

Luo projektiin Resources-kansio. Lisää sinne resurssitiedostot. Geneerinen en-valinta sopii hyvin Suomalaiseen makuun, koska meillä ei yleensä tehdä suurta eroa Amerikan- ja Britannianenglannin välille.

Luo resurssitiedostot

Luo resurssitiedostot

2. Luodaan sovelluskohtainen ResourceManager

Luo päälomakkeelle tai sovelluksen avaavaan program-kohtaan globaali ResourceManager.

private ResourceManager _resourceManager = null;

Initialinnin yhteydessä aseta nykyinen kulttuuri, tässä tapauksessa Suomi ja sen lisäksi viittaus resurssitiedostojen sijaintiin.

Thread.CurrentThread.CurrentCulture = new CultureInfo("fi-FI");
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
_resourceManager = new ResourceManager("WFSatelliteAssembly.Resources.WFSatelliteAssembly", 
                                       Assembly.GetExecutingAssembly());

Globaalin resurssienhallitsijan sijaan voit luoda myös aina uuden, jos siltä tuntuu. Tällöin pitää huolehtia resurssitiedostojen löytymisestä, varsinkin jos yritetään viitata niihin toisesta projektista käsin. Useampaa projektia käytettäessä globaali olio tuntui kätevämmältä.

3. Asetetaan lomake tai UserControl lokalisoitavaksi

Valitse haluttu luokka ja muuta se lokalisoitavaksi.

Laita lokalisointi päälle

Laita lokalisointi päälle

4. Tehdään lokalisointi koodin puolella

Konstruktoriin, heti komponenttien initialisoinnin jälkeen aseta kieliversioidut tekstit.

InitializeComponent(); // Visual Studion luoma metodi
UpdateUiControls();

Itse päivitysmetodi

private void UpdateUiControls()
{
    try
    {
        if (_resourceManager != null)
        {
            Text = _resourceManager.GetString("Lomakkeen otsikko");
            uiLabelFirst.Text = _resourceManager.GetString("Eka teksti");
            uiLabel1.Text = _resourceManager.GetString("Toka teksti");
            uiLabel3.Text = _resourceManager.GetString("Kolmas teksti");
            uiLabel4.Text = _resourceManager.GetString("Valitse kieli");
            uiButton1.Text = _resourceManager.GetString("Peruuta");
            uiButtonTemput.Text = _resourceManager.GetString("Tee temput");
        }
    }
    catch (System.Exception e)
    {
        MessageBox.Show(e.Message);
    }
}

5. Luodaan lokalisoitavat tekstit resurssitiedostoihin

UpdateUiControls-metodissa annetaan avain, jonka perusteella haetaan lokalisoitu teksti. Esimerkiksi lomakkeen otsikko haetaan avaimella ”Lomakkeen otsikko” ja sen arvo suomeksi on ”Monikielisyys”. Jos kielen vaihtaa englanniksi, otsikon teksti muuttuu arvoon ”Satellite assembly test”.

Suomenkielinen lokalisointi

Suomenkieliset tekstit

Englanninkielinen lokalisointi

Englanninkieliset tekstit

6. Luodaan paikka, jossa voi vaihtaa kieliasetusta

Kielen valinta voidaan tehdä RadioButtonilla seuraavasti:

private void uiRadioButton_Click(object sender, Resco.UIElements.UIMouseEventArgs e)
{
    UIRadioButton radioButton = sender as UIRadioButton;
    string culture = string.Empty;
    if (radioButton == null) return;

    switch (radioButton.Text)
    {
        case "Suomi":
            culture = "fi-FI";
            break;
        case "English":
            culture = "en-GB";
            break;
    }

    // This is used for the language of the user interface
    Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(culture);
    // This is used with formatting and sort options (e.g. number and date formats)
    // e.g. a float value 2.352 will be 2,3.52 if CurrentCulture is set to de-DE
    Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(culture);
}

Näillä ohjeilla voi luoda kieliversioinnin Windows Forms -sovellukselle.

Katso myös

C#-kielen kehitys

Pidän rajapinnoista ja tehokkaasta ohjelmoinnista. Ensimmäinen pysäyttävä kokemukseni syntyi siirtymä C# 2.0 ja 3.0:n välillä, kun pääsi kirjoittamaan autoproperty-tyyppisiä get ja set metodeja. Näitä tuttuja:

public int Foo { get; set; }

C# 6 tarjoaa vihdoin pelkän getterin sisältämät propertyt.

public class Point
{
public int X { get; }
public int Y { get; }

public int ReadWrite { get; set; }
}

C# 5 tarjosi async ja await -toimintoja, jotka olivat Taskin kanssa tuttuja C# 4:n puolelta.

Evoluutio 5-versioon asti löytyy evoluutiomatriisista.

C# 6 näyttää olevan muutoinkin ohjelmoijan kannalta se kieliversio, joka vähentää koodin kirjoittamista. Olen aivan täpinöissäni, koska lyhyen parametrisoidun stringin voi luoda luettavammassa muodossa. Vanha toteutus

return String.Format("({0}, {1})", X, Y);

muuttuu muotoon

return "(\{X}, \{Y})";

Kuutosen mukana näyttää tulevan paljon muitakin herkkuja matkaan. Lambda-lauseella saa tehtyä uusia laajennuksia uudella =>-nuolioperaattorilla. Jalka väpättää innostuksesta uutta kieliversiota käyttäviä projekteja odotellessa.

Vielä C# 6 ei asennu automaattisesti vielä Visual Studio 2013 mukana, mutta ehkä tulevaisuudessa sen saa päivitettyä yhdeksi mahdolliseksi kieliversioksi. Tähän mennessä VS ja eri kieliversiot ovat pyörähtäneet aika mukavasti käyntiin. Varsinkin kun VS2012 mukana voi kehittää useammalla eri versiolla eli kieliversio ei ole naimisissa IDE-version kanssa.

Post Navigation