tag:blogger.com,1999:blog-56478420923229998202024-03-21T08:37:10.861+01:00Daniel Dymek - blogDanielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.comBlogger24125tag:blogger.com,1999:blog-5647842092322999820.post-6389312532410870402017-05-31T21:48:00.000+02:002017-05-31T21:50:46.144+02:00Podsumowanie na koniec konkursu Daj Się Poznać i dalsze plany<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyn_W-ydlo1lHGK9wwPt47bZxpwXNAkXNTR7qHhLoV7MkEiWdxCOVEfdZPUbmou32dQE5Ah2v7GSZxQDX0E1TUJpdLBhjZf53UH8-Be3YGVKMTASTgkD0-xCEf5HYc8Xq6b9HYkyK5xu4/s1600/finish.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="512" data-original-width="512" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyn_W-ydlo1lHGK9wwPt47bZxpwXNAkXNTR7qHhLoV7MkEiWdxCOVEfdZPUbmou32dQE5Ah2v7GSZxQDX0E1TUJpdLBhjZf53UH8-Be3YGVKMTASTgkD0-xCEf5HYc8Xq6b9HYkyK5xu4/s200/finish.png" width="200" /></a></div>
Dziś upływa kolejny, ostatni już miesiąc konkursu Daj Się Poznać. Czas zatem na podsumowania - zarówno te duże, całych trzech miesięcy, jak i te małe - czyli tego co działo się w maju.<br />
<br />
<a name='more'></a>Zacznę od całego konkursu. Trzy miesiące jego trwania minęły wyjątkowo szybko, ale zarazem pracowicie. Gdybym miał podsumować całość jednym zdaniem, to powiedziałbym, że jestem zadowolony z uczestnictwa i było warto.<br />
A co konkretnie udało mi się przez ten czas osiągnąć?<br />
<br />
<h3>
Blogowanie</h3>
Przede wszystkim cieszę się, że założyłem bloga i zacząłem na nim publikować. Najtrudniej zrobić ten pierwszy krok, a teraz mam to już za sobą. Co więcej, udało mi się wytrwać do końca konkursu z jego prowadzeniem. Mając za sobą te 23 posty, które pojawiły się do tej pory, zdecydowanie bardziej doceniam pracę jaką trzeba włożyć w regularne publikowanie wartościowych treści.<br />
<br />
Garść statystyk z trzech miesięcy prowadzenia bloga:<br />
<ul>
<li>
Użytkownicy: 422</li>
<li>Odsłony: 1083</li>
<li>Najpopularniejsze posty:<br />
1. <a href="http://danieldymek.blogspot.com/2017/04/jakie-jest-najlepsze-ide-dla-angulara-i.html" target="_blank">Jakie jest najlepsze IDE dla Angular i dlaczego moim zdaniem jest to WebStorm</a><br />
2. <a href="http://danieldymek.blogspot.com/2017/04/hosting-aplikacji-angular-w-github-pages.html" target="_blank">Hosting aplikacji Angular w Github Pages</a><br />
3. <a href="http://danieldymek.blogspot.com/2017/03/jak-postawic-strone-w-angular-2-w-5.html" target="_blank">Jak postawić stronę w Angular 2 w 5 minut</a><br />
</li>
</ul>
<ul>
</ul>
<h3>
Projekt konkursowy</h3>
W ramach konkursu pisałem Portfel Emerytalny, czyli narzędzie do monitorowania oszczędzonych środków na emeryturę w produktach typu IKE i IKZE. Najważniejszy dla mnie jest fakt, że projekt finalnie powstał i można zobaczyć efekty mojej pracy - aplikacja jest dostępna pod adresem <b><a href="http://planujemeryture.pl/">planujemeryture.pl</a></b>. Co prawda jest to wersja demo, która prezentuje moje własne inwestycje, ale widać mniej więcej co chcę osiągnąć. W 3 miesiące udało się zbudować i skomunikować 4 filary, które tworzą cały produkt: interfejs użytkownika, API, bazę i automat pobierający dane.<br />
<br />
Ponownie kilka liczb:<br />
<ul>
<li><a href="https://github.com/thorin87/retirement-savings" target="_blank">30 commitów na GitHub</a></li>
<li>zaledwie 35 unikalnych odwiedzających (od 1 maja, bo wtedy pokazałem aplikację)</li>
<li>75 odsłon strony</li>
</ul>
W tej beczce miodu jest jednak łyżka dziegciu - czyli ostatni miesiąc prac nad projektem. Muszę powiedzieć wprost - zawaliłem. Z całego mojego planu na maj udało się wykonać jedynie 2 punkty, z czego tylko 1 programistyczny:<br />
<ol>
<li>założenie profilu <a href="http://fb.com/planujemeryture">fb.com/planujemeryture</a>, który ma służyć promocji Portfela Emerytalnego</li>
<li>uruchomienie automatu, który pobiera kursy funduszy inwestycyjnych i zapisuje je na potrzeby aplikacji</li>
</ol>
Profil na Facebooku do tej pory nie ma żadnego polubienia, ale zwalam to na fakt że nie ma tam żadnych treści - do tego też się nie przyłożyłem. Automat do napychania bazy danymi jest niezbędny żeby aplikacja pokazywała aktualne dane - szkoda jednak że nie udało się dodatkowo udostępnić możliwości "przeklikania" strony i wpisania własnych danych.<br />
<br />
<h3>
Co dalej?</h3>
Portfel Emerytalny będzie dalej rozwijany. W jednym z pierwszych postów pisałem, że jest to narzędzie przede wszystkim dla mnie, a ciągle daleko mu do spełnienia moich potrzeb. Mam do zaimplementowania resztę planów z maja i kroczący stop loss z powiadomieniami - jest co robić. Jeśli jesteś zainteresowany/a dalszym rozwojem aplikacji śledź tego bloga, <a href="http://fb.com/planujemeryture" target="_blank">profil aplikacji na FB</a> lub <a href="https://twitter.com/thorin87" target="_blank">mojego twittera</a>.<br />
<br />
Blog również będzie działał dalej, ale nowe posty na pewno będą pojawiały się rzadziej. Planuję pisać o tym jak przebiega rozwój moich projektów, pewnie też o programowaniu i ciekawych rozwiązaniach z tej dziedziny, może coś o oszczędzaniu i inwestowaniu. Sam jeszcze nie wiem dokładnie co, ale wiem że będę pisał - i tym pozytywnym planem kończę dzisiejszy wpis.Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com1tag:blogger.com,1999:blog-5647842092322999820.post-67635682204403245022017-05-28T21:15:00.001+02:002017-05-28T21:20:10.916+02:00Automat do pobierania kursów funduszy - 12 tydzień konkursu Daj Się Poznać<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxAh-rx3I-gGGvAmlYbnj2Jp9N4Kvbc6yFhskVoYFCF_aaTSITofBF9ZBiIJP4eUXbUDuIpvCrRqsAGG95l_-7lIGk0X3Ck2HH50kMQsp_XNb5Gx7Ka-UZuTPO8dKucJ72pXRNaeCZaKo/s1600/marketresearch_.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="396" data-original-width="400" height="197" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxAh-rx3I-gGGvAmlYbnj2Jp9N4Kvbc6yFhskVoYFCF_aaTSITofBF9ZBiIJP4eUXbUDuIpvCrRqsAGG95l_-7lIGk0X3Ck2HH50kMQsp_XNb5Gx7Ka-UZuTPO8dKucJ72pXRNaeCZaKo/s200/marketresearch_.png" width="200" /></a></div>
Witajcie! W tym tygodniu znowu publikuję tylko jednego posta i to dopiero w niedzielę. Na szczęście tym razem mogę napisać, że powstało sporo nowego kodu. Udało mi się dokończyć i uruchomić automatyczne pobieranie kursów funduszy Nationale-Nederlanden oraz ich zapis w bazie - oczywiście za pośrednictwem API. Zatem dziś krótko o tym rozwiązaniu.<br />
<br />
<a name='more'></a>Zalążek projektu DataDownloader powstał już ponad miesiąc temu, bo jeszcze w 7. tygodniu konkursu (<a href="http://danieldymek.blogspot.com/2017/04/raport-z-placu-boju-7-tydzien-dsp.html" target="_blank">zobacz wpis na blogu na ten temat</a>). Wtedy udało się przy jego pomocy pobrać plik JSON z danymi dla przykładowego funduszu i zapisać go na dysku. W tym tygodniu dopisałem:<br />
<ol>
<li>parsowanie tego pliku do kolekcji obiektów klasy <i>Rate</i>. Pojedynczy obiekt tej klasy reprezentuje wartość funduszu w konkretnej dacie. Docelowo wszystkie wyceny funduszy będą parsowane do tego właśnie formatu, co pozwoli na użycie wspólnego zapisu do API dla wszystkich pobranych danych. Do parsowania JSON użyłem jedynej słusznej paczki <a href="http://www.newtonsoft.com/json" target="_blank"><i>Newtonsoft.Json</i></a></li>
<li>wysłanie tak przygotowanych danych do API przy użyciu POST. Poza samym kursem funduszu wysyłany jest również sekretny token użytkownika z prawami administratora - inaczej każdy mógłby utworzyć nowe wartości kursu. Do obsługi RESTowych API w C# zawsze używam paczki <i><a href="http://restsharp.org/" target="_blank">RestSharp</a></i> i tak samo zrobiłem również tutaj.</li>
<li>obsługę wysłanego żądania po stronie API, czyli sprawdzenie czy token jest prawidłowy i ewentualne zapisanie pozostałych danych w bazie. Do zapisu do bazy musiałem przeiterować kolekcję par data wartość i utworzyć z nich zapytanie SQL. Następnie takie zapytanie jest wykonane przez bazę danych i API zwraca kod 201 z lokalizacją nowo zapisanych zasobów.</li>
</ol>
W trakcie prac pojawiły się 2 problemy z którymi musiałem sobie poradzić i o których chciałbym napisać coś więcej.<br />
<br />
Pierwszy dziwny problem dotyczył dat w wygenerowanym przez RestSharp JSONie. Zserializowane daty były o godzinę lub dwie wcześniej niż oryginalna - np. data 28.05.2017 00:00:00 stawała się 27.05.2017 23:00:00. Podejrzewam, że chodzi o przesunięcie <span class="st">względem czasu UTC, ale nie mogłem znaleźć jak zmusić standardowy serializer w <i>RestSharp </i>do serializacji 1:1. Pomogła zmiana serializera na jedyny słuszny, czyli ponownie <i>Newtonsoft.Json</i> (konkretnie użyłem paczki <i><a href="https://github.com/adamfisher/RestSharp.Newtonsoft.Json" target="_blank">RestSharp.Newtonsoft.Json</a></i>)</span><br />
<br />
<span class="st">Drugim problem było to, jak nie powielać już istniejących wartości kursów w bazie danych. Rozwiązaniem idealnym byłoby pobieranie ostatniej daty dla której mam wartość funduszu i wysyłanie do API jedynie późniejszych wartości. Na razie jednak takie rozwiązanie nie wchodziło w grę, bo same fundusze dla których pobieram wartość kursu są wpisane na sztywno w kod programu. Kiedy fundusze będą pobierane z API to będę mógł zwrócić również taką datę. Na razie jednak API za każdym razem dostaje pełny zestaw kursów dla każdego z funduszy, a o to żeby nie było powtórek w tabeli dba sama baza. Dzieje się tak dzięki indeksowi UNIQUE na kolumnach z datą i id funduszu (czyli dla każdego funduszu może być tylko jedna wartość w każdej z dat). Ostatnim i najważniejszym elementem tego rozwiązania jest samo zapytanie. Zamiast normalnego INSERT (które nie wykonuje się jeśli choć jeden z elementów zaburza unikalność) użyłem INSERT IGNORE - dzięki temu do bazy zostają dodane tylko takie elementy, których jeszcze nie ma w tabeli <i>Rate</i>.</span><br />
<span class="st"><br /></span>
<span class="st">Podsumowując prace nad tą częścią projektu wygląda na to, że automatyczne pobieranie kursów będzie największym i najbardziej skomplikowanym jego elementem. Moim zdaniem to dziwne, że tego typu dane nie są dostępne w postaci jakiegoś otwartego API dostarczonego przez każde TFI działające na rynku. W końcu są to dane publiczne, więc może kiedyś doczekam się prawa, które nakaże ich udostępnienie w postaci łatwej programistycznie. A jeśli nie to może sam takie zbuduję jak już będę miał parsery dla kilku towarzystw funduszy inwestycyjnych :)</span>Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-21640551699690374872017-05-20T10:51:00.000+02:002017-05-20T10:51:33.673+02:00InfoShare 2017 - moje przemyślenia i wnioski<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzAMPbUUV9I2LbSihFxHnYG6U7rqxW0ajztumm3XHmA-7HF7DWm68wUEd6DFFOBr_bRO9sRLiXSX7auTUgep_NNuj_0U85tgP24YR3-uG09VbwZ9kaOmdcHqjs86vL-W1KnPeCBmor424/s1600/infoshare.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzAMPbUUV9I2LbSihFxHnYG6U7rqxW0ajztumm3XHmA-7HF7DWm68wUEd6DFFOBr_bRO9sRLiXSX7auTUgep_NNuj_0U85tgP24YR3-uG09VbwZ9kaOmdcHqjs86vL-W1KnPeCBmor424/s200/infoshare.png" width="200" /></a></div>
Konferencja InfoShare jest stałym punktem na mojej corocznej mapie wydarzeń - nie mogło mnie więc tam zabraknąć również w tym roku. Za każdym razem wynoszę wiele cennej wiedzy z prezentacji, w których mam okazję tam uczestniczyć. Dziś chciałbym podzielić się kilkoma tematami które rezonują w mojej głowie po tegorocznej edycji.<br />
<a name='more'></a><br />
Najwięcej wartościowych rad usłyszałem na temat marketingu i budowania marki osobistej. W ramach projektu Portfela Emerytalnego staram się powoli ruszać z jego promocją, a o swój wizerunek w sieci dbam od dawna - stąd te tematy były dla mnie bardzo atrakcyjne. Konkretnie byłem na (dzielę się, bo prawdopodobnie pojawią się nagrania):<br />
<ul>
<li>Izabela Russell: You Can’t Hide - Online Presence For Entrepreneurs</li>
<li>Mark Schaefer: Content Code</li>
<li>Sujan Patel: How To Move Mountains: 9 Tactics to Build Your Personal Brand </li>
<li>Michał Szafrański: Skuteczna promocja niskim kosztem, czyli jak wydając 2069 zł wygenerowałem 2,35 mln zł przychodu - case study „Finansowy ninja”</li>
</ul>
Główne wnioski? Blog i tworzenie wartościowych treści to must have - ale koniecznie trzeba pozostać sobą i nie kreować się na kogoś innego. Nie można liczyć na szybkie rezultaty - blog zostaje szerzej zauważony dopiero po około roku, dwóch latach regularnego pisania. Facebook ma coraz mniejsze znaczenie w promocji, bo jedynie około 1% lubiących fanpage dostaje powiadomienia o nowych treściach na nim. Trzeba jednak gromadzić audytorium zainteresowane tym co oferujemy - lista mailingowa jest do tego bardzo dobra, może być też grupa na facebooku/slacku etc.<br />
<br />
Oczywiście było też to, co tygryski lubią najbardziej - czyli prezentacje techniczne i kod. Tutaj szczególnie chciałbym wyróżnić:<br />
<ul>
<li><b>Harry Roberts: Why Fast Matters</b><br />
Harry mówił o tym jak strony robią się coraz większe i cięższe. Nie jest to może problemem dla krajów Europy czy Ameryki Północnej, ale w krajach azjatyckich czy w Afryce mało kto ma szerokopasmowy internet. Tam króluje dostęp mobilny i to często jeszcze 2G. Generalnie o potrzebie spojrzenia też na tę część globu, jeśli budujemy produkt o zasięgu międzynarodowym. </li>
<li><b>Remy Sharp: The Art Of Debugging (browsers)</b><br />
Na tej prezentacji dostałem dużo wiedzy o zaawansowanych metodach debugowania aplikacji frontendowych bezpośrednio w przeglądarkach. W Chrome można na przykład podpiąć lokalne pliki bezpośrednio z dysku i edytować je bezpośrednio w narzędziach developerskich. W konsoli natomiast zamiast pisać selektory wybierające element z DOM można go zaznaczyć i użyć $0 (zaznaczony), $1 (następny element), $_ (ostatnio wyświetlony) itd.
</li>
<li><b>Felix Rieseberg: Desktop Apps with JavaScript</b><br />
Felix pracuje w Slacku nad rozwojem ich aplikacji desktopowej. Opowiadał o tym, jak przy pomocy Electron i JavaScript (lub TypeScript) można łatwo rozwijać takie aplikacje. Co więcej - jeśli mamy taką aplikację jako stronę, to przeportowanie jej na aplikację okienkową jest bardzo proste. Możemy wręcz wydzielić współdzielony kod i załatwić web i desktop za (prawie) jednym podejściem. Zdecydowanie warto zgłębić ten temat.
</li>
<li><b>Piotr Stapp: HTTP2 na ratunek wydajności</b><br />
HTTP/2 jest nową wersją HTTP, która naprawia wiele niedociągnięć i problemów z wersją 1.1. Okazuje się, że większość przeglądarek wspiera już HTTP/2, więc praktycznie nic nie stoi na przeszkodzie, żeby zacząć ją stosować. Jeśli więc zajmujesz się optymalizacją aplikacji webowych, to warto się lepiej przyjrzeć temu nowemu standardowi.
</li>
</ul>
<br />
Na zakończenie jeszcze jedno przemyślenie, a może nawet przepowiednia. Wierzę, że trendy powstają w takich miejscach jak infoShare. Słuchałem tego co się mówi o nowych technologiach, o tym co będzie ważne w najbliższym czasie. Na podstawie własnych odczuć i tego co usłyszałem prognozuję: sprzętowo - Virtual / Augmented Reality; marketingowo - komunikatory i boty oparte o nie. Obie rzeczy trzeba zaprogramować, więc planuję trochę rozeznać się w tych tematach, żeby być na bieżąco. Za rok sprawdzę na ile moje przepowiednie się sprawdzą :)Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-33534329611726270882017-05-16T07:09:00.000+02:002017-05-16T07:09:51.295+02:00Portfel Emerytalny - 11 tydzień konkursu Daj Się Poznać<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLJDgXP8695AAhbrM-uHf7geXP7HvM90oaE4MfzUFnNT_mR0VkMKlbzbn9cieYCpJy9GYtxMihBsjXCYpOZ8DsArueFWNu009gfsIIekcSkePHaIfK129S58SqMb0XYhEN4mHBVj4Uvxo/s1600/portfel_orange.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLJDgXP8695AAhbrM-uHf7geXP7HvM90oaE4MfzUFnNT_mR0VkMKlbzbn9cieYCpJy9GYtxMihBsjXCYpOZ8DsArueFWNu009gfsIIekcSkePHaIfK129S58SqMb0XYhEN4mHBVj4Uvxo/s200/portfel_orange.PNG" width="196" /></a></div>
Przyszedł czas na kolejny update co dzieje się z prowadzonym przeze mnie projektem. Niestety podobnie jak w ubiegłym tygodniu nie powstało za wiele kodu. Stali czytelnicy pewnie zauważyli też, że w ubiegły czwartek/piątek nie pojawił się drugi z cotygodniowych postów. To wszystko dlatego, że zrobiłem sobie mały urlop i nie miałem za wiele okazji do kodowania.<br />
<br />
Nie znaczy to jednak, że nie wydarzyło się zupełnie nic. Najważniejszą nowością jest <b>nowy adres pod którym jest dostępna aplikacja: <a href="http://planujemeryture.pl/" target="_blank">planujemeryture.pl</a></b>. Od teraz będzie to podstawowy adres aplikacji, jednak na razie utrzymuję ją również w tej samej wersji pod adresem <a href="https://thorin87.github.io/" target="_blank">thorin87.github.io</a> <br />
<br />
Równolegle wystartował również <b>fanpage na FB: <a href="https://www.facebook.com/planujemeryture" target="_blank">www.facebook.com/planujemeryture</a></b>. Na razie jest tam bardzo ubogo i nie ma nawet żadnego polubienia. Będę tam wrzucał aktualizacje co dzieje się z aplikacją, być może też co nieco o oszczędzaniu na emeryturę - jeśli temat jest dla Ciebie interesujący to zapraszam do "lajkowania".<br />
<br />
Blog też przeszedł drobne zmiany. Po prawej pojawiły się odnośniki do aplikacji Portfela Emerytalnego oraz do profili w mediach społecznościowych. Poza tym dodałem brakujące tłumaczenia elementów szablonu i kilka innych kosmetycznych poprawek.<br />
<br />
W samej aplikacji natomiast udało się popracować tylko nad automatem do pobierania danych, ale na razie bez efektów (jeszcze nie działa). Fundusze w bazie zyskały nowe pole <i>ExternalId </i>pod jakim są identyfikowane na stronach TFI, ale ze względu na małą ilość pozostałego do końca konkursu czasu na razie te <i>Id </i>zostaną wpisane na sztywno w kodzie automatu.Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-58350923506889211892017-05-08T19:05:00.002+02:002017-05-08T19:05:23.618+02:00Portfel Emerytalny - 10 tydzień konkursu Daj Się Poznać<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYGAuoNjFPOFoHeFa-dhuUZfBumpEV4fQ9uzouRayPU2cHS4voCsIXdpA8kIEAprafcUSOPOx-xAWoCNBu-jFXdkZ1Ac3nbU0pi8kpj_6RCFJ_tgiXOTEHSWgThgD798v1vlispOFv9x8/s1600/portfel_orange.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYGAuoNjFPOFoHeFa-dhuUZfBumpEV4fQ9uzouRayPU2cHS4voCsIXdpA8kIEAprafcUSOPOx-xAWoCNBu-jFXdkZ1Ac3nbU0pi8kpj_6RCFJ_tgiXOTEHSWgThgD798v1vlispOFv9x8/s200/portfel_orange.PNG" width="196" /></a>Cześć! Zapraszam na cotygodniowe podsumowanie tego, co dzieje się z moim <a href="https://thorin87.github.io/" target="_blank">projektem konkursowym</a>.<br />
<br />
W tym tygodniu nie udało się napisać zbyt wiele kodu, ale przemyślałem jak zoptymalizować zapytanie do bazy, które zwraca dane potrzebne do wyświetlenia wykresu. Będzie sporo przetwarzania wyników z bazy po stronie backendu, ale jednocześnie zapewnię możliwość wyboru, które fundusze są prezentowane na wykresie. Zacząłem już nawet zapisywać co wymyśliłem, ale na razie skończyło się na zakomentowaniu wszystkiego. Zapytanie które jest teraz zwraca dokładnie czego potrzebuję, więc jego optymalizacją zajmę się w przyszłości. <br />
<br />
Kolejną rzeczą którą poprawiłem jest format JSON zwracany jako odpowiedź na zapytania do API. Wcześniej każdy wiersz wyniku był zwracany jako tablica, a teraz jest to obiekt z nazwami kolumn z zapytania. Czyli było tak:<br />
<pre><code>{
"data": [
[
1,
"IKE",
"IKE Plus",
"NN Investment Partners TFI S.A.",
"Towarzystwo funduszy inwestycyjnych"
],
[
2,
"IKZE",
"Dobrowolny Fundusz Emerytalny PZU",
"PTE PZU SA",
"Powszechne towarzystwo emerytalne"
]
]
}</code></pre>
a teraz jest tak:
<br />
<pre><code>{
"data": [
{
"Id": 1,
"Name": "IKE",
"Owner": "NN Investment Partners TFI S.A.",
"OwnerType": "Towarzystwo funduszy inwestycyjnych",
"ProductName": "IKE Plus"
},
{
"Id": 2,
"Name": "IKZE",
"Owner": "PTE PZU SA",
"OwnerType": "Powszechne towarzystwo emerytalne",
"ProductName": "Dobrowolny Fundusz Emerytalny PZU"
}
]
}</code></pre>
Po tej zmianie mogłem we frontendzie zmienić nic nie mówiące wywołania w stylu <i>wallet[1]</i> na opisowe <i>wallet.Name</i>. Dodałem też kilka klas (a konkretnie interfejsów) modelu we frontendzie, dzięki czemu do tego będzie działało jeszcze podpowiadanie składni dla tych obiektów.<br />
<br />
To tyle jeśli chodzi o ubiegły tydzień, mam nadzieję że kolejny będzie bardziej obfity w nowy kod i funkcjonalności.Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-44345281436144332412017-05-06T17:28:00.000+02:002017-05-06T17:31:11.795+02:00Portfel Emerytalny - podsumowanie kwietnia<img border="0" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqM5ITsSSvlldMB5t1yddYTXhP5mopeOTi5IxVJzYjDVzlWRbZPR1KdUJRchz8wJ6LjvwgiOigEx0y86Q6eEq1mwaEYRUiF4CdnQToN7hMmMpjhtr77qY8XFuHWD6z85xRgFxJE0bvQtE/s200/podsumowanie.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;" width="200" />
Upłynął kolejny miesiąc konkursu Daj Się Poznać, pora więc na podsumowanie co się zmieniło i jaki jest teraz stan aplikacji Portfela Emerytalnego. Tym razem dużo łatwiej robić mi takie zestawienie, bo mam cotygodniowe raporty ze zmianami oraz listę celów, które wyznaczyłem sobie na kwiecień. Skonfrontuję je zatem ze sobą, poza tym zaplanuję co będę robił w maju.<br />
<br />
Plan na kwiecień był podzielony na 3 główne obszary: aplikacja, promocja, blog. W trakcie miesiąca plan ten przeszedł drobną metamorfozę - aplikacja została zmieniona na tryb tylko do odczytu, o czym pisałem w <a href="http://danieldymek.blogspot.com/2017/04/raport-z-placu-boju-8-tydzien-konkursu.html" target="_blank">podsumowaniu 8. tygodnia</a>. Głównym celem w obszarze aplikacji było opublikowanie Portfela Emerytalnego online, co udało się osiągnąć - efekt można zobaczyć na <a href="https://thorin87.github.io/" target="_blank">https://thorin87.github.io/</a>. Nie byłoby to jednak możliwe, gdybym chciał zrealizować wszystkie punkty z tego obszaru - stąd właśnie decyzja o rezygnacji z możliwości wprowadzania własnych danych. A co dokładnie udało się wykreślić z listy?<br />
<ul>
<li><strike>znaleźć i wdrożyć layout interfejsu użytkownika</strike></li>
<li><strike>zapisać w bazie kursy wszystkich funduszy których jednostki posiadam
lub posiadałem</strike> (idealnie gdyby działał już automat aktualizujący dane)</li>
<li>zaimplementować operacje związane z portfelem inwestycji (kupno, sprzedaż, zamiana)</li>
<li><strike>uzupełnić portfel o historyczne operacje które wykonywałem</strike></li>
<li><strike>wyświetlać listę posiadanych jednostek funduszy</strike> </li>
<li>prezentować historię operacji</li>
<li><strike>wyświetlać wykresy wartości posiadanych walorów</strike> (idealnie gdyby zaznaczały się na nim operacje z historii)</li>
<li><strike>wyświetlać procentowy zysk/stratę ze wszystkich inwestycji</strike> (idealnie byłoby gdyby dało się wybrać z których)</li>
</ul>
Jak widać udało się zrealizować całkiem sporą część planu, a to czego nie udało się zrobić zostanie przeniesione na plan majowy - ale o tym za chwilę.<br />
<br />
Zrezygnowałem też na razie z promocji na Facebooku. Uznałem, że skoro mam zakładać profil produktu, to lepiej będzie jeśli Portfel Emerytalny będzie już dostępny w sieci - przynajmniej w podstawowej wersji. Teraz już jest, więc profil na FB to kolejna rzecz która przechodzi na listę rzeczy do zrobienia w maju.<br />
<br />
Ostatni obszar kwietniowego planu to zmiany na blogu. Ten punkt udało się wdrożyć w całości, co tydzień pojawiał się jeden post o zmianach w projekcie i jeden o tematyce bardziej ogólnej. Niestety nie udało się utrzymać regularnych publikacji w poniedziałki i czwartki, jednak ostatecznie w każdym z tygodni pojawiły się 2 posty i tego chcę się trzymać.<br />
<br />
<h3>
Plan na maj</h3>
W chwili pisania tego posta zostały jedynie 3 pełne tygodnie maja. Jeśli plan ma być realny, to nie mogę zakładać zbyt wiele rzeczy do zrobienia. Jak już pisałem na pewno chcę założyć profil Portfela Emerytalnego na Facebooku. Jeśli zaś chodzi o samą aplikację, to poniżej prezentuję listę funkcjonalności, które chciałbym żeby pojawiły się w maju:<br />
<ul>
<li>uruchomić automat aktualizujący dane dla funduszy, których jednostki posiadam (dodatkowo zrobić research którymi funduszami zająć się później)</li>
<li>dokończyć profile użytkowników oparte o tokeny </li>
<li>dodać możliwość dodania do profilu portfeli IKE i IKZE</li>
<li>zaimplementować operacje w konkretnym portfelu (kupno, sprzedaż, zamiana jednostek uczestnictwa)</li>
<li>prezentować historię operacji w portfelach</li>
<li>dodać wybór, które fundusze są prezentowane na wykresie </li>
<li>zaznaczać na wykresie operacje z historii</li>
</ul>
Do pełni założonej na początku funkcjonalności będzie brakowało jeszcze analizy kursu funduszy przez kroczący stop loss i powiadomień o jego osiągnięciu. Patrząc na dotychczasowe tempo rozwoju prawdopodobnie nie uda się osiągnąć tego w maju. Wydaje mi się jednak, że ważniejsze jest udostępnienie możliwości zakładania własnych portfeli. Kroczący stop loss będzie zatem zaimplementowany w kolejnej wersji aplikacji, bo wierzę że rozwój Portfela Emerytalnego nie skończy się razem z końcem konkursu.<br />
<ul>
</ul>
Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-6259254269134565532017-05-02T10:26:00.002+02:002017-05-02T10:26:21.755+02:00Portfel Emerytalny jest już online - 9 tydzień konkursu Daj Się Poznać <div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHYtneZKwmgxT4oNNwMo4cMkpkoNV2HndBTfmLHxn4nchMuStl4OwtiZwBGKwgx0u_sWJcVVMKZEVnO_dKOVB0ZmCqhDbQ4aiejatSztVF4P5-vNCecV0pg_u3J4B9sHEwpz-9Gxb46Sg/s1600/1493671825_Web_Design.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHYtneZKwmgxT4oNNwMo4cMkpkoNV2HndBTfmLHxn4nchMuStl4OwtiZwBGKwgx0u_sWJcVVMKZEVnO_dKOVB0ZmCqhDbQ4aiejatSztVF4P5-vNCecV0pg_u3J4B9sHEwpz-9Gxb46Sg/s200/1493671825_Web_Design.png" width="200" /></a></div>
Ostatni tydzień rozwoju aplikacji był poświęcony jednemu celowi - spiąć wszystkie warstwy ze sobą i wystawić je online. Co prawda z małym opóźnieniem, ale cel udało się osiągnąć. Z przyjemnością zatem informuję, że aplikacja Portfela Emerytalnego jest już dostępna online pod adresami:<br />
<a href="https://thorin87.github.io/" target="_blank">https://thorin87.github.io/</a> oraz<br />
<a href="https://thorin87.github.io/retirement-savings/" target="_blank">https://thorin87.github.io/retirement-savings/</a><br />
<br />
Główne wyzwania jakie stanęły na drodze, to wydajne zapytanie do bazy o dane na potrzeby wykresu oraz problemy ze zbudowaniem wersji produkcyjnej frontendu.<br />
Zapytanie do bazy niestety ciągle pozostawia wiele do życzenia (czas wykonania ~3s), ale zwraca dokładnie to czego potrzebuję. Przyjdzie jeszcze czas na jego optymalizację, na razie zostaje tak jak jest. Do tego drugiego problemu szczególnie przyłożył się moduł <i>angular2-highcharts</i> i błąd<br />
<blockquote class="tr_bq">
Error encountered resolving symbol values
statically. Calling function 'ChartModule', function calls are not
supported. Consider replacing the function or lambda with a reference to
an exported function</blockquote>
wywołany przez poniższą linię w module aplikacji<br />
<blockquote class="tr_bq">
ChartModule.forRoot(require('highcharts/highstock'))</blockquote>
Jak rozwiązać ten problem? Odsyłam do <a href="https://github.com/thorin87/retirement-savings/commit/bc662624b0df4795ae62025502b92bc4f839b42c#diff-6705bbd7da1c05c9e0aa9f97e5ffe204" target="_blank">mojego kodu na GitHub</a> lub do <a href="https://github.com/gevgeny/angular2-highcharts/issues/156" target="_blank">oficjalnego issue założonego dla tego problemu.</a><br />
<br />
Pozostałe zmiany we frontendzie to:<br />
<ol>
<li>wyłączenie Routingu (na razie go nie potrzebuję, cała aplikacja jest single page)</li>
<li>wydzielenie adresu API do plików konfiguracyjnych (projekt wygenerowany z angular-cli od ręki obsługuje oddzielne pliki konfiguracyjne dla środowiska deweloperskiego i produkcji)</li>
<li>wydzielenie modułu dla kart z podsumowaniem wyświetlanych na początku strony </li>
<li>pobieranie i wyświetlanie danych z API (karty podsumowania, wykres i portfele)</li>
<li>sporo drobnych poprawek i usuwania niepotrzebnych fragmentów kodu</li>
</ol>
Baza również przeszła drobną zmianę, ponieważ zupełnie bez sensu było trzymanie dat operacji kupna i sprzedaży zasobu (asset) w jednym wierszu. Teraz jest jedna data OperationDate i ewentualnie ilość jest mniejsza od zera, jeśli jest to sprzedaż.<br />
<br />
W API też sporo zmian, ale bez rewolucji. Głównie są to poprawione lub rozszerzone już istniejące zapytania do bazy. Pojawiły się też 2 nowe metody - pobieranie danych do wykresu i podsumowania - ale opierają się o ten sam schemat, czyli wywołaj zapytanie i zwróć jego wynik jako JSON bez większej obróbki.<br />
<br />
Jeszcze w tym tygodniu pojawi się podsumowanie całego miesiąca pracy i jej efektów, a także plan na ostatni już miesiąc konkursu. Zapraszam też do śledzenia mnie na <a href="https://twitter.com/thorin87" target="_blank">Twitterze</a>, gdzie pojawia się info o każdym nowym wpisie na blogu.Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-7199883787729424742017-04-27T08:07:00.001+02:002017-04-27T08:13:18.733+02:00Hosting aplikacji Angular w Github Pages<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwWrPMh3p9z0yc9r3AAXe0JM5gAFe6LcI8jfpDVhUvb0NjkpIz90klo9FjfgtRJpNa6XlMeANN5Qa8n-ly_p9mRggsobP13vOROjRuFTSnWk2JUpatFH7xMvUtVC7tp01obN6crJhEsQ0/s1600/github-256-black.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwWrPMh3p9z0yc9r3AAXe0JM5gAFe6LcI8jfpDVhUvb0NjkpIz90klo9FjfgtRJpNa6XlMeANN5Qa8n-ly_p9mRggsobP13vOROjRuFTSnWk2JUpatFH7xMvUtVC7tp01obN6crJhEsQ0/s200/github-256-black.png" width="200" /></a></div>
Dziś o tym, jak można za darmo opublikować stronę napisaną w Angular (a tak naprawdę każdą statyczną stronę) przy użyciu infrastruktury GitHub. Tytułowe <a href="https://pages.github.com/" target="_blank">GitHub Pages</a> to po prostu kolejne repozytorium gita, które zakładamy w serwisie, a jego zawartość jest prezentowana jako strona w domenie <i>github.io</i>.<br />
<a name='more'></a><br />
<h3>
GitHub</h3>
Strona którą chcemy opublikować może być prezentowana pod adresem <br />
(1) <i>nazwa_uzytkownika.github.io</i> lub <br />
(2) <i>nazwa_uzytkownika.github.io/nazwa_repozytorium</i>.<br />
Od tego którą opcję wybierzemy zależy dalsza konfiguracja.<br />
W przypadku opcji 1 musimy założyć nowe repozytorium o dokładnie takiej nazwie jak podany wyżej adres. Ja najpierw wybrałem tę opcję, więc założyłem <a href="https://github.com/thorin87/thorin87.github.io" target="_blank">repozytorium thorin87.github.io</a>. W tej opcji robimy push plików ze stroną do brancha <b>master </b>nowo założonego repo i po maksymalnie kilku minutach strona powinna już działać.<br />
W opcji 2 mamy już repozytorium (znowu na moim przykładzie - <a href="https://github.com/thorin87/retirement-savings" target="_blank">retirement-savings</a>). Na potrzeby opublikowania strony musimy zatem stworzyć branch o nazwie <b>gh-pages</b> i tam umieścić pliki html, js, css itd. które tworzą naszą stronę.<br />
<br />
<h3>
Publikacja</h3>
W internecie można znaleźć mnóstwo opisów jak przy pomocy Angular CLI i komendy<br />
<pre><code class="bash">ng github-pages:deploy</code></pre>
można uprościć cały proces build i deploy. Problem w tym, że <a href="https://github.com/angular/angular-cli/pull/4385" target="_blank">ta komenda została usunięta 3 lutego</a> i teraz po jej wydaniu dostajemy tylko komunikat<br />
<blockquote class="tr_bq">
The specified command github-pages:deploy is invalid.</blockquote>
Na szczęście internet nie znosi próżni i jest już paczka, która zastępuje brakującą komendę: <a href="https://github.com/angular-buch/angular-cli-ghpages" target="_blank">angular-cli-ghpages</a><br />
Instaluję więc paczkę i buduję projekt:<br />
<pre><code class="bash">npm i -g angular-cli-ghpages
ng build --prod</code></pre>
Pozostało wysłanie wyniku na serwer, w zależności od tego opcji wybranej w pierwszej części będzie to
<br />
<pre><code class="bash">ngh --repo=https://GH_TOKEN@github.com/thorin87/thorin87.github.io.git --branch=master</code></pre>
lub
<br />
<pre><code class="bash">ngh --repo=https://GH_TOKEN@github.com/thorin87/retirement-savings.git</code></pre>
GH_TOKEN obecny w adresach repozytorium to token dostępowy GitHub, który możemy wygenerować tutaj: <a href="https://github.com/settings/tokens/new" target="_blank">https://github.com/settings/tokens/new</a> (w tym wypadku potrzebne jest zaznaczenie scope repo). Oczywiście dla swoich potrzeb musisz podmienić również nazwę użytkownika i nazwę repozytorium w adresach.<br />
<br />
To wszystko! Rezultat w przypadku mojej makiety frontendu można zobaczyć pod adresem <a href="http://thorin87.github.io/" target="_blank">thorin87.github.io</a> oraz <a href="https://thorin87.github.io/retirement-savings" target="_blank">https://thorin87.github.io/retirement-savings</a>.
Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-24849414329152063872017-04-24T08:11:00.000+02:002017-04-24T08:17:08.826+02:00Raport z placu boju - 8 tydzień konkursu Daj Się Poznać <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPzGOkzDyDq_z-PRWQRUTHezc4lhQZMpb400vOBoagfo3LTQ9nA1D5ioijsghOKZedP8_QIPcJy1sib4OCzaM4t4p1mBFxYV8VCuRvL3EkkRzu-zjO5nR7Q3l3mPUdDSrHxSpEMJH_dC0/s1600/baza+v1.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="120" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPzGOkzDyDq_z-PRWQRUTHezc4lhQZMpb400vOBoagfo3LTQ9nA1D5ioijsghOKZedP8_QIPcJy1sib4OCzaM4t4p1mBFxYV8VCuRvL3EkkRzu-zjO5nR7Q3l3mPUdDSrHxSpEMJH_dC0/s200/baza+v1.PNG" width="200" /></a>Mija kolejny tydzień konkursu Daj Się Poznać, pora zatem na raport co się dzieje z aplikacją Portfela Emerytalnego. Poprzedni raport wypadał prawie dokładnie w środku kwietnia i po jego napisaniu zostały 2 tygodnie miesiąca, sprawdziłem więc jak idzie realizacja <a href="http://danieldymek.blogspot.com/2017/03/podsumowanie-pierwszego-miesiaca-dsp-i.html" target="_blank">listy moich planów</a> na ten miesiąc. Wniosek był prosty - niestety nie dam rady zrobić wszystkiego co zaplanowałem. Więcej o tym będzie w podsumowaniu całego miesiąca, ale w tym tygodniu pozwoliło mi to podjąć decyzję, że na razie skupiam się tylko na odczycie danych.<br />
<br />
Aplikacja w trybie read-only będzie prezentowała to co ma zapisane w bazie, ale bez możliwości zmiany czy dodania kolejnych informacji. Skoro zatem zrezygnowałem na razie m.in. z możliwości dodawania portfeli i operacji w portfelach, to musiałem dodać je ręcznie bezpośrednio w bazie danych. Spisanie kilku moich zakupów z systemów transakcyjnych TFI nie było większym problemem, ale myślę, że kiedyś będzie musiała się pojawić opcja importu danych. Dodawanie kilkudziesięciu operacji nawet przez najwygodniejszy interfejs może skutecznie zniechęcić do użycia Portfela Emerytalnego. <br />
Oprócz uzupełnienia stanu portfela dodałem też wszystkie fundusze prowadzone przez moich dostawców IKE i IKZE oraz kursy funduszy, które posiadam lub posiadałem. Dzięki temu baza jest już gotowa do policzenia wartości wszystkich moich funduszy w czasie.<br />
<br />
Utworzyłem też strukturę, która będzie przechowywała dane o dostawcach produktów emerytalnych oraz samych produktach które oferują. Strukturę tworzą 3 tabele:<br />
<ol>
</ol>
<ol>
<li><i>FinancialInstitutionType </i>- rodzaj instytucji finansowej, na początek są to
<ul>
<li>Towarzystwa funduszy inwestycyjnych (TFI)</li>
<li>Powszechne towarzystwa emerytalne (PTE)</li>
</ul>
<pre><code class="sql">CREATE TABLE `FinancialInstitutionType` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`Code` varchar(10) NOT NULL,
`Name` varchar(250) NOT NULL,
PRIMARY KEY (`Id`)
)</code></pre>
</li>
<li><i>FinancialInstitution </i>- instytucje finansowe prowadzące IKE lub IKZE, przykładowo NN Investment Partners TFI S.A. lub PTE PZU SA<br /><pre><code class="sql">CREATE TABLE `FinancialInstitution` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(250) NOT NULL,
`TypeId` int(11) NOT NULL,
PRIMARY KEY (`Id`)
)</code></pre>
</li>
<li><i>InvestmentProduct </i>- w tej tabeli znajdą się konkretne produkty IKE i IKZE, które można założyć. Przykładowo będzie to IKE Plus prowadzone przez wymienione wcześniej NN TFI<pre><code class="sql">CREATE TABLE `InvestmentProduct` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(250) NOT NULL,
`Type` varchar(10) DEFAULT NULL,
`FinancialInstitutionId` int(11) NOT NULL,
PRIMARY KEY (`Id`)
)</code></pre>
</li>
</ol>
Poza dodanymi wierszami i nowymi tabelami pojawiło się również kilka kosmetycznych zmian. Są to np. zmiana pierwszych liter w nazwach tabel na duże i dodanie w tabeli <i>Fund </i>do jakiego <i>InvestmentProduct </i>należy. Tabela <i>Wallet </i>również dostała pole <i>InvestmentProductId</i>, ale tutaj będzie ono mogło być NULLem - do portfela można będzie dodać też np. gotówkę, która nie jest związana z żadnym produktem inwestycyjnym.<br />
<br />
Mam nadzieję, że to koniec zmian i uzupełniania bazy, bo pora w końcu zabrać się za wyświetlanie tych wszystkich danych w interfejsie użytkownika - i to jest plan na najbliższy tydzień.Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-88960571860402682362017-04-20T07:37:00.002+02:002017-04-20T07:40:14.065+02:00Jakie jest najlepsze IDE dla Angular i dlaczego moim zdaniem jest to WebStorm<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1q2CCdTaH6XPhXhEHbyeRcXxtST_yLKEDXfX13tXe3HdKHt8Oz7olZzzKhRVKnZrPz7KLV7z_kUdqDH0SbNS5RaamvVh1V2u1D0IZ_VrBUnpxPDEb3ffQm6-bVTysptwktaems5Pa9Vw/s1600/webstorm+logo.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1q2CCdTaH6XPhXhEHbyeRcXxtST_yLKEDXfX13tXe3HdKHt8Oz7olZzzKhRVKnZrPz7KLV7z_kUdqDH0SbNS5RaamvVh1V2u1D0IZ_VrBUnpxPDEb3ffQm6-bVTysptwktaems5Pa9Vw/s200/webstorm+logo.png" width="200" /></a></div>
Chyba każdy programista lubi i potrzebuje dobrego środowiska <span class="st">programistycznego</span>. Oczywiście pisać kod można nawet w notatniku i też będzie działało, ale zdecydowanie nie jest to produktywna droga. Dziś będę chwalił oprogramowanie ze stajni JetBrains - tytułowy WebStorm, który zdecydowanie wspomaga pracę i zwiększa tempo rozwoju aplikacji.<br />
<a name='more'></a><br />
Angular (i generalnie frontend) pojawił się w moim życiu zawodowym całkiem niedawno. Wchodząc do tego nowego świata szukałem przyjaznego IDE. Zacząłem od <a href="https://code.visualstudio.com/" target="_blank">Visual Studio Code</a>, sprawdziłem <a href="https://www.genuitec.com/products/angular-ide/" target="_blank">Angular IDE</a>, ale to <a href="https://www.jetbrains.com/webstorm/" target="_blank">WebStorm</a> zdobył moją miłość. Wiele funkcji tych 3 edytorów się pokrywa, każdy z nich ma niezbędne podstawy i każdy wystarczy do niewielkiego projektu. Dlatego dziś:<br />
<br />
<h4>
Co zaoferował WebStorm czego nie mają inni</h4>
<ol>
<li>nawigacja z widoków bezpośrednio do komponentu 💗- zarówno jeśli chodzi o całe selektory, ich inputy oraz outputy i w zasadzie wszystkie elementy dla których logiczne będzie nawigowanie do innego pliku<br /><div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4CnQaRMOeniCSHgKaDAl6dv0r3hucgu7wIEHs7GTI8ewJ4-vt-8BM4TMDrk5twPwZYPRyx4RINS69YtuxWAl181ydCoiln3dwl625GDohlTb-IQ_NE9DwX728ElK5l3ECJ_cQlsZgdLI/s1600/webstorm+navigation.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4CnQaRMOeniCSHgKaDAl6dv0r3hucgu7wIEHs7GTI8ewJ4-vt-8BM4TMDrk5twPwZYPRyx4RINS69YtuxWAl181ydCoiln3dwl625GDohlTb-IQ_NE9DwX728ElK5l3ECJ_cQlsZgdLI/s1600/webstorm+navigation.gif" /></a></div>
</li>
<li>nawigacja z komponentu do plików html i css - analogicznie w drugą stronę, kiedy mamy podpięty do komponentu template i style
<pre><code class="javascript">@Component({
selector: 'home-cmp',
templateUrl: 'home.component.html',
styleUrls: ['./home.component.css']
})</code></pre>
to można nawigować bezpośrednio do tych plików z ich nazw
</li>
<li>analiza package.json i możliwość szybkiego wystartowania znalezionych skryptów - w komercyjnym projekcie który rozwijam komendy do startu aplikacji są dosyć długie, tutaj wystarcza dwuklik myszką i projekt się uruchamia<br /><div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbZmd70odNQ5yh5sqB5DJegAV7Dn5k-XffgWRzFb5pS9fin4KAcY0KnQ7VkVOo8MofpiQmwKygo8DitXTQg2QNtBpf2okcXn9OdYzd4obk1LTwSLXHIAcnFUvsYXCIsq7Put3l4zIHxLE/s1600/webstorm+packagejson.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbZmd70odNQ5yh5sqB5DJegAV7Dn5k-XffgWRzFb5pS9fin4KAcY0KnQ7VkVOo8MofpiQmwKygo8DitXTQg2QNtBpf2okcXn9OdYzd4obk1LTwSLXHIAcnFUvsYXCIsq7Put3l4zIHxLE/s1600/webstorm+packagejson.PNG" /></a></div>
</li>
<li>oznaczanie nieużywanych importów <div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYz7Mq8cNHJTpN7fOih1Q_SyXyNL2_MRNUSUib6vAtl7bo0T-57m_6iu0KWnzuVroYxRYC8V5ZiazobPy1WfyZMC8C9KPAGxEPEUPbRqM0eOj1rx_Bh6q54cX2jxi7bNIAN5ZOIPkPa-U/s1600/webstorm+import.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYz7Mq8cNHJTpN7fOih1Q_SyXyNL2_MRNUSUib6vAtl7bo0T-57m_6iu0KWnzuVroYxRYC8V5ZiazobPy1WfyZMC8C9KPAGxEPEUPbRqM0eOj1rx_Bh6q54cX2jxi7bNIAN5ZOIPkPa-U/s1600/webstorm+import.PNG" /></a></div>
</li>
</ol>
Takich funkcji na pewno znalazłoby się więcej, wymieniłem te które najbardziej przydają się w mojej codziennej pracy.<br />
<br />
Jedyny minus? WebStorm kosztuje około 300zł za roczną subskrypcję. W kontekście użycia go w pracy zarobkowej przestaje to mieć znaczenie, ale pewnie nie kupiłbym go tylko do użycia w jakimś pet-projekcie.<br />
<br />
Zatem jeśli szukasz IDE do Angular czy innego projektu w TypeScript lub JavaScript i jeszcze nie znasz WebStorm, to polecam spróbowanie - można testować za darmo przez 30 dni.Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com4tag:blogger.com,1999:blog-5647842092322999820.post-37684195670684722752017-04-17T13:27:00.002+02:002017-04-17T13:27:32.767+02:00Raport z placu boju - 7 tydzień DSP<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLEqaj4bNFW8RFkO6TU__-XM9TWl8glMJWa3ck1qHba8_m4HXeuBzKP8TVNn7DJZgFQ21Y3wElV7ek_S9XMElZ48C9zdsBqLHy3Z47UFnvOE6Z_2NXMnaLwpm36aKQFMcVqbzQT6BKWc8/s1600/IMAG0068+%25282%2529.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLEqaj4bNFW8RFkO6TU__-XM9TWl8glMJWa3ck1qHba8_m4HXeuBzKP8TVNn7DJZgFQ21Y3wElV7ek_S9XMElZ48C9zdsBqLHy3Z47UFnvOE6Z_2NXMnaLwpm36aKQFMcVqbzQT6BKWc8/s200/IMAG0068+%25282%2529.jpg" width="200" /></a>Upłynął kolejny tydzień, więc pora na raport co z moim projektem konkursowym.<br />
<br />
Ostatnio pisałem, że nie mogę dodać operacji w API które modyfikują bazę, dopóki nie będę mógł w jakiś sposób uwierzytelniać i autoryzować użytkowników. Naturalnie otwierałoby to możliwość zmian każdemu użytkownikowi w każdym portfelu. Nie chciałem pisać całego modułu użytkowników, logowanie przez Facebook czy innego dostawcę też wydawało się czasochłonne jak na potrzeby prostego demo do którego dążę. Zdecydowałem się na tymczasowe rozwiązanie w postaci tokenów. Założenie tego rozwiązania są następujące:<br />
<ul>
<li>użytkownik odwiedza stronę bez tokena - dostaje informację o projekcie, być może wyświetla mu się przykładowy portfel</li>
<li>użytkownik bez tokena robi akcję na stronie (np. założenie swojego portfela) - jest generowany dla niego token, który zostaje dopisany do adresu url strony</li>
<li>użytkownik odwiedza stronę z tokenem w url - widzi swój portfel</li>
</ul>
System jest prosty (można by nawet powiedzieć, że prostacki), ale spełni swoje zadanie na ten moment. Jest otwarty na udoskonalenia (np. token można zapisać w cookie zamiast url), po dodaniu innego systemu uwierzytelnienia można go łatwo zintegrować z nowym rozwiązaniem. No i najważniejsza jego zaleta - mieści się w kilku liniach kodu<br />
<pre><code class="python">@app.route("/token", methods=['GET', 'POST'])
def token():
if request.method == 'POST' and 'token' in request.json:
query = "INSERT INTO user (Token, Admin) VALUES ('{0}', 0)"
query = query.format(request.json['token'])
try:
insertedId = insertToDb(query)
return jsonify(userid=insertedId, error=None)
except:
error = "Error: unable to insert token"
return jsonify(userid=None, error=error)
else:
return jsonify(token=uuid.uuid4())
def insertToDb(query):
cursor = mysql.connection.cursor()
cursor.execute(query)
mysql.connection.commit()
return cursor.lastrowid</code></pre>
<br />
Drugą zmianą z ubiegłego tygodnia jest pojawienie się serwisu, który ma automatycznie pobierać i zapisywać kursy funduszy inwestycyjnych. Tydzień temu wspomniałem, że udało mi się znaleźć na stronie TFI Nationale-Nederlanden adres pod jakim są dostępne pliki json z potrzebnymi mi danymi. Dodany przeze mnie do projektu <a href="https://github.com/thorin87/retirement-savings/tree/master/retirement-savings-data-downloader" target="_blank">DataDownloader</a> wykorzystuje te właśnie adresy i dla trzech przykładowych funduszy pobiera i zapisuje pliki z wartościami funduszy w czasie. Do zrobienia pozostaje interpretacja tych danych i wysłanie ich do zapisu do API, a kolejne kroki to dodanie pobierania dla innych TFI. Nie wiem jednak od jakich zacząć, więc daj proszę znać w komentarzu pod tym postem na jakich funduszach by Ci zależało.Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-27445669472954214452017-04-14T08:06:00.001+02:002017-04-14T08:09:40.310+02:00Jak oszczędzać na emeryturę?<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhohV-jdhGPXuqtlpIYpqE87RgwKsozoENIBJU853w2nSCjQ8ZLHe3qqAH__yt6RJxzewuOp7gjeOtcuG21t14eNqf8qfOyoZYGzxau0LQaX8uKOKz02LBzmja4G1JqMAvLyJYBul2zXVA/s1600/skarbonka.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhohV-jdhGPXuqtlpIYpqE87RgwKsozoENIBJU853w2nSCjQ8ZLHe3qqAH__yt6RJxzewuOp7gjeOtcuG21t14eNqf8qfOyoZYGzxau0LQaX8uKOKz02LBzmja4G1JqMAvLyJYBul2zXVA/s200/skarbonka.jpg" width="200" /></a></div>
Kolejny raz opóźnia się mój założony cykl wydawniczy i znowu publikuję z jednodniowym poślizgiem. Nie wiem czy są tu jacyś czytelnicy, którzy co poniedziałek i czwartek ze zniecierpliwieniem odświeżają stronę w oczekiwaniu na posta - jeśli są to przepraszam za tę sytuację. Postaram się poprawić :) Do rzeczy jednak. Dziś chciałbym poruszyć temat rzekę - czyli jak oszczędzać na emeryturę.<br />
<br />
Ale zanim o tym <b>jak oszczędzać</b>, to najpierw odpowiem na pytanie <b>czy oszczędzać</b> i <b>dlaczego</b>. Jeśli czytasz ten artykuł to prawdopodobnie wiesz już, że oszczędzać na emeryturę należy. W mediach zaczęło się o tym mówić, pojawiają się reklamy o młodych bogach itd. Wydaje mi się, że obecni 20-30-40 latkowie mają świadomość tego, jak będą wyglądały ich emerytury z ZUS - szczególnie w kontekście ostatniego obniżenia wieku emerytalnego. Jeśli jednak ktoś ma jeszcze jakieś wątpliwości, to polecam uważne przyjrzenie się poniższemu wykresowi<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZRW0k-aL-weGFBnZw3DHW4GeZnLdeJcoyNplXAzFV6pJfF06dW8hyORIHRjvB3MHWnop9uh37Q7To8l5iG-xYdoqFxC6myqi5_SnloCIEfqvFAUqjRyMCn5cejPO_fMaDjl4tzDF9_vY/s1600/obnizanie-wieku-emerytalnego-w-polsce-9-638.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZRW0k-aL-weGFBnZw3DHW4GeZnLdeJcoyNplXAzFV6pJfF06dW8hyORIHRjvB3MHWnop9uh37Q7To8l5iG-xYdoqFxC6myqi5_SnloCIEfqvFAUqjRyMCn5cejPO_fMaDjl4tzDF9_vY/s640/obnizanie-wieku-emerytalnego-w-polsce-9-638.jpg" width="640" /></a></div>
<span style="font-size: x-small;">Źródło: <a href="http://grape.org.pl/blog/co-dokladnie-oznacza-obnizanie-wieku-emerytalnego-w-polsce/" target="_blank">http://grape.org.pl/blog/co-dokladnie-oznacza-obnizanie-wieku-emerytalnego-w-polsce/</a></span><br />
<br />
Jeśli zatem masz 20-30 lat, to masz około 70% szans na to, że twoja emerytura od państwa będzie minimalna. Na tę chwilę jest to chyba 880zł, od 1 października 1000zł. Co prawda co roku coś się zmienia w systemie emerytalnym, ale myślę że najbezpieczniej jest założyć, że większość emerytury (jeśli nie całość) musimy sobie zapewnić samemu.<br />
<br />
Powróćmy jednak do głównego wątku. Tytułowe pytanie usłyszałem ostatnio od jednej ze znajomych i w pierwszej chwili nie wiedziałem co odpowiedzieć. Jest tyle możliwości, że mógłbym opowiadać o tym przez kilka godzin. Jak streścić te wszystkie opcje tak, żeby nie przytłoczyć i nie zniechęcić? Czy zagłębiać się w inwestowanie na giełdzie albo w kupno funduszy inwestycyjnych? Dużo przecież zależy też od profilu danej osoby i tego, ile czasu chce poświęcić na zarządzanie swoimi oszczędnościami.<br />
<br />
Najlepszą odpowiedzią jaka mi przyszła do głowy jest: <b>przede wszystkim oszczędzaj</b>. Odkładaj co miesiąc stałą kwotę, najlepiej około 10% swoich dochodów na oddzielne konto. Nie możesz odkładać aż tyle? Odłóż najpierw 100 zł miesięcznie i w miarę możliwości (np. po otrzymaniu podwyżki wynagrodzenia) zwiększaj tę kwotę. Utwórz zlecenie stałe, które zaraz po wypłacie przeleje pieniądze na ten cel - jeśli zostaną odłożone już wtedy, to na pewno ich nie wydasz. Ważna jest przede wszystkim systematyczność. Jeśli osiągniesz ten krok, to dopiero wtedy możesz przejść dalej.<br />
<br />
Drugą ważną rzeczą jest korzystne oprocentowanie Twoich środków na emeryturę. Magia procentu składanego naprawdę działa. Na początku (przynajmniej mi) wydawało się, że oszczędności przyrastają powoli - trzeba jednak pozwolić im pracować, a przez kilkadziesiąt lat odsetki od zgromadzonej kwoty prawdopodobnie przekroczą wpłacony kapitał. Dla przykładu wezmę opcję minimum z poprzedniego punktu (czyli 100 zł). Na poniższych wykresach widać, jak zachowuje się zaoszczędzona kwota kiedy odkładamy ją regularnie przez 30 lat. Pokazuję dwa warianty - rachunek oprocentowany na 3% i 5% rocznie z naliczaniem odsetek co miesiąc.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYLBgAirbeXNc6Qr9Ux1yZrUZV_eev75dXc3ioX-_VPnNrMdpbcQAmt-Ix7AagbSRyyXF92uIxLGNI8SKcEsqmDCbHlpe3qUqqe6JnGqmQO70H4lNcY4qfi3WzKEzumJ5cD1N9KNtzozM/s1600/100zl_30lat.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="372" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYLBgAirbeXNc6Qr9Ux1yZrUZV_eev75dXc3ioX-_VPnNrMdpbcQAmt-Ix7AagbSRyyXF92uIxLGNI8SKcEsqmDCbHlpe3qUqqe6JnGqmQO70H4lNcY4qfi3WzKEzumJ5cD1N9KNtzozM/s640/100zl_30lat.PNG" width="640" /></a></div>
Jak na dłoni widać, jak dużą różnicę robi każdy punkt procentowy więcej w kwestii ostatecznej kwoty jaką otrzymamy. Celowo pominąłem na powyższych obliczeniach podatek Belki, czyli 19% podatku od zysku. Pominąłem go dlatego, żeby teraz pokazać jak zachowa się zaoszczędzona kwota kiedy ten podatek uwzględnię<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6M27bpl68YPcyEJ3MGLXSrbq9fuaj_62utlmmEUhTWhZ7wnRepMz_G3m5yf80ImqIhUPwK2WgbWFApCtu9A4Ap0Oecp3C_xMf0bhqiSbJHBEdrpTvfRhY7xZnpP48PuEXlWG2TI5_S0U/s1600/100zl_30lat_belka.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="346" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6M27bpl68YPcyEJ3MGLXSrbq9fuaj_62utlmmEUhTWhZ7wnRepMz_G3m5yf80ImqIhUPwK2WgbWFApCtu9A4Ap0Oecp3C_xMf0bhqiSbJHBEdrpTvfRhY7xZnpP48PuEXlWG2TI5_S0U/s640/100zl_30lat_belka.PNG" width="640" /></a></div>
W tym wariancie jest to ponad 13000 zł różnicy pomiędzy tymi dwiema opcjami i to odkładając jedyne 100 zł miesięcznie. Piszę o tym dlatego, bo chcę pokazać <b>wymierne korzyści z posiadania konta IKE lub IKZE, które są zwolnione z podatku od zysków kapitałowych</b>. Nawet odkładając niewielkie kwoty z myślą o zabezpieczeniu emerytury warto założyć jedno z tych kont. Jest to najłatwiejsza metoda na korzystniejsze efektywne oprocentowanie i poprawienie ostatecznego wyniku jaki osiągniesz. Najprostszą wersją takiego konta (bezpieczną i nie zajmującą czasu) będzie lokata bankowa pod "parasolem" IKE. Najlepsze warunki takiego IKE ma obecnie bank Millenium, który oferuje 3% na lokacie z kapitalizacją roczną.<br />
<br />
Opisałem dwa punkty na drodze do spokojnej emerytury, o które moim zdaniem każdy powinien zadbać. To jednak nie koniec, bo sposobów na poprawienie ostatecznego wyniku jest więcej. Ja nie zamierzam zadowolić się maksymalnie 3% które płacą banki na IKE w postaci lokaty. W kolejnej części opiszę, jak można próbować wyciągnąć więcej i jak może się do tego przydać Portfel Emerytalny który piszę.<br />
<br />Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-46450591982629711892017-04-11T09:18:00.001+02:002017-04-11T09:18:54.598+02:00Raport z placu boju - 6 tydzień DSP<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijPr5ECtrI2CLyxcjo8V0jUOzyl1uyogQP6YdJX-CPbi-JzdEutjaevNgjgpzA6CmElZ9z-ThcFELFDHeAd0Yy2eu0GdGtT4HqeQjRtw2DQW34aVylGrb1FCsyKsxkgXlcg8NeifB1Nq0/s1600/sql_raport.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="98" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijPr5ECtrI2CLyxcjo8V0jUOzyl1uyogQP6YdJX-CPbi-JzdEutjaevNgjgpzA6CmElZ9z-ThcFELFDHeAd0Yy2eu0GdGtT4HqeQjRtw2DQW34aVylGrb1FCsyKsxkgXlcg8NeifB1Nq0/s200/sql_raport.PNG" width="200" /></a></div>
Dzisiejszy raport wyjątkowo pojawia się we wtorek, czyli dzień później niż wynikałoby to z mojego planu i wcześniejszych zapowiedzi. W ubiegłym tygodniu sprawy prywatne zajęły mi cały dostępny czas i niestety nie udało mi się nic zrobić w projekcie. Nie chciałem wrzucać wpisu tylko po to, żeby opisać w nim, że nic nie zrobiłem - dlatego właśnie postanowiłem odłożyć posta na dzień później, a w międzyczasie postarać się o materiał na niego. Właśnie z tego względu nie mam dziś do opisania zbyt wiele, ale lepsze to niż nic :)<br /><br />W projekcie pojawiły się nowe tabele w bazie danych: <i>wallet </i>i <i>asset </i>. Będą one służyły do przechowywania odpowiednio:<br /><ul>
<li>portfeli, czyli zbioru inwestycji danego użytkownika. W portfelach na razie będą mogły być tylko jednostki funduszy inwestycyjnych, ale docelowo również akcje, obligacje, gotówka itp.</li>
<li>pojedynczych składników z których jest zbudowany portfel. W tej tabeli znajdą się posiadane ilości jednostek funduszy oraz daty ich zakupu i ewentualnej sprzedaży. Zawartość tej tabeli można także rozumieć jako operacje wykonywane w portfelach</li>
</ul>
Zostały również dodane nowe metody w API, które także dotyczą portfela i operacji na nim. Można więc za pomocą API pobrać listę aktualnie posiadanych walorów i historię operacji. Musiałem dopisać też kilka pomocniczych metod jak np. pobranie listy dostępnych funduszy. Dodałem również możliwość wysłania do API informacji o kupnie i sprzedaży jednostek funduszy. Tu jednak musiałem się zatrzymać, bo zanim będę mógł dodawać kolejne operacje, które można wykonać, to muszę przemyśleć jak będzie wyglądała autentykacja i autoryzacja użytkowników.<br /><br />Ostatnią rzeczą na którą poświęciłem kilka chwil to badanie możliwości automatycznego pobierania kursów funduszy. Każde towarzystwo funduszy inwestycyjnych ma obowiązek publikowania wyników prowadzonych przez siebie inwestycji, więc te dane są publicznie dostępne. Problemem pozostaje ich pobranie, bo prawdopodobnie będzie trzeba pisać dedykowaną metodę dla każdego TFI. Rozważałem również użycie narzędzi do testowania interfejsów użytkownika (jak np. Selenium), któremu mógłbym wskazać jaką stronę ma otworzyć, jaki przycisk kliknąć i gdzie zapisać wygenerowany plik. Zbadałem jak to wygląda w przypadku NN TFI i udało mi się wyłuskać z kodu linki pod jakimi są dostępne notowania konkretnych funduszy. Otwiera to drogę do jakiegoś prostego pobieracza tych plików, ale to już temat na kolejne tygodnie.<br />Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-29991075027837522702017-04-06T08:03:00.001+02:002017-04-06T08:04:23.211+02:004developers 2017 z mojej perspektywy<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjn7zYyjcY0Ddamt6KumGPMEVNIF7FdB6P2sepPrXYwyDGxxTI5hrSsZAe-qVfC3-54IWjrnKJ7K4B6A4QXKuHtbE_YwssAGX7fs0daikyh8tMOY55ML9iX_FE0s6WOTYHLOCBh0KjCN6c/s1600/4dev-logo.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjn7zYyjcY0Ddamt6KumGPMEVNIF7FdB6P2sepPrXYwyDGxxTI5hrSsZAe-qVfC3-54IWjrnKJ7K4B6A4QXKuHtbE_YwssAGX7fs0daikyh8tMOY55ML9iX_FE0s6WOTYHLOCBh0KjCN6c/s200/4dev-logo.png" width="200" /></a>W ostatni poniedziałek miałem przyjemność uczestniczyć w
interdyscyplinarnym festiwalu technologicznym 4developers, czyli jednej z
największych konferencji dla programistów w Polsce. Dziś, kilka dni po
tym wydarzeniu, chciałbym podzielić się moimi spostrzeżeniami i
przemyśleniami na jego temat.<br />
<br />
Konferencja odbyła się w Warszawie w hotelu Sangate Airport. Na 3
piętrach części konferencyjnej można było uczestniczyć w aż 14 ścieżkach
tematycznych, dodatkowo dla uczestników została przygotowana strefa
relaksu z pufami i rozrywkami w stylu ping-ponga czy konsoli. Ogólnie sporo miejsca, ale uczestników też było mnóstwo. Organizatorzy mówią o 1800 osobach, co zdecydowanie dało się odczuć.
Momentami było po prostu odrobinę tłoczno, szczególnie na klatkach
schodowych. Poza tą drobną niedogodnością obiekt gdzie odbywała się
konferencja był bardzo dobrze przygotowany - duży plus dla
organizatorów.<br />
<br />
Co do samego przebiegu wydarzenia, to ja spędziłem go bardzo aktywnie. Ilość dostępnych ścieżek wręcz
przytłaczała i niejednokrotnie stawałem przed trudną decyzją, który
wykład wybrać spośród kilku opcji. Liczę na to, że pojawią się nagrania tych, które musiałem odrzucić i będę mógł nadrobić niemożliwość rozdwojenia się :) 15 minut przerwy pomiędzy kolejnymi pozycjami agendy jest w sam raz żeby wypić kawę i zmienić salę, ale jeśli czytasz to przed kolejną edycją to lepiej zaplanuj co chcesz zobaczyć już dzień wcześniej.<br />
<br />
Jeśli chodzi o prelekcje, to te na które trafiłem merytorycznie były bardzo dobrze
przygotowane. Jedyny minus - zdarzyło się, że musiałem siedzieć na
podłodze, bo zabrakło miejsc. Nie mogę tu jednak nikogo winić za taki stan rzeczy,
pewnie gdybym wcześniej na nie przychodził to nie byłoby tego problemu
;)<br />
<br />
<h4>
Co udało mi się wynieść z konferencji i na co warto zwrócić uwagę</h4>
<ul>
<li>Konrad Kokosa opowiedział o ETW, czyli mechanizmie Event Tracing for Windows. Świetne rozwiązanie do śledzenia co dzieje się z naszą aplikacją i jak współpracuje ona z systemem. Ma bardzo niewielki narzut, co pozwala stosować go nawet w środowisku produkcyjnym. Wygląda na niezwykle pomocne w szukaniu skomplikowanych błędów.</li>
<li>.NET Core - Microsoft dwoi i się i troi żeby udostępnić jedno środowisko dla wszystkich platform i idzie mu coraz lepiej. Łukasz Pyrzyk zgrabnie podsumował w jakim stanie aktualnie znajduje się .NET Core i powiedział o nowych funkcjach jak Span<T>, ArrayPool czy ValueTask. Rewolucji może nie będzie, ale ewoluuje w zdecydowanie dobrym kierunku.</li>
<li>Serverless - na ten temat był nawet więcej niż jeden wykład, ja byłem na tym gdzie prezentował Jakub Gutowski (znany jako Gutek). Serverless zmienia podejście do pojęcia serwera, niejako zwalnia z myślenia o nim. Można to określić jako nanoserwisy - wrzucamy na serwer wręcz pojedyncze funkcje które wywołujemy jak usługi. Skalowaniem rozwiązania zajmuje się dostawca, płatność jest za ilość wywołań. Ciekawy trend który warto kojarzyć.</li>
<li>GraphQL - jedna z ostatnich nowości w tworzeniu elastycznych API. Pozwala korzystającemu z naszej usługi na zdecydowanie, jak szeroki zakres danych chce otrzymać w odpowiedzi. Powinno zainteresować każdego, kto buduje API dla wielu klientów i każdy z nich potrzebuje innego zestawu danych w odpowiedzi na to samo zapytanie. Prezentował Piotr Gankiewicz - zwycięzca Daj Się Poznać 2016.</li>
<li>Porty i adaptery - architektura wręcz niezbędna dla każdej większej aplikacji biznesowej, znam i korzystam, ale Dominik Przybysz pomógł mi swoim wykładem nieco lepiej usystematyzować wiedzę.</li>
</ul>
Podsumowując - czy warto kupić wejściówkę? Moim zdaniem warto, bo konferencja jest solidnie zorganizowana, nie ma żadnego pitu-pitu tylko zastrzyk naprawdę solidnej wiedzy. Pro-tip: warto przed zakupem poszukać kodu rabatowego, można kupić bilet 15-20% taniej. Mam zatem nadzieję, że widzimy się na kolejnej edycji!Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-66379857035696499412017-04-03T13:38:00.000+02:002017-04-03T13:39:31.974+02:00Raport z placu boju - 5 tydzień DSP<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkd7a0izHuFXMpxEAttrVriB8MSlnzj3p8rk6HPrpP-fGHr1VOBNvQgvlvqQIK0PgYtG_5WmfsYAqkYnlnFug08jvvQhNBWrhItx_TeKgFIBnsG_-DXmW8G8olqWXrU-EeznjLOUmN428/s1600/raport1.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="106" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkd7a0izHuFXMpxEAttrVriB8MSlnzj3p8rk6HPrpP-fGHr1VOBNvQgvlvqQIK0PgYtG_5WmfsYAqkYnlnFug08jvvQhNBWrhItx_TeKgFIBnsG_-DXmW8G8olqWXrU-EeznjLOUmN428/s200/raport1.PNG" width="200" /></a></div>
Cześć! Tym wpisem rozpoczynam cotygodniową serię raportów z tworzenia Portfela Emerytalnego. <a href="http://danieldymek.blogspot.com/2017/03/podsumowanie-pierwszego-miesiaca-dsp-i.html" target="_blank">Tak jak pisałem w ostatnim poście</a> teraz takie podsumowania będą pojawiać się raz na tydzień w poniedziałki i będą zawierać podsumowania co udało się zrobić w ostatnim czasie w moim projekcie na konkurs Daj Się Poznać 2017.<br />
<br />
<h4>
Szablon strony</h4>
W ostatnim tygodniu znalazłem gotowy, darmowy szablon strony na podstawie którego będę budował interfejs użytkownika. Zależało mi na tym, aby mieć jak najmniej pracy związanej z dostosowywaniem szablonu do moich potrzeb, dlatego od razu szukałem takiego, który będzie przystosowany do Angular 2. Ważne było też, żeby działał zarówno na dużych ekranach komputerów, jak i na smartfonach. Ten który znalazłem jest responsywny, zbudowany na bootstrap i wykorzystuje Material Design od Google. Material Design daje jeszcze jedną, istotną zaletę - zbiór gotowych komponentów do wykorzystania: <a href="https://material.angular.io/" target="_blank">https://material.angular.io/</a>.<br />
Nie może być jednak idealnie i szablon miesza trochę czystego JavaScript z TypeScriptem, ale mam nadzieję to uporządkować w trakcie rozwoju aplikacji.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxAdCK1tReQzeef2I-TJDTYv3e4mX2y373w-NqmjbIfkE4JT7ABvsdQm2tclSmH9nUYZ3CIhFHwsQUi7ZoJvLJMJTm05uXaY5j94mTY_QdI0A8z4L9URqlTIApwhGUFf6aNnT1uqmS7pU/s1600/opt_md_angular_thumbnail.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxAdCK1tReQzeef2I-TJDTYv3e4mX2y373w-NqmjbIfkE4JT7ABvsdQm2tclSmH9nUYZ3CIhFHwsQUi7ZoJvLJMJTm05uXaY5j94mTY_QdI0A8z4L9URqlTIApwhGUFf6aNnT1uqmS7pU/s400/opt_md_angular_thumbnail.jpg" width="400" /></a></div>
<br />
Twórca zrobił tutaj kawał dobrej roboty, więc w podziękowaniu link do strony: <a href="https://www.creative-tim.com/product/material-dashboard-angular2" target="_blank">https://www.creative-tim.com/product/material-dashboard-angular2</a><br />
<br />
<h4>
Dostosowanie szablonu</h4>
Pobrany szablon musiałem jeszcze zintegrować z <a href="http://danieldymek.blogspot.com/2017/03/jak-postawic-strone-w-angular-2-w-5.html" target="_blank">wygenerowaną z angular-cli aplikacją</a> i na jego podstawie zbudować zalążek tego, jak będzie się prezentował interfejs użytkownika Portfela Emerytalnego. W tej kwestii czeka mnie jeszcze sporo pracy, ale pierwsze rezultaty prezentują się następująco:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlHBl7rKx24ECI_9eYKFqrYfp0uxBPekjcUz-5ryLcoVbHeP_VJrurGgTTrMBlzrCbnpKalG8cLueCMU572OcrJ19lz_zTIyxHpFvQVbp0mt5TFZ69ybCbzX1BAowdGKJIOlv5L9fRwJ8/s1600/screencapture-localhost-4200-dashboard-1491202718061.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlHBl7rKx24ECI_9eYKFqrYfp0uxBPekjcUz-5ryLcoVbHeP_VJrurGgTTrMBlzrCbnpKalG8cLueCMU572OcrJ19lz_zTIyxHpFvQVbp0mt5TFZ69ybCbzX1BAowdGKJIOlv5L9fRwJ8/s400/screencapture-localhost-4200-dashboard-1491202718061.png" width="243" /></a></div>
<br />
<h4>
Zmiana biblioteki do wyświetlania wykresów</h4>
Ostatnią zmianą wprowadzoną w ubiegłym tygodniu jest rezygnacja z <a href="http://valor-software.com/ng2-charts/" target="_blank">ng2-charts</a>, którego pierwotnie chciałem użyć do wyświetlania wykresów. Podjąłem wiele prób wyświetlania danych przy użyciu tej biblioteki, rozwiązałem wiele pojawiających się problemów, ale wykresy nadal nie działały tak jak oczekiwałem. Przykładem niech będzie to, że kiedy zmieniałem ilość punktów które ma wyświetlić wykres to ten rzucał błędem parsowania.<br />
Żeby nie zamieniać programowania w hackowanie tej biblioteki żeby działała, postanowiłem spróbować innego rozwiązania. Wybrałem <a href="https://github.com/gevgeny/angular2-highcharts" target="_blank">angular2-highcharts</a>, który okazał się idealnym rozwiązaniem wolnym od problemów z którymi zetknąłem się używając ng2-charts. Dodatkowo highchart od ręki obsługuje wykresy, na których możemy wybrać zakres czasu dla jakiego zostaną pokazane dane.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9l1b7FCJ-LWbS6ixafLftxeIQGNr4YskgCyniWQLAeGXVavDxYREoL3REGXcgYQqfoTv6VjIPl24ARTSspp8hO0442kuvIWo-vY2fFoRykDsjJ0CLLd2uQNzpFe95CtpTk9vt3YF0m8k/s1600/highcharts.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="223" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9l1b7FCJ-LWbS6ixafLftxeIQGNr4YskgCyniWQLAeGXVavDxYREoL3REGXcgYQqfoTv6VjIPl24ARTSspp8hO0442kuvIWo-vY2fFoRykDsjJ0CLLd2uQNzpFe95CtpTk9vt3YF0m8k/s320/highcharts.PNG" width="320" /></a></div>
Kolejna rzecz mniej do napisania samemu, co ostatecznie zadecydowało o wyborze tego rozwiązania.<br />
<br />
To tyle jeśli chodzi o dzisiejszego, opóźnionego posta. Na kolejne podsumowanie zapraszam za tydzień.Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-37623502238430035612017-03-30T07:22:00.000+02:002017-03-30T07:22:01.456+02:00Podsumowanie pierwszego miesiąca DSP i plany dalszego działania<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6_JhrIPYr6WMQT-cTdHPyAgGEruE39Ve5XafFtX61eDfGz_xwfrF1NF8Z2tFzQgcVz1dQuzF_HD40YpLMLPNRyAAwpIe9GRR2L1IflRIyxyUY5HFUZ_eh91qyV0wBh-5SQ8q7MzXDzDg/s1600/podsumowanie.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6_JhrIPYr6WMQT-cTdHPyAgGEruE39Ve5XafFtX61eDfGz_xwfrF1NF8Z2tFzQgcVz1dQuzF_HD40YpLMLPNRyAAwpIe9GRR2L1IflRIyxyUY5HFUZ_eh91qyV0wBh-5SQ8q7MzXDzDg/s200/podsumowanie.png" width="200" /></a></div>
Kończy się marzec, a wraz z nim pierwszy miesiąc trwania konkursu Daj Się Poznać. Portfel Emerytalny, czyli mój projekt konkursowy, naturalnie również jest rozwijany już miesiąc. Co przez ten czas udało się zrobić, a gdzie zawaliłem sprawę? Jakie mam plany na kwiecień i jakie zmiany czekają bloga? O tym wszystkim w dzisiejszym wpisie.<br />
<a name='more'></a><br />
<h4>
Na dobry początek co się udało i z czego jestem zadowolony:</h4>
<ol>
<li>Blogowanie - uruchomienie bloga, zmiana jego wyglądu, regularne posty w poniedziałki i czwartki</li>
<li>Projekt - postawienie szkieletu aplikacji w postaci skomunikowanych ze sobą bazy, API oraz frontendu. Dobry punkt wyjściowy do dalszego rozwoju</li>
<li>Portfel Emerytalny został wymieniony w gronie <a href="http://webporadnik.com/dsp-genialnie-projekty-czesc-2/" target="_blank">genialnie zapowiadających się projektów</a> - to dla mnie spore wyróżnienie i znak, że warto było wziąć udział w konkursie</li>
<li>Kilku nowych obserwujących na Twitterze</li>
</ol>
<h4>
Co natomiast nie wyszło?</h4>
<ol>
<li>Nie wyznaczyłem sobie żadnych celów na początku, więc nie mam teraz z czym skonfrontować aktualnego stanu rozwoju aplikacji </li>
<li>Z całego czasu poświęconego na konkurs zdecydowanie za dużo pochłania pisanie postów. Jest odrobinę lepiej niż na samym początku i nabieram jako takiego "flow", ale nadal chciałbym więcej czasu spędzać nad kodem niż nad wpisami na bloga</li>
<li>Brak strony na Facebooku - nie założyłem jej na początku trwania konkursu, bo nie chciałem mieć profilu prywatnego i osobno "profesjonalnego". Teraz coraz bardziej czuję, że to był błąd i odcięcie się od potencjalnych odwiedzających</li>
<li>Promowanie projektu, a właściwie jego prawie kompletny brak (poza twittami o nowych postach)</li>
</ol>
<h3>
Plan na kwiecień</h3>
Co zatem dalej z moim projektem? Przede wszystkim chcę naprawić to, co nie wyszło w marcu, czyli: wyznaczam cele, zmieniam nieco formę bloga i zakładam stronę na Facebooku. Przejdę zatem do meritum - cele do osiągnięcia:<br />
<ol>
<li>
Z końcem kwietnia chcę mieć działające, ładne demo. Ma działać dla moich inwestycji i być prezentacją funkcjonalności produktu. Rzeczy do zrobienia w związku z tym:<br />
<ul>
<li>znaleźć i wdrożyć layout interfejsu użytkownika</li>
<li>zapisać w bazie kursy wszystkich funduszy których jednostki posiadam lub posiadałem (idealnie gdyby działał już automat aktualizujący dane)</li>
<li>zaimplementować operacje związane z portfelem inwestycji (kupno, sprzedaż, zamiana)</li>
<li>uzupełnić portfel o historyczne operacje które wykonywałem</li>
<li>wyświetlać listę posiadanych jednostek funduszy </li>
<li>prezentować historię operacji</li>
<li>wyświetlać wykresy wartości posiadanych walorów (idealnie gdyby zaznaczały się na nim operacje z historii)</li>
<li>wyświetlać procentowy zysk/stratę ze wszystkich inwestycji (idealnie byłoby gdyby dało się wybrać z których)</li>
</ul>
</li>
<li>Założenie strony produktu na Facebooku i jego promocja</li>
<li>Zmiany w publikacjach na blogu
<ul>
<li>Jeden post w tygodniu bardziej techniczny (ale też z umiarem - patrz następny punkt) z podsumowaniem zmian w projekcie które udało się wdrożyć</li>
<li>Nie opisywać krok po kroku co robiłem z punktu widzenia programisty,
tylko raczej opisać nowe funkcjonalności okiem użytkownika końcowego -
to odpowiedź na zarzut żony, że piszę zbyt techniczne posty ;) </li>
<li>Drugi z tygodniowych postów bardziej ogólny i być może nawet nie dotyczący projektu. Może pojawi się coś więcej o samym oszczędzaniu długoterminowym.</li>
</ul>
</li>
</ol>
To tyle na dziś, mam nadzieję że opracowany tutaj plan pomoże mi w rozwoju Portfela Emerytalnego i uda się dostarczyć gotowy produkt na koniec konkursu. Do usłyszenia (przeczytania?) w poniedziałek, a jeśli ktoś z czytających będzie na 4developers to być może nawet do zobaczenia :)Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-90163875313961438472017-03-27T10:36:00.004+02:002017-03-27T10:40:25.457+02:00Połączenie backendu z frontendem, czyli odbieranie danych z API w Angular<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXmLV1eIZuTPQGjP4PLnbSb706qu31ChDQwRZo-tSnlBxGIOfIeeoagLU3ubajGLw8aeiADjJtKndzUD8eOVPu2Vnkonhk2cj_jIMM1dtLQTuq4eCWP1EUCzHi6H1JE5mmk7OUrkraCq8/s1600/angular_flask.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="139" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXmLV1eIZuTPQGjP4PLnbSb706qu31ChDQwRZo-tSnlBxGIOfIeeoagLU3ubajGLw8aeiADjJtKndzUD8eOVPu2Vnkonhk2cj_jIMM1dtLQTuq4eCWP1EUCzHi6H1JE5mmk7OUrkraCq8/s320/angular_flask.png" width="320" /></a></div>
W dzisiejszym poście zamierzam pokazać jak odebrać dane z API w Angular i wyświetlić je w aplikacji - czyli ciąg dalszy spinania aplikacji w całość. Na razie wyświetlę tylko suche dane, bez "ubierania" ich w wykres - na ten temat pojawi się osobny post.
<a name='more'></a>
<h5>
Odbieranie JSON w Angular</h5>
Do celów pobierania danych z API utworzyłem dedykowany serwis który będzie odpowiedzialny za to zadanie. Jego kod wygląda następująco:
<br />
<pre><code class="typescript">import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
@Injectable()
export class ApiService {
private baseUrl: string = 'http://localhost:5000';
constructor(private http : Http) { }
getTestData() : Observable<any> {
return this.http.get(`${this.baseUrl}/dbtest`)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body.data || { };
}
private handleError (error: Response | any) {
// In a real world app, we might use a remote logging infrastructure
let errMsg: string;
if (error instanceof Response) {
const body = error.json() || '';
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
} else {
errMsg = error.message ? error.message : error.toString();
}
console.error(errMsg);
return Observable.throw(errMsg);
}
}</any></code></pre>
Serwis jest oznaczony dekoratorem <code class="typescript">@Injectable()</code>, dzięki czemu będzie dodawany do komponentów przez wstrzykiwanie zależności. Tak samo jest w tej klasie wczytany serwis <code class="typescript">Http</code>, dzięki któremu wyślemy żądanie do API - w konstruktorze podajemy tylko, że chcemy go używać i nie martwimy się jego utworzeniem. Następnie mamy właściwą metodę <code class="typescript">getTestData()</code> do pobrania danych, gdzie wykorzystujemy serwis <code class="typescript">Http</code> i obsługujemy powodzenie żądania oraz ewentualny błąd. Metoda ta zwraca obiekt <code class="typescript">Observable</code>, czyli coś co będziemy mogli obserwować i co powiadomi nas kiedy zmieni swoją zawartość - czyli kiedy żądanie ukończy swoje działanie. Zanim jednak będę mógł takie dane odebrać i wyświetlić muszę zwrócić uwagę na jeszcze jedną rzecz.<br />
<br />
<h5>
Co to jest CORS i dlaczego ma znaczenie?</h5>
Skrót CORS oznacza <i>Cross</i><i>-</i><i>origin</i><i> </i><i>resource</i><i> </i><i>sharing</i>. Jest to mechanizm umożliwiający pobranie zasobów przy użyciu <i>XMLHttpRequest</i> (takie zapytania wysyła Angular i w ogólności JavaScript) z zewnętrznego serwera. W praktyce sprowadza się do tego, że jeśli chcemy uzyskać zasoby z serwera z innej domeny, to ten serwer musi w takiej odpowiedzi zawierać nagłówek <i>Access-</i><i>Control</i><i>-</i><i>Allow</i><i>-</i><i>Origin</i> z naszą domeną.<br />
Dlaczego o tym piszę i dlaczego to ważne? Temat ten dotyczy mojego projektu, bo API będzie na innym serwerze niż interfejs użytkownika, muszę więc zapewnić odpowiednią obsługę żądań cross domain. Na szczęście Flask ma gotową bibliotekę do CORS i uruchomienie sprowadza się do dodania w backendzie importu modułu<br />
<pre><code class="python">from flask_cors import CORS, cross_origin</code></pre>
i poniżej oznaczeniu że aplikacja ma go używać
<br />
<pre><code class="python">CORS(app)</code></pre>
<h5>
Użycie ApiService i wyświetlenie odebranych danych</h5>
Dzięki temu, że mam już gotowy serwis do wysłania żądania do serwera i wstępnej obróbki danych, to samo jego użycie jest bardzo proste. Definiuję zmienną gdzie zostaną zapisane dane, wpisuję w konstruktorze że ma zostać wstrzyknięty serwis i wywołuję metodę tego serwisu przy inicjalizacji komponentu. Metoda <code class="typescript">first()</code> informuje, że zwrócony z <code class="typescript">getTestData()</code> obiekt <code class="typescript">Observable</code> ma poinformować o jednej zmianie swojego stanu i zakończyć działanie. Do metody <code class="typescript">subscribe()</code> natomiast przekazuję funkcję, która zostanie wykonana kiedy <code class="typescript">Observable</code> zmieni swój stan - czyli kiedy serwer odpowie na zapytanie i odbierzemy odpowiedź. Kod prezentuje się następująco:
<br />
<pre><code class="javascript">export class AppComponent implements OnInit {
testData : any[];
constructor(private apiService: ApiService) { }
ngOnInit(): void {
this.apiService.getTestData().first().subscribe(response => this.testData = response);
}
}</code></pre>
Pozostaje już tylko wyświetlić te dane, więc w pliku html wpisuję
<br />
<pre><code class="html">Dane z api:<br />{{testData}}</code></pre>
Dane odebrane z API wyświetlają się, zatem wszystkie warstwy aplikacji komunikują się i działają poprawnie. Mam więc w końcu szkielet, na którym będę mógł dalej rozwijać swoją aplikację. Mam nadzieję, że teraz jej rozwój ruszy z kopyta :) Ciągle jednak więcej czasu spędzam nad pisaniem postów niż nad kodem, dlatego muszę nieco zmienić koncepcję bloga - prawdopodobnie będzie trochę mniej technicznie. Po więcej szczegółów zapraszam w czwartek!
Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-47128624915121560362017-03-23T08:15:00.000+01:002017-03-23T08:15:02.616+01:00Python Flask i MySQL - łatwo i szybko czy droga przez mękę?<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieOEXsfRSssdQ5ATFHepdupG8bbURM92eshPVHDgXt9AJAQ6HkGB1bSUP02GlTuNKtgXB3WzFeT-iP512JO1yLC4QAQzZKwmmb0gs-kZu9mAV-LFzHaQn8U5Ln7iPXmu7G7Qpd7mbxbwM/s1600/flask_mysql.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="197" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieOEXsfRSssdQ5ATFHepdupG8bbURM92eshPVHDgXt9AJAQ6HkGB1bSUP02GlTuNKtgXB3WzFeT-iP512JO1yLC4QAQzZKwmmb0gs-kZu9mAV-LFzHaQn8U5Ln7iPXmu7G7Qpd7mbxbwM/s200/flask_mysql.png" width="200" /></a>Kontynuując post z poniedziałku pozostaję w temacie połączenia Flask i MySQL. W dzisiejszym wpisie będzie case study jak to połączenie odbyło się w moim projekcie - w końcu pora zacząć spinać wszystkie elementy w jedną, działającą całość. <br />
<div>
<br /></div>
<div>
<a href="http://danieldymek.blogspot.com/2017/03/przeglad-dostepnych-rozwiazan-do.html" target="_blank">W poprzednim wpisie</a> podałem kilka modułów do MySQL dostępnych dla Flask, ale nie wspomniałem którego użyję. Pierwsza wersja backendu używała Flask-MySQL, zdecydowałem jednak o zmianie na Flask-MySQLdb. Różnica niewielka, ale przekonała mnie kompatybilność z Python 3+. Niestety po wydaniu polecenia<br />
<blockquote class="tr_bq">
pip install flask-mysqldb</blockquote>
zobaczyłem jedynie błąd
<br />
<blockquote class="tr_bq">
running build_ext<br />
building '_mysql' extension<br />
error: Microsoft Visual C++ 9.0 is required. Get it from http://aka.ms/vcpython27</blockquote>
pobranie Microsoft Visual C++ Compiler for Python 2.7 i uruchomienie instalacji zmieniło tylko komunikat na
<br />
<blockquote class="tr_bq">
_mysql.c(29) : fatal error C1083: Cannot open include file: 'my_config.h': No such file or directory
</blockquote>
Na szczęście jest stackoverflow, zgodnie ze <a href="http://stackoverflow.com/questions/26866147/mysql-python-install-fatal-error" target="_blank">znalezioną poradą</a> pobrałem odpowiednią paczkę ze strony <a href="http://www.lfd.uci.edu/~gohlke/pythonlibs/#mysqlclient" target="_blank">http://www.lfd.uci.edu/~gohlke/pythonlibs/#mysqlclient</a> (w moim przypadku mysqlclient-1.3.10-cp27-cp27m-win32.whl), kilka poleceń w konsoli<br />
<blockquote class="tr_bq">
pip install wheel<br />
Successfully installed wheel-0.29.0<br />
<br />
pip install .\mysqlclient-1.3.10-cp27-cp27m-win32.whl<br />
Successfully installed mysqlclient-1.3.10<br />
<br />
pip install flask-mysqldb<br />
Installing collected packages: flask-mysqldb<br />
Successfully installed flask-mysqldb-0.2.0</blockquote>
Zatem w końcu sukces, a to dopiero początek drogi.<br />
<br />
<h5>
Jak wczytać ustawienia z zewnętrznego pliku</h5>
</div>
<div dir="ltr">
Niezależnie jednak od użytego modułu pojawiła się potrzeba zapisania danych połączenia z bazą w osobnym pliku. Można to zrobić na wiele sposobów, np.</div>
<ul>
<li>plik z kodem Python, który importuje się jak inne moduły</li>
<li>JSON</li>
<li>YAML, czyli specjalny format do przechowywania konfiguracji</li>
<li>plik INI</li>
<li>standardowy XML</li>
</ul>
<div dir="ltr">
Bardzo dobre zestawienie tych metod razem z przykładami użycia jest dostępne <a href="https://martin-thoma.com/configuration-files-in-python/" target="_blank">tutaj</a>.</div>
Najłatwiejsza i wystarczająca w moim przypadku wydaje się metoda nr 1 i tak powstał plik databaseconfig.py:
<br />
<pre><code>mysql = {'host': 'database_host',
'user': 'database_user',
'passwd': 'database_passwd',
'db': 'database_name'}</code></pre>
<h5>
Kod!</h5>
Pora na programistyczne mięcho. Mam już wszystko żeby napisać kolejną metodę do API,
postanowiłem więc przygotować dane do wyświetlenia na wykresie w interfejsie
użytkownika. <br />
Dodaję import flask_mysqldb oraz jsonify z modułu flask (tworzy obiekt response z jsonem który można zwrócić bezpośrednio z metody), wczytuję konfigurację z pliku. Nagłówek pliku app.py z wygląda teraz tak:
<code></code><br />
<pre><code class="python">from flask import Flask
from flask import Response
from flask import jsonify
from flask_mysqldb import MySQL
app = Flask(__name__)
import databaseconfig as cfg
app.config['MYSQL_USER'] = cfg.mysql['user']
app.config['MYSQL_PASSWORD'] = cfg.mysql['passwd']
app.config['MYSQL_DB'] = cfg.mysql['db']
app.config['MYSQL_HOST'] = cfg.mysql['host']
mysql = MySQL(app)</code></pre>
a metoda pobierająca dane z bazy tak:<br />
<pre><code class="python">@app.route("/dbtest")
def fetchfromdb():
query_string = "SELECT Date, Value FROM rate WHERE Date > '2015-01-01' AND FundId = 1"
cursor = mysql.connection.cursor()
cursor.execute(query_string)
return jsonify(data=cursor.fetchall())</code></pre>
<div dir="ltr">
Sukces? Jeszcze nie. Niestety przygotowana przeze mnie metoda po wywołaniu wyrzuciła błąd z parsowaniem typu decimal<br />
<blockquote class="tr_bq">
TypeError: Decimal('110.11') is not JSON serializable </blockquote>
</div>
<div dir="ltr">
<h5>
Parsowanie decimal</h5>
O co chodzi z tym błędem? Otóż JSON w swojej specyfikacji nie uwzględnia takiego typu jak decimal, więc autorzy Flask nie implementowali swojej wersji tego jak ma być serializowany. Chcesz mieć decimal - musisz sam zdecydować jak ma on być zapisywany. Można oczywiście pozbyć się decimali z zapytania do bazy<br />
<pre><code class="SQL">SELECT Date, CAST(Value * 100 AS INT) FROM rate WHERE Date > '2015-01-01' AND FundId = 1</code></pre>
ale to tylko obejście problemu zamiast jego rozwiązania.</div>
<div dir="ltr">
Na szczęście domyślny parser JSON można nadpisać swoją implementacją, w której zdefiniujemy zachowanie dla wybranych typów, a reszta zostanie w domyślnej postaci:<br />
<pre><code class="python">import flask.json
import decimal
class MyJSONEncoder(flask.json.JSONEncoder):
def default(self, obj):
if isinstance(obj, decimal.Decimal):
# Convert decimal instances to strings.
return str(obj)
return super(MyJSONEncoder, self).default(obj)
app.json_encoder = MyJSONEncoder</code></pre>
Po takiej zmianie aplikacja działa już poprawnie i zwraca dane jakie możemy odebrać we frontendzie.<br />
</div>
<br />
Po rozwiązaniu powyższego problemu dowiedziałem się jeszcze o bibliotece simplejson, która zawiera domyślną metodę obsługi decimal. Chciałem jednak pozostać przy Flask.jsonify że względu na to, że zwraca od razu obiekt Response gotowy do zwrócenia z funkcji. Nie testowałem, ale ponoć<br />
<blockquote class="tr_bq">
If you install the simplejson package, flask.jsonify will automatically use that instead of the stdlib json library. </blockquote>
<div dir="ltr">
Na koniec odniosę się do pytania, które umieściłem w tytule. Niestety nie mogę powiedzieć żeby połączenie z MySQL było wybitnie łatwe - w całym procesie pojawiło się kilka problemów. Część z nich wynika na pewno z mojej nieznajomości Pythona. Na szczeście nie była to również droga przez mękę i nadal uważam że Flask był dobrym wyborem jeśli chodzi o szybkie prototypowanie backendu. Zobaczymy czy i jak długo ta opinia się utrzyma :) </div>
Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com1tag:blogger.com,1999:blog-5647842092322999820.post-2098949286161732082017-03-20T07:02:00.000+01:002017-03-20T08:39:03.775+01:00Przegląd dostępnych rozwiązań do połączenia Flask i MySQL<div dir="ltr">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrMw_5Z4aYv7KtIA-oWTJX-EK2NFFWZHjTW8ASuwX-1ksqef8_Pa-T6EMZkogyBS6d5gQoJNcyIXbEBUQWlPXpuBCgagl5NkvlrnXsUdW7ZkpMT_5JB5q2hXGJPmdcgUFeGVFbasKxXC4/s1600/flask_mysql.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="196" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrMw_5Z4aYv7KtIA-oWTJX-EK2NFFWZHjTW8ASuwX-1ksqef8_Pa-T6EMZkogyBS6d5gQoJNcyIXbEBUQWlPXpuBCgagl5NkvlrnXsUdW7ZkpMT_5JB5q2hXGJPmdcgUFeGVFbasKxXC4/s200/flask_mysql.png" width="200" /></a>Ten post jest pierwszą częścią opisu współpracy Flask i MySQL. Kiedy
zacząłem tworzyć wpis dotyczący połączenia bazy i backendu w moim projekcie, to chciałem w nim opisać kompleksowo wszystko czego się nauczyłem w trakcie poznawania Flask.
Post rozrósł się do ogromnego wypracowania, dlatego został podzielony na części. Dzisiaj opiszę dostępne metody takiego połączenia, na pewno pojawi się również opis konkretnego wdrożenia na przykładzie Portfela Emerytalnego. Być może na tym się nie skończy, bo temat jest naprawdę obszerny.<br />
<br />
Poszukiwania metody połączenia się z bazą przyniosły odkrycie, że
istnieje kilka modułów których możemy użyć w tym celu. Znalezione przeze mnie to:</div>
<ul>
<li><a href="#Flask-MySQL">Flask-MySQL</a></li>
<li><a href="#Flask-MySQLdb">Flask-MySQLdb</a></li>
<li><a href="#Flask-SQLAlchemy">Flask-SQLAlchemy</a> </li>
</ul>
Wymieniłem tylko takie związane wprost z Flask, bo dla samego Pythona istnieje ich wiele więcej (<a href="http://mysql-python.sourceforge.net/" target="_blank">MySQLdb</a>, <a href="https://mysqlclient.readthedocs.io/en/latest/" target="_blank">mysqlclient</a>, <a href="https://dev.mysql.com/doc/connector-python/en/" target="_blank">Connector/Python</a>, <a href="http://sqlobject.org/" target="_blank">SQLObject</a>, <a href="http://docs.peewee-orm.com/en/latest/" target="_blank">peewee</a>, <a href="https://ponyorm.com/" target="_blank">PonyORM</a> itd.). Taki wybór w założeniu ma zapewnić brak problemów w użyciu w połączeniu z Flask.
<br />
Krótki opis każdego z modułów (forma jest celowo dość ścisła, post ma być szybką ściągawką dla mnie i być innych szukających tego typu zestawienia).
<br />
<br />
<h4 id="Flask-MySQL">
Flask-MySQL</h4>
Strona projektu: <a href="https://flask-mysql.readthedocs.io/" target="_blank">https://flask-mysql.readthedocs.io</a><br />
Chyba najprostszy z wymienionych modułów, oparty na wymienionym powyżej MySQLdb. Niestety z tego powodu działa tylko z Python w wersji 2.4-2.7. Dla mnie nie jest to problem, ale jeśli ktoś pisze w Python 3+ to nie skorzysta z tego rozszerzenia. Ciągle dość popularny i dobrze wypozycjonowany, ja jednak nie będę go używał.<br />
<br />
Inicjalizacja:
<br />
<pre><code class="python">from flask import Flask
from flaskext.mysql import MySQL
app = Flask(__name__)
mysql = MySQL()
app.config['MYSQL_DATABASE_HOST'] = 'localhost'
app.config['MYSQL_DATABASE_USER'] = 'db_username'
app.config['MYSQL_DATABASE_PASSWORD'] = 'db_password'
app.config['MYSQL_DATABASE_DB'] = 'db_name'
mysql.init_app(app)</code></pre>
Użycie:
<br />
<pre><code class="python">connection = mysql.connect()
cursor = connection.cursor()
cursor.execute("SELECT * FROM user")
data = cursor.fetchall()</code></pre>
<h4 id="Flask-MySQLdb">
Flask-MySQLdb</h4>
Strona projektu: <a href="http://flask-mysqldb.readthedocs.io/" target="_blank">http://flask-mysqldb.readthedocs.io</a><br />
W skrócie i uproszczeniu: ulepszona wersja poprzedniego modułu, obsługuje Python 3. Zacytuję wypowiedź autora którą znalazłem: <br />
<ul>
</ul>
<blockquote class="tr_bq">
I wrote it because back then flask-mysql didn't work outside of a
request context (not sure if it does now) and because it's based on
MySQL-python while flask-mysqldb is based on <a href="https://pypi.python.org/pypi/mysqlclient" rel="nofollow">mysqlclient</a>
which is fully backwards compatible fork of MySQL-python and is
compatible with Python 3.3+. You mentioned you're using Python 3.4.3 so
flask-mysql will not work.<br />
flask-mysqldb is really meant to be a tiny, tiny wrapper for mysqlclient so if you need something more like an ORM <a href="https://pythonhosted.org/Flask-SQLAlchemy/" rel="nofollow">flask-sqlalchemy</a> is definitely the way to go.</blockquote>
Inicjalizacja:<br />
<pre><code class="python">from flask import Flask
from flask_mysqldb import MySQL
app = Flask(__name__)
app.config['MYSQL_HOST'] = 'localhost'
app.config['MYSQL_USER'] = 'db_username'
app.config['MYSQL_PASSWORD'] = 'db_password'
app.config['MYSQL_DB'] = 'db_name'
mysql = MySQL(app)</code></pre>
Użycie:
<br />
<pre><code class="python">cursor = mysql.connection.cursor()
cursor.execute("SELECT * FROM user")
data = cursor.fetchall()</code></pre>
<br />
<h4 id="Flask-SQLAlchemy">
Flask-SQLAlchemy</h4>
Strona projektu: <a href="http://flask-sqlalchemy.pocoo.org/2.1/" target="_blank">http://flask-sqlalchemy.pocoo.org/2.1/</a><br />
Bardziej ORM niż prosty moduł do połączenia z bazą. Najpopularniejszy wśród Pythonowych ORMów, prawdopodobnie dlatego dorobił się dedykowanego modułu dla Flask.<br />
<br />
Inicjalizacja:
<br />
<pre><code class="python">from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://username:password@localhost/db_name'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
def __init__(self, username, email):
self.username = username
self.email = email
def __repr__(self):
return '<user r="">' % self.username</user></code></pre>
Użycie:
<br />
<pre><code class="python">data = User.query.all()</code></pre>
Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-30620043901489347322017-03-16T08:26:00.002+01:002017-03-16T08:30:51.433+01:00Baza danych: struktura, przykładowe dane i połączenie<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhh-YaGeTeyI3vMvLSFhwMsawJJ7zqf2l9f1jMJ1C2FDLCVahbRGWOvhVhQoolEmbj3u3UEdgV5Hk-14JbztWooZBA7OHfBWq47fnrgcPNvTqG1IifQZhYedbtvv4C6GmhB3dtDXoVgk_s/s1600/database-mysql.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhh-YaGeTeyI3vMvLSFhwMsawJJ7zqf2l9f1jMJ1C2FDLCVahbRGWOvhVhQoolEmbj3u3UEdgV5Hk-14JbztWooZBA7OHfBWq47fnrgcPNvTqG1IifQZhYedbtvv4C6GmhB3dtDXoVgk_s/s200/database-mysql.png" width="200" /></a>W <a href="http://danieldymek.blogspot.com/2017/03/pierwsze-kroki-z-python-flask-i-heroku.html" target="_blank">ostatnim poście</a> napisałem, że kolejnym krokiem będzie odbieranie we frontendzie przykładowych danych z api. Życie jednak zweryfikowało te plany i trafiłem na jakiś błąd parsowania json przez przeglądarkę w momencie odbierania żądania. Nie mogłem się go pozbyć pomimo wielu prób, stwierdziłem zatem, że szkoda na to czasu. Lepiej sprawdzić czy ten błąd występuje również kiedy odbiorę dane z bazy i te dane zserializuję do json. Jeśli będzie ten sam błąd - to wtedy poszukam co jest nie tak, a jest szansa że problem w ogóle się nie pojawi.W związku z powyższym w dzisiejszym poście opiszę przygotowanie bazy danych.<br />
<br />
Swoją bazę stawiam w hekko.pl, mam u nich wykupiony hosting więc przy okazji użyję go do tego projektu. Samo wygenerowanie bazy odbywa się przez panel DirectAdmin i sprowadza się do kilku kliknięć, więc nie ma tu zbyt wiele do opisania. Jest dostępny phpMyAdmin do zarządzania bazą, ale mam trochę wstręt do niego i od razu pobrałem MySQL Workbench. Przy pierwszej próbie połączenia okazało się, że muszę jeszcze wprost ustawić jakie hosty mają dostęp do bazy. Na czas testów dodałem %, czyli po prostu dostęp dla wszystkich<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXwfRwBuWZaQvvqMDBvtvYavM642Dtehtl5RMggP8a7nzIJzPRw9F7829kLLRPDQrYZlvdIUrFG-g7f8SBI8hEHR2aDQJ2iogglwJ5_WPfaDlUz1Js1TYBETeLy7HuxAQrbrw_KUEy0Ys/s1600/hekko_dostep_do_bazy.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXwfRwBuWZaQvvqMDBvtvYavM642Dtehtl5RMggP8a7nzIJzPRw9F7829kLLRPDQrYZlvdIUrFG-g7f8SBI8hEHR2aDQJ2iogglwJ5_WPfaDlUz1Js1TYBETeLy7HuxAQrbrw_KUEy0Ys/s1600/hekko_dostep_do_bazy.PNG" /></a></div>
<br />
Struktura bazy na potrzeby pierwszej wersji portfela emerytalnego prezentuje się następująco:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgtKPKEi5-htHluuedtHCcOWE7jhTsicf0DmrDcQ9PWyXFzLLLpImwxbl5-pXa9_OfJ2qULGON6JwYdJvFfPw22K256oXONBn0JAJV8LK2DPH2etejrCfXBxUDhPndr8irS0wB0xlbYJM/s1600/baza+v1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgtKPKEi5-htHluuedtHCcOWE7jhTsicf0DmrDcQ9PWyXFzLLLpImwxbl5-pXa9_OfJ2qULGON6JwYdJvFfPw22K256oXONBn0JAJV8LK2DPH2etejrCfXBxUDhPndr8irS0wB0xlbYJM/s1600/baza+v1.PNG" /></a></div>
Na potrzeby wyświetlenia we frontendzie przykładowego wykresu potrzebuję jedynie wartości funduszy w czasie, więc zakładam tylko tabele Fund (będzie zawierała nazwy funduszy) oraz Rate (wartość w czasie):<br />
<pre><code>CREATE TABLE `fund` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(256) NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
CREATE TABLE `rate` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`Date` date NOT NULL,
`Value` decimal(10,2) NOT NULL,
`LastUpdate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
`FundId` int(11) NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8</code></pre>
Pozostało jeszcze tylko uzupełnić tabelę przykładowymi danymi. Kursy funduszu pobieram <a href="https://www.nntfi.pl/fundusze-inwestycyjne/fundusze-mieszane/nn-stabilny-globalnej-alokacji?unitsCategoryId=K&dateFrom=24.09.2014&dateTo=14.03.2017" target="_blank">ze strony TFI</a> i parsuję przy pomocy narzędzia <a href="http://regexr.com/" target="_blank">regexr</a> - wyrażenia regularne spisują się znakomicie do takiego wyselekcjonowania danych<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzE-UVB5K72N3wpE7W8A9O5BCbzeo6Xpj71RM19q66gWBAwWWYveenuL8BzfVWXDeQCtsSyiN_dGKRQc9BZfVePqb_flcCTrln_EZ2ZupL2yHNofbNu26DKfwQweV93TJuHAGDsvYlEGk/s1600/regexr.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="369" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzE-UVB5K72N3wpE7W8A9O5BCbzeo6Xpj71RM19q66gWBAwWWYveenuL8BzfVWXDeQCtsSyiN_dGKRQc9BZfVePqb_flcCTrln_EZ2ZupL2yHNofbNu26DKfwQweV93TJuHAGDsvYlEGk/s640/regexr.PNG" width="640" /> </a></div>
<div class="separator" style="clear: both; text-align: left;">
Wszystko łączę w zapytania i wykonuję na bazie: </div>
<pre><code>INSERT INTO fund (`Name`) VALUES ('NN (L) Stabilny Globalnej Alokacji (K)')
INSERT INTO rate (`Date`, `Value`, `FundId`) VALUES
('2014-09-24', 106.66, 1),
('2014-09-25', 106.44, 1),
('2014-09-26', 106.83, 1),
('2014-09-29', 106.71, 1),
...
</code></pre>
To tyle na dziś, kolejny post będzie o tym jak te dane z bazy odebrać w backendzie i wystawić je jako json. Zapowiada się długi wpis, bo ponownie pojawiło się kilka problemów - po szczegóły zapraszam w poniedziałek.
Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-20694808569261481492017-03-13T08:32:00.000+01:002017-03-22T22:53:03.914+01:00Pierwsze kroki z Python, Flask i Heroku<div dir="ltr">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgk8K0EnRXAnf-vgbmuHJA3IsLEC18jn_37IDARThe_L2xb-qhJXwnL4Zs3MjyfaLI1S5X-633jUMzKUMw0tcbgy-CXCmJfYcWuQ5PRTZm7i8m6iTltmicbMX9P9vSrozcAFJcIiWAI1GQ/s1600/heroku-python-mobile.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgk8K0EnRXAnf-vgbmuHJA3IsLEC18jn_37IDARThe_L2xb-qhJXwnL4Zs3MjyfaLI1S5X-633jUMzKUMw0tcbgy-CXCmJfYcWuQ5PRTZm7i8m6iTltmicbMX9P9vSrozcAFJcIiWAI1GQ/s200/heroku-python-mobile.png" width="174" /></a></div>
W trakcie pisania portfela emerytalnego chcę nauczyć się czegoś nowego, stąd pomysł na użycie języka Python. Po krótkich poszukiwaniach znalazłem też prosty framework do API, czyli Flask. Uruchomienie przykładu ze strony Flask na localhost poszło jeszcze szybciej niż <a href="http://danieldymek.blogspot.com/2017/03/jak-postawic-strone-w-angular-2-w-5.html" target="_blank">postawienie szkieletu strony w Angular</a> i sprowadza się do utworzenia jednego pliku i wywołania dwóch komend w konsoli. Nie chcę przepisywać treści z oficjalnej strony więc zainteresowanych odsyłam na <a href="http://flask.pocoo.org/" target="_blank">http://flask.pocoo.org/</a><br />
<br />
Wybierając Python jako język w którym powstanie backend miałem nadzieję (a nawet byłem przekonany), że będę mógł uruchomić napisane przeze mnie skrypty na hostingu który posiadam. O jakże naiwne było to podejście ;) Nawet jeśli udałoby się uruchomić jakiś prosty skrypt to nie było mowy o zainstalowaniu czegokolwiek - a ja potrzebowałem wspomniany wyżej Flask.<br />
Na szczęście są platformy w chmurze w modelu PaaS (Platform as a Service, czyli dostajemy gotowe całe środowisko w którym uruchamiamy swoje aplikacje). Nigdy nie korzystałem z takich platform, więc znowu pojawiła się okazja do nauki nowych rzeczy. Po szybkim przeszukaniu sieci znalazłem Google App Engine (GAE) oraz Heroku. W obydwu tych miejscach można bez problemu można uruchomić prostą aplikację bez konieczności płacenia, a kiedy potrzebujemy większych zasobów to płacimy za ich zużycie.<br />
<br />
Moje pierwsze kroki skierowałem w stronę GAE, ale ilość opcji i skomplikowanie instalacji szybko mnie zniechęciły. Heroku okazało się nie mieć żadnej z tych wad i po krótkiej konfiguracji udało się utworzyć aplikację retirement-savings-api i uruchomić jej pierwszą wersję - standardowe Hello World o którym pisałem we wstępie.<br />
Pewnym zaskoczeniem dla mnie było to, jak uploaduje się aplikację na serwer. Działa to tak, że po stronie serwera mamy uruchomione repozytorium git - więc wystarczy<br />
<blockquote class="tr_bq">
heroku git:remote -a retirement-savings-api<br />
git add .<br />
git commit -m "stub"<br />
git push heroku master
</blockquote>
i aplikacja już jest na serwerze gotowa do działania. Jeszcze słowem wyjaśnienia - komenda heroku wywoływana powyżej pochodzi z narzędzia udostępnionego przez Heroku, ale nic nie stoi na przeszkodzie żeby użyć po prostu<br />
<blockquote class="tr_bq">
git remote add heroku https://git.heroku.com/retirement-savings-api.git
</blockquote>
</div>
<div dir="ltr">
Zachęcony początkowymi sukcesami postanowiłem przygotować jakieś konkretne dane z których będzie mógł skorzystać frontend. Na początek dodałem statyczny plik z jsonem który API ma odczytywać i po prostu zwracać do klienta. Dopisałem krótką metodę:
<br />
<pre><code class="python">@app.route("/test")
def testdata():
file = open('static/testdata.json', 'r')
file_contents = file.read()
resp = Response(file_contents, status=200, mimetype='application/json')
return resp
</code></pre>
</div>
<div dir="ltr">
Ponownie commit, push i sprawdzam <a href="https://retirement-savings-api.herokuapp.com/test" target="_blank">https://retirement-savings-api.herokuapp.com/test</a>. Wszystko działa jak należy, dane z pliku wyświetlają się, więc teraz pora odebrać te dane po stronie frontu - ale to już materiał na następnego posta.</div>
Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com1tag:blogger.com,1999:blog-5647842092322999820.post-53351825587783275192017-03-09T08:00:00.000+01:002017-03-22T22:53:29.398+01:00Jak postawić stronę w Angular 2 w 5 minut<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-6QwZ1wNKMzpwiTwYS6oQch5P_sQKiycmVLYZK-9uBGjZsc8vlc844QhSuqlAmBz9p6UKH9vQrlWIXD_iiFVG6YeuGvsUHVAeTQa9yzNkAuzQtAPjTJTcEukDWe3uVCdE-WXQtqNsYuY/s1600/angular.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-6QwZ1wNKMzpwiTwYS6oQch5P_sQKiycmVLYZK-9uBGjZsc8vlc844QhSuqlAmBz9p6UKH9vQrlWIXD_iiFVG6YeuGvsUHVAeTQa9yzNkAuzQtAPjTJTcEukDWe3uVCdE-WXQtqNsYuY/s200/angular.png" width="200" /></a></div>
Pora w końcu napisać bardziej techniczny post. Na pierwszy ogień idzie frontend. Tak naprawdę samego kodu nie będzie zbyt wiele, bo dziś opiszę jak postawić działający szkielet witryny i uruchomić go lokalnie. Tytuł nie jest przesadzony i naprawdę można to zrobić w 5 minut, co zaraz się okaże.<br />
<br />
<a name='more'></a>Żeby zacząć się bawić Angularem potrzebujemy przede wszystkim <a href="https://nodejs.org/">Node.js</a>. Pobrany ze strony, zainstalowany. Do wygenerowania angularowej aplikacji użyję Angular CLI, zatem zgodnie z instrukcją na <a href="https://cli.angular.io/" target="_blank">stronie</a> wykonuję w konsoli polecenia<br />
<blockquote class="tr_bq">
npm install -g @angular/cli<br />
ng new retirement-savings-ui
</blockquote>
sprawdzam czy aplikacja działa<br />
<blockquote class="tr_bq">
cd retirement-savings-ui<br />
ng serve</blockquote>
wszystko jest w porządku (a czemu miałoby nie być, w końcu jeszcze nie grzebałem w kodzie), konsola zgłasza<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHbouqoGD9tsHdffGjVn93rWEcPxkq1TM6ulfYCPn9niqUzRRXpQXyMBb7KdnI57uYu4J7SFWNZMu9aeBFgDvpG6dGQssr4nT6An3FhyPO5MyhUbZtLUK-j37rYuxcMblmtIZCzfS8i7I/s1600/ng_serve.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHbouqoGD9tsHdffGjVn93rWEcPxkq1TM6ulfYCPn9niqUzRRXpQXyMBb7KdnI57uYu4J7SFWNZMu9aeBFgDvpG6dGQssr4nT6An3FhyPO5MyhUbZtLUK-j37rYuxcMblmtIZCzfS8i7I/s1600/ng_serve.PNG" /></a></div>
<br />
a strona widoczna pod http://localhost:4200/ radośnie oznajmia<br />
<span style="font-size: large;"><span style="font-family: "times" , "times new roman" , serif;">app works!</span></span><br />
<br />
No i w tym momencie mógłbym skończyć - szkielet aplikacji działa, dodane są testy jednostkowe oraz end-to-end. Ale skoro już jestem przy frontendzie, to tworzę jeszcze komponent który będzie zajmował się wykresami.<br />
<blockquote class="tr_bq">
ng generate component chart
</blockquote>
oraz instaluję gotowy komponent wykresów, którego będzie używał powyższy<br />
<blockquote class="tr_bq">
npm install ng2-charts --save<br />
npm install chart.js --save</blockquote>
Na początek wystarczy, pora teraz na postawienie backendu który dostarczy dane do wyświetlenia na wykresie - ale to już w kolejnym wpisie.<br />
<br />Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-4322676122252815312017-03-06T09:21:00.000+01:002017-03-06T09:21:32.680+01:00Emerytalny Portfel Inwestycyjny - opis projektu<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKgA-NafoCMKGlUluXVGITtJa-L0Jt35z63VNMWn6hD8xWom1E-8SgqmXjFKjAKyO78tYTLxHIs1832rVN2CSj3muwouxNSyd52ZAWzm2vZYpirPVJFhLqjaj02JEBFoaO1UwVtFiWNY8/s1600/LookingGlassInvestmentFund.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKgA-NafoCMKGlUluXVGITtJa-L0Jt35z63VNMWn6hD8xWom1E-8SgqmXjFKjAKyO78tYTLxHIs1832rVN2CSj3muwouxNSyd52ZAWzm2vZYpirPVJFhLqjaj02JEBFoaO1UwVtFiWNY8/s200/LookingGlassInvestmentFund.jpg" width="200" /></a>Zaczynamy tydzień kolejnym wpisem, dziś przekazuję więcej informacji na temat projektu, który realizuję w ramach konkursu Daj Się Poznać. <b>Czym więc jest tytułowy Emerytalny Portfel Inwestycyjny?</b> Krótko mówiąc - miejscem gdzie można śledzić postępy w oszczędzaniu na emeryturę, zobaczyć na wykresie jak przyrastają (lub, o zgrozo - topnieją) nasze inwestycje, dostać powiadomienie jeśli warto zamienić dane aktywa na inne oraz sprawdzić kiedy w takim tempie na tę emeryturę uzbieramy.<br />
<a name='more'></a><br />
Żeby opowiedzieć coś więcej, chciałbym najpierw przybliżyć jak można na taką emeryturę oszczędzać w Polsce. Pomijam oczywiste metody jak standardowe konta oszczędnościowe czy lokaty, skupiam się za to na tzw. III filarze - wyspecjalizowanych w tym celu produktach <b>powiązanych z ulgami podatkowymi</b>, czyli IKE i IKZE.<a href="http://emerytura.gov.pl/iii-filar/porownanie-ikeikze/" target="_blank"> Zobacz porównanie pomiędzy IKE i IKZE.</a><br />
<br />
Właśnie te produkty będą w pierwszej kolejności obsługiwane przez mój system właśnie ze względu na ulgi wspomniane przed chwilą, czyli:<br />
<ul>
<li>w obu typach kont zwolnienie z podatku od zysków (nie płacimy 19% podatku Belki)</li>
<li>dodatkowo tylko dla IKZE: odliczenie od podatku wpłat na konto - możemy więc dodatkowo odzyskać 18% (lub 32%) z wpłaconej kwoty</li>
</ul>
Jeśli więc oszczędzamy na emeryturę (do czego gorąco zachęcam), to osiągamy realne korzyści z posiadania tych produktów. Oba typy kont mogą być prowadzone na kilka sposobów:<br />
<ul>
<li>lokaty bankowe</li>
<li>obligacje skarbowe</li>
<li><b>fundusze inwestycyjne </b></li>
<li>dobrowolne fundusze emerytalne</li>
<li>rachunek maklerski </li>
<li>polisy na życie z funduszem kapitałowym</li>
</ul>
Zaznaczyłem na liście powyżej fundusze inwestycyjne (FI), ponieważ na
początek chciałbym się skupić właśnie na nich. Sam posiadam konto IKE
właśnie w postaci funduszy. FI mają to do siebie, że co prawda mogą
zapewnić wyższe zyski niż lokaty czy obligacje, ale są też obarczone
ryzykiem straty. Im większe możliwości zarobienia tym większe ryzyko.
Dlatego też <b>trzeba nimi zarządzać</b> - nie można wrzucać co miesiąc x zł w jakiś
fundusz akcji i o nim zapomnieć.<br />
<ul>
</ul>
<h3>
Co właściwie ma robić ten portfel emerytalny</h3>
Portfel emerytalny który piszę ma pomóc właśnie w zarządzaniu posiadanymi przez nas jednostkami funduszy. Logowanie się co jakiś czas na konto żeby sprawdzić jak się mają nasze inwestycje i ręczne liczenie stóp zwrotu może i działa, ale jest czasochłonne i mało atrakcyjne. Dlatego zamierzam napisać platformę, która pozwoli wprowadzić posiadane przez użytkownika instrumenty finansowe, pobierze automatycznie ich kursy do wyliczenia wartości, w przyszłości skonsoliduje dane z kilku produktów i zaprezentuje interesujące nas informacje z gotowymi obliczeniami. Na początku chciałabym żeby system zautomatyzował czynności, które i tak robię, czyli:<br />
<div>
<ol>
<li>sprawdzał czy stopa zwrotu z posiadanych aktywów jest wystarczająco wysoka (np. czy fundusz osiągnął w ostatnim roku przynajmniej 2% zysku). Jeśli nie, to powinienem poszukać bardziej opłacalnego</li>
<li>analizował czy powinienem sprzedać fundusz który traci na wartości. Tutaj najpierw chciałbym zaimplementować tzw. kroczący stop loss. Działa on w następujący sposób: kupuję jednostki funduszy i zakładam, że akceptuję stratę maksymalnie np. 8%. Kiedy fundusz rośnie to razem z nim przesuwa się poziom na którym będę sprzedawał (zawsze jest to te 8% od najwyższej wartości). Jeśli jednak spada to poziom wycofania się zostaje na stałym poziomie. Jeśli fundusz spadnie o te 8% od najwyższej wartości i osiągnie poziom wycofania, to system wysyła powiadomienie, że należy sprzedać dane jednostki uczestnictwa</li>
</ol>
<div>
<div>
<h3>
Strona techniczna</h3>
Projekt dzieli się na standardowe 3 warstwy: baza danych, backend, frontend. Dodatkowo gdzieś obok będzie działało pobieranie kursów funduszy. O każdej z tych warstw będzie coś więcej w kolejnych postach, a na razie krótko o technologiach i skąd takie wybory. Przypominam też, że rozwój aplikacji można śledzić na bieżąco na <a href="https://github.com/thorin87/retirement-savings" target="_blank">moim koncie github</a>.<br />
<h4>
Baza danych</h4>
Na codzień używam MSSQL, ale na potrzeby tego
projektu zamierzam posłużyć się MySQL. Wybór raczej praktyczny - znam tę
bazę z czasów kiedy pisałem w PHP, do tego mam serwer gdzie mogę taką
bazę postawić<br />
<h4>
Backend, czyli API</h4>
Do tej pory backendy które pisałem były w C#
lub PHP. Ponieważ ten projekt ma mnie nauczyć czegoś nowego,
postanowiłem wypróbować Pythona z frameworkiem Flask. Całość będzie stała na Heroku, którego również używam po raz pierwszy. Backend będzie uwierzytelniał użytkownika i przekazywał dane z bazy do interfejsu, czyli ponownie - standard.<br />
<h4>
Interfejs użytkownika znany również jako frontend</h4>
Tutaj wybór padł na Angular
2. Poznałem ten framework niedawno i jestem naprawdę zadowolony z jego
używania. Ciągle jednak wiem za mało, więc ponownie jest okazja do
podszkolenia się i usystematyzowania wiedzy.<br />
<h4>
Pobieranie kursów</h4>
Na razie wiem tylko, że będzie podsystem, który będzie zajmował się wyłącznie pobieraniem kursów funduszy i ich zapisem do bazy. Chciałbym żeby był oparty na pluginach, które pozwolą go łatwo rozszerzać. Prawdopodobnie postawię na C# i będzie to jakaś usługa systemowa lub aplikacja konsolowa.<br />
<h3>
Słowo na koniec</h3>
Mam nadzieję, że kolejne posty będą się pojawiały w stałych porach, czyli w poniedziałek rano i środę po południu. Zobaczymy czy uda się utrzymać tempo 😉 Blog już trochę poprawił swój wygląd, ale wciąż dużo pracy przede mną. Jeśli masz jakiekolwiek przemyślenia lub uwagi - zapraszam do komentowania oraz do obserwowania mnie na <a href="https://twitter.com/thorin87" target="_blank">twitterze</a>, gdzie informuję o każdym nowym poście.</div>
</div>
</div>
Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0tag:blogger.com,1999:blog-5647842092322999820.post-92131879973753228902017-03-01T16:44:00.000+01:002017-03-05T17:23:16.386+01:00Hello World<div dir="ltr">
Witaj na moim blogu! W pierwszym wpisie wypada się przedstawić, zatem kilka słów o mnie: tata, mąż i programista .NET z ponad 7 letnim stażem. Moim hobby są finanse (w każdym aspekcie) a w wolnym czasie nałogowo oglądam seriale.<br />
<a name='more'></a><br /></div>
<div dir="ltr">
Motywacją do założenia bloga jest <a href="http://dajsiepoznac.pl/">konkurs</a><a href="http://dajsiepoznac.pl/"> daj </a><a href="http://dajsiepoznac.pl/">się</a><a href="http://dajsiepoznac.pl/"> </a><a href="http://dajsiepoznac.pl/">poznać</a>, w którym zdecydowałem się wziąć udział w ostatniej chwili - rejestrowałem się na pół godziny przed zamknięciem zapisów. Właśnie z tego powodu blog wygląda na razie bardzo roboczo, ale powinno się to poprawić w najbliższym czasie.<br />
<br /></div>
<div dir="ltr">
Jednym z głównych założeń konkursu (poza prowadzeniem bloga) jest projekt programistyczny. Ja zdecydowałem się na utworzenie narzędzia, które już dawno chodziło mi po głowie, a którego brakuje na polskim rynku. Jest to miejsce w którym mógłbym śledzić swoje oszczędności emerytalne, a szczególnie fundusze inwestycyjne dostępne w ramach IKE czy IKZE. Zdaję sobie sprawę, że temat jest dość niszowy, ale jeśli zainteresuje chociaż jedną osobę poza mną to już będzie mój mały sukces :)<br />
<br /></div>
<div dir="ltr">
Więcej informacji o projekcie w następnych wpisach, stay tuned!</div>
Danielhttp://www.blogger.com/profile/01920882460151562286noreply@blogger.com0