Warning: Constant WP_DEBUG already defined in /home/vladbutn/public_html/wp-config.php on line 82
Vlad Butnaru - Trainer & Developer - AI and Data enthusiast

Care sunt pasii unui interviu in IT

Tot ce cauta companiile de IT este o persoana capabila sa se integreze in echipa existenta a proiectului, care sa nu necesite mult timp de acomodare cu metodologia si tehnologia implementarii software si pe care sa si-l poata permite – destul de evident.

Interviurile in industria software constau, de obicei, din urmatorii pasi:

  1. Discutia initiala – atunci cand un recruiter te contacteaza si te intreaba daca esti interesat de o noua oportunitate profesionala.
  2. Descrierea rolului – atunci cand primesti un document care descrie responsabilitatile noului rol.
  3. Discutia cu departamentul HR – un meeting in care porti o discutie cu recruiterul despre experienta ta, in care ti se prezinta tehnologiile si modul de lucru. Cateodata, acest interviu include si o discutie in limba engleza. Nu te astepta la intrebari tehnice in acest pas din proces.
  4. (Optional) Test tehnic – unele companii iti vor trimite un miniproiect pe care trebuie sa il programezi, de obicei de la zero, in care va trebui sa folosesti cunostintele tehnice specifice tehnologiilor necesarele rolului.
  5. Discutia tehnica – un meeting in care discuti cu cel putin un reprezentant tehnic care lucreaza la proiectul la care vei lucra daca esti acceptat. Fii pregatit sa regasesti celebrele intrebari despre programare pe care le gasesti cautand pe Google “interview questions for x”, unde x este limbajul de programare preferat.
  6. Negocierea salariului – o intalnire cu persoana din departamentul HR cu care ai avut discutia initiala in care vei fi intrebat cand poti incepe si ce asteptari salariale ai. De cele mai multe ori (din pacate) nu iti va fi comunicat un interval salarial, ci te va lasa pe tine sa alegi. De regula, cine mentioneaza primul suma este dezavantajat – daca vei spune ca iti dorest un salariu de 1000 de euro, in timp ce ei au un interval de 900 – 1200 euro, bineinteles ca ei vor accepta sa te plateasca cu suma dorita; daca reusesti sa ii convingi sa iti spuna intervalul, ai libertatea de a negocia in avantajul tau, deoarece ti-ar fi spus limita minima.
  7. Angajarea – dupa ce va intelegeti pe partea financiara, semnezi contractul de angajare si ai scapat! 

Website-uri rapide si optimizate cu WSR

Motivatie

Atunci când ai un website, în special dacă nu ai mare experiență sau timp sa îl optimizezi, te bazezi pe tool-urile pe care le găsești după o căutare pe Google. De multe ori, însă, te lovești de tot felul de servicii promovate care oferă marea și sarea și nu au un rezultat vizibil.

In Romania, numărul firmelor care oferă servicii „SEO” sau „Website Optimization” creste în fiecare luna – însă putine sunt cele care chiar au un efect pozitiv asupra ratei de conversie a vizitatorilor.

Mai mult, din momentul in care te inregistrezi pe website-ul lor, pasii sunt foarte simpli de urmat:

  • Adaugi website-ul tau.
  • Schimbi nameserverele DNS de pe hostingul tau cu cele oferite de WSR.
  • Astepti intre 2 si 4 zile lucratoare pentru ca echipa sa finalizeze optimizarile.
  • Te bucuri de un website mult mai rapid.

Ce este WSR

Am fost mereu sceptic când a venit vorba de a apela la provideri externi de servicii de optimizare – mereu mi-a plăcut sa fac tot posibilul sa fac tot ce pot prin propriul cod. Problema de care mă lovesc se învârte în jurul unei infrastructuri IT care sa duca optimizarea la un nou nivel.

WSR a fost o alegere foarte buna. Blogul pe care îl citești chiar acum a fost optimizat prin aceștia. Nu doar ca a mărit viteza de încărcare a acestui blog cu 40%, dar tot ei au înglobat infrastructura DNS sub echipamentele proprii. Asta rezulta intr-o experiența îmbunătățită pentru tine și pentru mine (fiind un blog WordPress, interfața de administrare se încarcă mult mai repede acum).

Cum sa incepi

Comunicarea cu WSR a fost absolut transparență și rapida – poti pune orice întrebări prin e-mail sau prin chatul live de pe website-ul lor. Mai mult, după ce iti creezi contul, iti este explicat pas cu pas ce trebuie sa faci pentru a beneficia de serviciile lor (în special de cel de CDN).

Dacă nu te descurci, sau dacă iti este lene, poți apela la serviciul lor de suport și te ajuta la fiecare pas (pot chiar sa configureze ei tot ce trebuie, dacă le dai acces). Practic, după înregistrare și activarea domeniului (pe care o fac tot ei), în 3-4 zile vei vedea efectele pe website-ul tău.

Inregistreaza-te folosind acest link pentru a primi 20% reducere (și sa ajungi la un preț foarte avantajos).

Când este util

Dacă ai un magazin online, rata de conversie este principala metrica pe care ar trebui sa te axezi: Cati dintre vizitatori ajung sa adauge produse în cos și sa le cumpere. Pentru a maximiza acest număr, trebuie sa lucrezi intens la îmbunătățirea experiența utilizatorilor – iar printre cele mai importante lucruri se afla viteza de încărcare. Imaginează-ti ca intri pe un magazin online și stai Jumatate de minut doar sa se încarce website-ul – destul de nefericita situația.

De asemenea, dacă ai un website de prezentare a unei companii, sau a unui portofoliu, și ai multe imagini / videoclipuri / conținut media – ele vor îngreuna încărcarea site-ului tău – WSR te ajuta prin a optimiza viteza de transfer considerabil.

Rezultate

Inainte

Testul gtmetrix inainte de optimizare (https://gtmetrix.com/reports/vladbutnaru.ro/2bN3ICxa/)

Dupa

Testul gtmetrix dupa optimizarea WSR (https://gtmetrix.com/reports/vladbutnaru.ro/FTGMXsYQ/)

Poate cel mai important, uite cum arata raportul individual inainte ca WSR sa aplice optimizarea:

Initial Server Response Time = 1.4s

Iar dupa optimizare:

Au disparut cele mai mari probleme care nu tin de structura site-ului

DOM Size-ul este generat de platforma WordPress folosita pentru acest blog si este normal sa nu aiba imbunatatiri prin serviciul WSR. Eliminarea problemei de incarcare a serverului este, poate, cea mai importanta optimizare, deoarece majoritatea potentialilor cititori / clienti vor simti sesizabil diferenta.

Alte teste de viteza a site-ului cu metrici importante:

Testul de încărcarea paginii HTML înainte de conectare: aici Viteza medie de încărcare în Europa este de 1,1 sec. 

După setările WSR de CDN: aici Viteza medie de încărcare în Europa este de 0,2 sec.

Direct de pe hosting aici.

Cu WSR aici.

Test First Byte (primul byte transferat catre vizitatori) inainte de WSR
Test First Byte (primul byte transferat catre vizitatori) dupa WSR
5.269 secunde pana vizitatorii pot interactiona cu website-ul (inainte de WSR)
2.905 secunde dupa WSR

Concluzie

Desi obisnuiesc sa fac tot ce este in puterea mea sa optimizez aplicatiile web pe care le dezvolt, pe partea de gazduire si transfer de date catre vizitatori, controlul developerilor este limitat la modul in care ne structuram fisierele CSS is JS. Ceea ce tine de cache-ul inteligent, de distribuirea continutului pe mai multe regiuni pentru o incarcare rapida si de optimizarea specifica fiecarei regiuni in parte nu este ceva ce putem controla din codul de frontend pe care il scriem.

Cel mai mult mi-a placut faptul care nu a fost necesara nicio interventie din partea mea pentru ca echipa WSR sa aplice optimizarile de continut – tot ce am facut a fost sa adaug website-ul in portalul lor si eu s-au ocupat de tot. Comunicarea a fost transparenta si deschisa, iar termenul de lucru, in cazul meu, a fost de 3 zile.

Inscrie-te si creste viteza site-ului tau acum, folosind acest link pentru a primi 20% discount.

Video

Cod c++ util pentru liceu si BAC

Motivatie

Consider ca foarte multi elevi se confrunta in liceu cu probleme de Informatica ce necesita o lista destul de lunga de comenzi / algoritmi C++. In mare, informatica din liceu este predata exact ca matematica – prezentari de algoritmi (formule) si rezolvare de probleme prin aplicarea lor. Daca ma intrebati pe mine, este departe de ceea ce inseamna cu adevarat sa inveti programare si nu are nicio tangenta cu ceea ce fac software developerii in viata de zi cu zi (de aceea interesul multor elevi este foarte scazut).

Unelte

Majoritarea dintre voi veti folosi Mingw sau Codeblocks in timpul orelor de informatica. Daca aveti de ales, va sugerez cea de-a doua optiune – datorita interfetei mai usor de folosit. Daca, in schimb, vreti sa scrieti algoritmi si sa rezolvati probleme de informatica fara sa fie nevoie sa instalati aceste aplicatii, puteti folosi https://www.onlinegdb.com/online_c++_compiler. Ruleaza in browser si il puteti folosi chiar pe dispozitive mobile (telefoane / tablete – chiar si televizoare smart).

Bucati de cod si explicatii

Inainte de toate, trebuie sa intelegeti structura fisierului main.cpp pe care o veti folosi de fiecare data cand incepeti sa rezolvati probleme:

#include <iostream>

using namespace std;

int main()
{
    int n;
    cin >> n;
    cout << "Ai introdus:" << n;
    return 0;
}

#include <iostream> – se numeste un import de librarie. Practic, aceasta linie spune compilatorului sa foloseasca toate functiile predefinite in aceasta librarie atunci cand ruleaza codul scris de noi.

iostream – sau input-output stream – este o librarie de baza C++ care iti permite sa scrii si sa citesti in si din consola aplicatiei tale. Datorita acestei librarii, poti folosi comenzile cin pentru citire si cout pentru afisare. Interesant, nu?

using namespace std – are in spate o explicatie mai elaborata, insa ce trebuie tu sa retii este faptul ca unele comenzi se afla sub diferite zone ale limbajului. In cazul de fata, comenzile cin si cout se afla in zona std, asa ca trebuie sa mentionam prin aceasta linie ca toate comenzile pe care le folosim in programul nostru se afla sub aceeasi zona, zona std. Aceasta linie este optionala, insa atunci cand nu o scriem, va trebui sa folosim std:: in fata comenzilor cin si cout -> ceea ce duce la o repetare inutila a acestora.

int main() – este functia noastra de inceput. Ea se mai numeste si entrypoint deoarece este executata prima data atunci cand rulam aplicatia noastra. In C++, fiecare functie are o valoarea returnata (in cazul nostru int – numar intreg), un nume (in cazul nostru main) si o serie de parametri aflati intre parantezele rotunde(in cazul nostru niciunul ()). Cel mai probabil, in timpul anilor de liceu, nu va trebui sa scrii functii de sine statatoare noi, ci va trebui sa scrii tot codul sub aceasta functie entrypoint.

return 0 – este valoarea returnata. Stim din explicatia anterioara ca acel int din int main() corespunde valorii returnate (o functie poate returna sau nu o valoare celui care o apeleaza). Suntem obligati sa returnam un numar intreg atunci cand definim functia main, iar noi alegem sa returnam 0 din obisnuinta.

Variabile

Pentru a putea rezolva problemele propuse, de cele mai multe ori avem nevoie sa lucram cu date de intrare si date de iesire. Acestea trebuiesc salvate in memoria calculatorului nostru – si vom face asta folosindu-ne de variabile.

Poti sa te gandesti la variabile ca la niste cutii. Fiecare cutie poate tine doar un obiect, iar pentru ca un obiect sa incapa in cutie, va trebui sa fie de un anumit tip.

In C++ avem cateva tipuri de astfel de cutii de baza, care se numesc primitive:

  • int – numere intregi (pozitive sau negative)
  • double – numere reale (pozitive sau negative)
  • long – numere intregi mari
  • long long – numere intregi foarte mari
  • short – numere intregi mici
  • char – un singur caracter (litera sau simbol) aflat intre apostroafe ‘ ‘
  • bool – adevarat / fals (true/false)

In fiecare cutie din aceste tipuri de mai sus se poate adauga un singur obiect de acelasi tip.

int a = -5;
double b = 4.5;
char c = 'c';
bool d = true;

Siruri / arrays

Limbajul C++ ne permite sa avem insiruiri de astfel de cutii (variabile). Daca avem nevoie sa tinem minte o lista de numere, de exemplu, vom putea declara un array de cutii de tip int in care sa tot adaugam numere. Trebuie sa avem grija la lungimea unui astfel de array, deoarece ea nu se va mari / micsora in functie de cate numere adaugam in acesta.

De asemenea, trebuie sa avem grija cum numaram elementele dintr-un array, deoarece, in programare, numararea incepe de la 0, nu de la 1. De exemplu, daca vom declara un sir de lungime 5, vom putea adauga variabile in acesta incepand cu pozitia 0 si terminand cu pozitia 4.

int numerePare[5] = {2, 4, 6, 8, 10};
cout << numerePare[1] // va afisa 4

Cei mai multi elevi gresesc la numararea elementelor dintr-un array, deci ai grija la acest detaliu.

Operatii matematice

Operatiile matematice sunt destul de simple:

  • Adunarea se poate face cu semnul „+” pus intre 2 sau mai multe variabile / numere.
  • Scaderea se poate face cu semnul „-” pus intre 2 sau mai multe variabile / numere.
  • Impartirea se poate face cu semnul „/” pus intre 2 sau mai multe variabile / numere.
  • Inmultirea se poate face cu semnul „*” pus intre 2 sau mai multe variabile / numere.
  • Restul impartirii se afla folosind semnul „%” (citit MOD) pus intre 2 sau mai multe variabile / numere.
int rezultat = 10 / 2; //5
int restulImpartirii = 12 % 5; //2
int inmultire = 10 * 10; //100
int adunare = 10 + 7 + 2; //19
int scadere = 10 - 2; //8

Structuri decizionale

Cand construim logica unui program, avem de cele mai multe ori nevoie de ramificatii. Aceste ramificatii pot fi introduse de structura decizionala if. Daca numarul pe care mi l-ai dat este par, afiseaza „Par”, asltfel, afiseaza „Impar”.

int numar = 10;
if (numar % 2 == 0){
   cout << "Par";
}
else {
   cout << "Impar";
}

Aici trebuie doar sa ai grija la comparatori:

  • Pentru a verifica egalitatea, foloseste „==” (nu „=”).
  • Pentru a verifica daca un numar este mai mare decat altul, foloseste „>”.
  • Pentru a verifica daca un numar este mai mic decat altul, foloseste „<„.
  • Pentru a verifica daca un numar este mai mare sau egal sau mai mic sau egal, foloseste „>=” sau „<=”.
  • Pentru a verifica daca un numar este diferit de altul, foloseste „!=”.

Structuri repetitive

Pentru a executa o comanda de mai multe ori, poti folosi structurile repetitive din C++ :

  • for
  • while
  • do – while
//executa o linie de 5 ori
for (int i = 0; i < 5; i++){}
//executa o linie cat timp a < b
while (a < b){}
//executa o linie cat timp a < b, dar cel putin o data
do{}
while (a < b);

Tutorial HTML – Cum sa faci o pagina de prezentare (partea 1)

Pagina principala – Meniul principal

Salutare! Aceasta serie de tutoriale te va invata cum sa dezvolti o pagina de prezentare completa pentru afacerea ta. Tutorialul este compus din 4 parti:

  • Pagina principala – Meniul Principal
  • Pagina principala – Continutul primei pagini
    • Hero Slider
    • Sectiuni
    • Footer
  • Pagina principala – SEO
  • Pagina de contact – Formular de contact

Astazi vom aborda prima parte – cum sa facem meniul principal pentru site-ul nostru de prezentare.

Meniul principal

Pentru aceasta serie de tutoriale, vom dezvolta un site web pentru o companie fictiva MySa care se ocupa cu design-ul caselor. Meniul principal trebuie sa contina link-uri catre toate paginile site-ului web, pentru ca utilizatorul sa poata ajunge la informatia dorita in cel mai scurt timp.

Aplicatii folosite

Pentru acest tutorial vom folosi Visual Studio Code si Google Chrome.

Structura de fisiere

Fisierele care compun un website sunt, de obicei, pagini html, fisiere css si fisiere javascript. Impreuna, aceste fisiere compun structura vizuala si functionala a paginilor web.

Structura fisierelor in Visual Studio Code

Bootstrap

Framework-ul Bootstrap ne ofera o lista lunga de componente care ne scutesc de scris cod duplicat. Mai toate website-urile au aceeasi structura: un meniu, un body, un footer, o pagina de contact, etc – iar acest framework ne permite sa refolosim multe din acestea in paginile noastre.

Pentru a folosi Bootstrap, va fi nevoie sa adaugam un link catre sursa acestuia in pagina noastra principala index.html.

<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"/>
</head>
<body>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>
</body>
</html>

In interiorul tag-ului body vom adauga codul paginii noastre. Tot ce adaugam aici va fi vizibil atunci cand un vizitator va accesa website-ul nostru. Vom incepe cu meniul principal.

Meniul principal

Vom folosi componentul navbar, parte din Bootstrap, care ne permite sa definim un meniu principal de navigare. Acest tag html va trebui adaugat in interiorul tag-ului body si va arata asa:

<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <div class="container-fluid">
    <a class="navbar-brand" href="#">MySa</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarNav">
      <ul class="navbar-nav">
        <li class="nav-item">
          <a class="nav-link active" aria-current="page" href="index.html">Acasa</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="despre.html">Despre</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="contact.html">Contact</a>
        </li>
      </ul>
    </div>
  </div>
</nav>

Daca vei salva fisierul index.html in care am adaugat codul de mai sus folosind browser-ul preferat (Chrome / Firefox / etc), vei observa noul meniu afisat:

Meniul companiei MySa

Daca doresti sa schimbi numele companiei pentru ca dezvolti site-ul web, poti modifica linia de cod de mai jos, inlocuind textul MySa cu orice doresti.

 <a class="navbar-brand" href="#">MySa</a>

Dupa cum observi, folosim un tag de tip <a>, atribuindu-i clasa de stil navbar-brand pe care o imprumutam din fiserele de stil ale framework-ului Bootstrap si care face textul pe care il scriem noi sa apara in partea din stanga sus si sa aiba o marime de font mai mare decat celelalte butoane ale meniului.

Restul butoanelor (Acasa, Despre si Contact) se pot modifica schimband respectivul text din fisierul sursa index.html.

Vei observa la urmatoarea linie de cod ca butonul Acasa este diferit fata de celelalte 2.

<a class="nav-link active" aria-current="page" href="index.html">Acasa</a>

Clasa „active” si atributul aria-current=”page” face ca acest meniu sa apara colorat negru, in comparatie cu celelalte butoane care sunt gri. Atunci cand vom dezvolta celelalte pagini, vom adauga aceste elemente in meniul corespondent acelei pagini.

Culori si personalizare

Observam ca meniul imprumutat din Bootstrap are fundalul gri si textul negru – daca dorim sa schimbam aceste culori, trebuie sa adaugam clase de stil in fisierul nostru de stil style.css.

De exemplu, daca dorim sa schimbam culoarea butoanelor inactive din meniu, va trebui sa suprascriem stilul imprumutat din Bootstrap. Pentru a face acest lucru, in fisierul style.css, am adaugat urmatoarele:

.navbar-light .navbar-nav .nav-link {
    color: brown;
}

Motivul pentru care am adaugat culoarea brown pentru clasele navbar-light, navbar-nav si nav-link este dat de locatia butoanelor in interiorul paginii noastre. Daca te vei uita in fisierul index.html, vei observa ca fiecare meniu are clasa nav-link, care se aflat sub navbar-nav, care la randul sau este situat sub navbar-light.

Am adaugat un link catre acest fisier imediat sub linkul catre Bootstrap, in index.html.

<link href="style.css" rel="stylesheet"/>

Iar rezultatul este:

Am schimbat culoarea meniurilor inactive

In acest moment, fiecare buton din meniu ne trimite catre o pagina html diferita.

  • Acasa – ne trimite pe index.html
  • Despre – ne trimite pe despre.html
  • Contact – ne trimite pe contact.html

Va trebui sa adaugam aceste fisiere in proiectul nostru:

Noile fisiere html

Continutul acestor pagini va fi similar (pentru. moment) – am copiat continutul din fisierul index.html si l-am pus in cele 2 noi pagini. Singura diferenta va fi, asa cum am spus anterior, butonul din meniu care va avea cele 2 particularitati: clasa „active” si atributul aria-current=”page”.

Meniul din despre.html:

  <a class="nav-link active" aria-current="page" href="despre.html">Despre</a>

Meniul din contact.html:

  <a class="nav-link active" aria-current="page" href="contact.html">Contact</a>

Nu uitam sa eliminam aceste atribute din vechiul buton acasa.

Concluzie

Sper ca acest tutorial te-a ajutat si ca ai reusit sa intelegi cele explicate. Arhiva cu fisierele o poti gasi mai jos. Spor la treaba!

Cum mi-am facut conexiunea de acasa sa fie „always online”

Dupa cum bine stiti, lucrez remote. Asta inseamna ca sunt dependent de o conexiune la Internet – asa cum multi suntem in aceasta perioada.

Se pare ca perioada aceasta a dat peste cap infrastructura providerilor de Internet – din Martie, retelele pica aproape saptamanal din cauza supraincarcarii. Au fost destule momente in care a trebuit sa ma conectez la hotspot-ul de pe telefon pentru a duce la bun sfarsit meetingurile (si nu e tocmai placut atunci cand trebuie sa prezint o functionalitate noua si sa partajez ecranul). A fost nevoie de cateva luni bune pana sa ma decid la o solutie optima, dar am gasit-o!

Router Multi Wan TL-R470T+

Am plecat de la ideea ca daca un ISP pica, sigur celalalt merge, si mi-am facut un al doilea abonament de date fixe (Telekom + Digi). Acum, cu doua conexiuni, bineinteles ca voi avea 2 echipamente (routere wireless) cu SSID-uri diferite (nume de retea diferite) si parole diferite – un prim pas spre a obtine ceea ce imi doresc.

Problemele acestei situatii:

  • Daca o retea pica, trebuie sa conectez toate dispozitivele din casa la a doua retea (si unele dispozitive sunt foarte greu de reconectat, precum aspiratorul, aerul conditionat, Alexa, etc.).
  • Daca o retea pica si isi revine apoi, punctul 1 trebuie refacut.
  • Echipamentele de la providerii de Internet au o acoperire wireless destul de limitata.

Solutia pe care am gasit-o este acest router multi-wan de la TP-Link care poate combina cele doua conexiuni de la ISP si sa decida el care este cea mai stabila, iar in caz ca una pica, muta automat toate conexiunile pe cea definita ca back-up.

Pssst…: Daca vrei sa inveti Java de la 0, sau vrei sa iti aprofundezi cunostintele, am cursul perfect pentru tine – vezi aici

Mai mult, acest dispozitiv face load-balancing in sensul in care traficul de pe fiecare dispozitiv este redirectionat in mod egal pe cele doua conexiuni la Internet provenite din cele doua porturi WAN. Avantaje?

  • Daca o retea pica, trecerea se face automat pe cealalta, in mai putin de 1 minut.
  • Din router-ul acesta plec cu un cablu UNT catre un router Wireless care este mult mai bun decat cele date de operatorii de retea.
  • Avand peste 10 device-uri conectate la aceeasi retea wireless, load balancer-ul va ruta fiecare request catre cea mai libera retea de Internet, rezultand o performanta foarte buna.

Am lucrat remote de la o cabana jumatate de saptamana si uite ce concluzii am tras

Lucrez remote de aproape 3 ani de zile. Motivul principal care m-a determinat sa renunt la mersul la birou a fost timpul – nu ai idee cat de mult inseamna cele doua ore pierdute fie in trafic, fie alegandu-ti hainele, fie coborand si urcand etajele cladirilor de birouri. De fapt, facand un calcul, am ajuns sa castig 3.5 ore in fiecare zi a saptamanii (si sa evit multe situatii enervante).

ActivitateTimp / saptamanaLa birouRemote
Pregatiri4 ore– 4– 1
Drum10 ore– 100
Urcat / Coborat din cladire2 ore– 20
Mancare la restaurant5 ore– 50
Vorbit random cu oameni prin birou2 ore– 20
– 23 ore– 1 ora
Un calcul grosolan al timpului pierdut la birou

Asadar, 23 de ore din saptamana le pierdeam cu maruntisuri, sa nu mai vorbim de nervii generati de traficul marilor orase, frustrari adunate de la colegi si consolidate de atitudinea managerilor, etc. Toate aceste resurse erau irosite fara sens, doar pentru placerea de a merge la birou. Imediat ce am facut o retrospectiva a ultimelor luni de pandemie, in care mai toata lumea din domeniul IT sta tolanita pe canapeaua proprie in timpul sedintelor, am inteles, de fapt, ca stilul de viata impus de acest virus a deschis ochii mai multor impatimiti ai cafelelor lungi in fata multinationalelor la care lucreaza.

Voi am aborda subiectul larg la muncii remote, prezentant atat aspectele pozitive, cat si cele pe care nu ai vrea sa le auzi – insa acum hai sa vorbim despre experimentul meu (si a sotiei mele, evident), de a lucra jumatate de saptamana dintr-o cabana din Romania.

Cu laptopurile la Blumenhof

Am ales o destinatie nu foarte indepartata casei noastre, si anume Gura Humorului. Am cautat ceva care sa ne permita sa stam cat mai mult afara, sa fie spatioasa si, bineinteles, sa aiba o conexiune la Internet care sa ne permita amandurora sa ne desfasuram activitatea in conditii optime. Din nefericire, Internetul nu a fost grozav, dar ne-am putut baza pe o amplasare corecta a telefoanelor pe balcon si hotspot-ul pornit.

Cabana este foarte aproape de manastirea Voronet care, din fericire, nu are foarte multi turisti in timpul saptamanii. Restaurantul de langa locatie era decent, insa sunt o gramada de locuri cu mancare foarte buna la 15-20 de minute de mers cu masina – ceea ce ne-a bucurat enorm.

Avand in vedere pandemia de Covid, am incercat sa stam cat mai feriti de lume, insa nu a fost greu sa gasim o carare prin padure care sa ne ofere aer curat si lumina din belsug. Ce poate fi mai relaxant decat sa iei o pauza de 15 minute in care sa te plimbi liber pe munte?

Pssst…: Daca vrei sa inveti Java de la 0, sau vrei sa iti aprofundezi cunostintele, am cursul perfect pentru tine – vezi aici

Daca in perioada asta consideri ca ar fi fain sa iti iei laptopul in geanta si sa lucrezi din alta parte decat din propria locuinta, uite cateva sfaturi utile:

  1. Asigura-te ca ai toate accesoriile de care ai nevoie in situatii mai putin placute. O baterie externa cu o capacitate generoasa, o tripla, un router portabil 4G si o gama larga de adaptoare nu ar trebui sa lipseasca din bagajul tau.
  2. Incearca sa intrebi in prealabil despre starea conexiunii la internet – desi multe cabane vor spune ca „Da, domle’, este ‘net„, citeste recenziile celorlalti turisti – poate dai de cineva care s-a aflat in situatia in care vrei sa fii tu.
  3. Cauta locatii care au mancare buna sau care iti ofera o bucatarie – astfel incat sa nu pierzi jumatate de zi gandindu-te ce sa mananci sau ore intregi pe drum pana la primul restaurant.
  4. Alege cabane izolate, pentru a nu risca sa ai un club sau un bar la 10 metri de balconul tau – linistea este esentiala pentru a putea lucra.
  5. Mergi in extra-sezon, de marti pana joi – pentru a evita supra-aglomeratia atat pe drum, cat si la cazare.
  6. Alegeti o camera mare, cu balcon deschis – multi turisti nu dau importanta camerelor in care sunt cazati atunci cand se duc la munte (pentru ca nu petrec prea mult timp in ea), dar tu vei sta macar 8 ore, si nu vrei sa fii constrans de dimensiunile mici sau lipsa aerului conditionat.
  7. Daca esti obisnuit sa lucrezi de pe un desktop (asa cum sunt si eu), fa-ti un setup care sa iti permita sa te conectezi remote pe unitatea de lucru de pe laptop-ul pe care il iei cu tine in calatorie. Nu doar ca este cea mai sigura modalitate de lucru, dar este si cea mai rapida. Voi scrie un articol separat despre setup-ul meu si cum am maximizat sansele de a lucra chiar daca raman fara curent sau inernet.
  8. Alege o pereche de casti de incredere, cu microfon care sa elimine cat mai mult zgomot de fundal, altfel nu vei putea intra in meeting-uri din balcon sau din padure si vei fi mereu nevoit sa ramai in camera de cazare.
  9. Pleaca cu gandul ca te vei relaxa, nu ca vei schimba doar peisajul – astfel vei fi motivat sa maximizezi activitatile pe care le vei face in pauzele de la munca.
  10. Planifica din timp calatorie, tinand cont de calendarul de la munca – nu te vei relaxa deloc daca vei pleca in saptamana in care va trebui sa faci hotfix-uri pe productie, sau in zilele dinaintea demo-urilor. Gaseste o perioada fara prea multe urgente (prima saptamana de sprint, de exemplu) si fructific-o la maximum!

Concluzii

Au fost de departe cele mai relaxante zile de lucru de anul acesta. Desi greu de crezut, m-am simtit ca in concediu, desi am petrecut la fel de mult timp lucrand ca atunci cand lucrez in conditii normale. Daca nu esti decis daca aceasta este alegerea potrivita pentru tine, cauta raspunsul urmatoarei intrebari: Tu ce faci in pauza de pranz? Raspunsul meu a fost: ma duc putin in padure sa iau o gura de aer.

Am facut o aplicatie care sa ma ajute sa vad in viitor

Daca titlul te-a atras – as vrea sa il dezvolt putin: Am incercat in repetate randuri sa fac o aplicatie care sa execute mai multe simulari financiare care sa ma ajute sa inteleg cat ar trebui sa cheltui pe zi pentru a ajunge sa economisesc o anumita suma de bani. Desi unele incercari au fost mai reusite decat altele si au avut rezultate apropiate de adevar, am ales sa descriu putin ideea de baza pentru cei care vor sa invete Java prin exemple practice.

Concept

Aplicatia pe care vreau sa o fac trebuie sa aiba 2 mari functionalitati:

  1. Sa poata sa imi spuna cati bani voi avea la finalul fiecarei luni, incepand de astazi, pana la data pe care o aleg eu.
  2. Sa poata sa imi spuna cati bani pot cheltui in fiecare zi pentru a ajunge la o anumita suma economisita la o data aleasa de mine.

Pentru ca acestea sa aiba sens, am nevoie de:

  • Balanta totala la momentul curent.
  • Suma de bani castigata la finalul fiecarei luni.
  • Suma fixa de bani pe care o cheltui lunar (rate, facturi, etc).

Arhitectura

Fiind un utilitar destul de light, am ales sa nu-i fac interfata grafica, asa ca am ales sa construiesc o aplicatie de tip CLI (command line interface). Pentru a citi datele, am ales sa imi formez o structura de fisier JSON care sa descrie datele initiale (si pe care aplicatia sa il citeasca atunci cand o pornesc). Cele 2 functionalitati de sus le voi ingloba in 2 comenzi simple, iar calea catre fisierul de configurare o voi da prin comanda initiala.

Avand in vedere datele descrise mai sus, am ales urmatoarea structura de JSON:

{
	"name": "Vlad",
	"balance_ron": 1000,
	"balance_eur": 500,
	"balance_usd": 50
}

Campurile sunt urmatoarele:

Nume campTip de dateDescriere
nameStringnumele fisierului de configurare. In caz ca voi dori sa am mai multe simulari, voi putea sa creez cate fisiere vreau
balance_rondoublebalanta totala a conturilor in moneda RON
balance_eurdoublebalanta totala a conturilor in moneda EUR
balance_usddoublebalanta totala a conturilor in moneda USD

Pssst…: Daca vrei sa inveti Java de la 0, sau vrei sa iti aprofundezi cunostintele, am cursul perfect pentru tine – vezi aici

Mapez JSON-ul acesta in clasa Configuration

import com.google.gson.annotations.SerializedName;


public class Configuration {
	
	@SerializedName("name")
	private String name;
	
	@SerializedName("balance_ron")
	private double balanceRon;
	
	@SerializedName("balance_eur")
	private double balanceEur;
	
	@SerializedName("balance_usd")
	private double balanceUsd;
	
}

Pentru lucrul cu JSON-ul si interfata CLI, am ales urmatoarele dependinte maven:

	<dependencies>
		<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
		<dependency>
			<groupId>com.google.code.gson</groupId>
			<artifactId>gson</artifactId>
			<version>2.8.6</version>
		</dependency>
		<dependency>
			<groupId>commons-cli</groupId>
			<artifactId>commons-cli</artifactId>
			<version>1.4</version>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-math3</artifactId>
			<version>3.6.1</version>
		</dependency>
</dependencies>

Avand in vedere ca acest utilitar nu va primi update-uri (ci le voi include intr-o aplicatie separata), am ales sa includ logica matematica in aceeasi clasa care va manipula si user IO-ul. Folosind libraria commons-cli, pot defini cateva metode standard care sa se ocupe de interactiunea cu utilizatorul:

	/**
	 * Generates application command line options
	 *
	 * @return application <code>Options</code>
	 */
	private Options getOptions() {
		Options options = new Options();

		options.addOption("f", "filename", true, "personal financial data file");
		return options;
	}

Metoda care defineste posibilele optiuni ale utilizatorului atunci cand ruleaza utilitarul. In cazul meu, voi avea nevoie de calea catre fisierul JSON de configurare initiala (cel cu balantele).

/**
	 * Prints application help
	 */
	private void printAppHelp() {

		Options options = getOptions();

		HelpFormatter formatter = new HelpFormatter();
		formatter.printHelp("JavaStatsEx", options, true);
	}

Metoda care va afisa help-ul atunci cand utilizatorul va rula aplicatia cu flagul –help sau -h.

/**
	 * Parses application arguments
	 *
	 * @param args application arguments
	 * @return <code>CommandLine</code> which represents a list of application
	 *         arguments.
	 */
	private CommandLine parseArguments(String[] args) {

		Options options = getOptions();
		CommandLine line = null;

		CommandLineParser parser = new DefaultParser();

		try {
			line = parser.parse(options, args);

		} catch (ParseException ex) {

			System.err.println("Failed to parse command line arguments");
			System.err.println(ex.toString());
			printAppHelp();

			System.exit(1);
		}

		return line;
	}

Metoda care va citi datele introduse de utilizator.

/**
	 * Runs the application
	 *
	 * @param args an array of String arguments to be parsed
	 */
	public void run(String[] args) {

		CommandLine line = parseArguments(args);
		if (line.hasOption("filename")) {
			String fileName = line.getOptionValue("filename");
			
			try {
				entryPoint(fileName);
			} catch (java.text.ParseException e) {
				e.printStackTrace();
			}

		} else {
			printAppHelp();
		}
	}

Metoda care va citi comanda initiala de rulare si va apela entryPoint folosind calea catre fisierul de configurare.

private void entryPoint(String configurationFile) throws java.text.ParseException {
		ConsolePrinter.printWelcome();
		ConsolePrinter.readConfiguration(configurationFile);
	
		boolean running = true;
		while (running) {
			ConsolePrinter.printMenu();
			int option = ConsolePrinter.readInt("Pick option: ");

			if (option == 0)
				running = false;

			if (option == 1) {
				String dateString = ConsolePrinter.readDate("Target date: ");
				double spendingsPerDay = ConsolePrinter.readDouble("Average spendings per day:");
				double fixedPayments = ConsolePrinter.readDouble("Average fixed payments per month:");
				double earningsPerMonth = ConsolePrinter.readDouble("Average earnings per month: ");

				DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
				Date date = formatter.parse(dateString);

				LocalDateTime now = LocalDateTime.now();
				LocalDateTime wantedDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();

				String leftAlignFormat = "| %-10s | %-4s |%n";
				System.out.format("+-----------+-----------+%n");
				System.out.format("| Month     | Balance   |%n");
				System.out.format("+-----------+-----------+%n");
				double startingBalance = ObjectStorage.configuration.getBalanceRon();
				for (LocalDateTime d = now; d.isBefore(wantedDate); d = d.plusMonths(1)) {
					startingBalance += (float) (earningsPerMonth - spendingsPerDay * 30 - fixedPayments);
					System.out.format(leftAlignFormat, d.getMonth().toString(), startingBalance + "");

				}
				System.out.format("+------------+---------+%n");

				ConsolePrinter.showLine("At given date, you will have: " + startingBalance + " in your accounts");

			}

			if (option == 2) {
				String dateString = ConsolePrinter.readDate("Target date: ");
				double targetSum = ConsolePrinter.readDouble("Target economies: ");
				double fixedPayments = ConsolePrinter.readDouble("Average fixed payments per month:");
				double earningsPerMonth = ConsolePrinter.readDouble("Average earnings per month: ");

				DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
				Date date = formatter.parse(dateString);

				LocalDateTime now = LocalDateTime.now();
				LocalDateTime wantedDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
				double startingBalance = ObjectStorage.configuration.getBalanceRon();

				long daysBetween = ChronoUnit.DAYS.between(wantedDate, now);
				for (LocalDateTime d = now; d.isBefore(wantedDate); d = d.plusMonths(1)) {
					startingBalance += (float) (earningsPerMonth - fixedPayments);

				}

				double dailySum = (targetSum - startingBalance) / daysBetween;

				ConsolePrinter.showLine("You can spend up to: " + dailySum + " per day");
			}
		}

	}

Metoda care executa logica te calcul pentru cele doua functionalitati. Aici am verificat ce optiune a ales utilizatorul (0, 1 sau 2) si, in functie de alegere, execut scenariul de calcul astfel:

  • Pentru option=0, voi inchide procesul aplicatiei.
  • Pentru option=1, voi cere data target, cheltuielile zilnice, cheltuielile fixe lunare si castigurile lunare, apoi voi calcula suma de bani pe care utilizatorul o va avea in balanta adaugand la balanta initiala numarul de luni * castigul lunar numarul de luni * cheltuileli fixe – numarul de zile * cheltuieli zilnice.
  • Pentru option=2, voi cere data target, suma de bani pe care utilizatorul o vrea in conturi, cheltuieli fixe lunare si castiguri lunare si voi afisa maximul de bani pe care utilizatorul o poate cheltui lunar pentru a avea in conturi suma dorita la data aleasa.

Fiind un proiect opensource, poti gasi sursa aici: https://github.com/vladutbutnaru/finvisor.

Pentru a rula aplicatia, nu trebuie decat sa iti configurezi singur un astfel de JSON, sa rulezi mvn clean install pe proiectul clonat si apoi sa rulezi executabilul jar din folderul target folosind calea corecta catre fisier:

./finvisor.jar -f configuration/vlad.json

Tutorial Java – Operatii cu variabile numerice

System.out.println("Salut lume!");
        
        // 2 + 2 = 4 || JAVA -> 4 = 4.0
        //int < double
        int varsta = 18;
        int temperatura = -20;
        
        double litri = 2.5;
        double temperaturaAfara = -13.4;
        
        boolean adevarat = true;
        boolean fals = false;
        
        char litera = 'a';
        char simbol = '%';
        
        String cuvant = "Cuvant, Cuvant 2";
        
        double rezultat = varsta + temperatura;
        
        double rezultatNou = rezultat + 1.5;
        
        // int + double != int (nu-i place) - pierde decimala
        // int + double == double 
        double rezultatIntreg = rezultatNou + 1;
        
        System.out.println(rezultatNou);

Exercitii

  1. Reprezentati printr-o primitiva valoarea pretului unui bilet la cinema.
  2. Salvati intr-o variabila suma a 3 bilete de mai sus.
  3. Afisati aceasta variabila folosind System.out.println();
  4. Salvati intr-o variabila suma 142 + 9.38 si afisati-o.

Tutorial Java 2 – Primitive

Ca sa intelegem cum reprezentam datele in Java, putem porni de la un exercitiu de creativitate: Ce proprietati exista in jurul nostru?

Ca programatori, trebuie sa ne construim un univers digital, iar inainte de a-i oferi o logica, trebuie sa intelegem cum sa il definim. Este ca si cum ai vrea sa descrii gravitatia, fara a avea niciun concept de mar … cam greu, nu?

Ei bine, limbajele de programare ne ofera mai mlte unelte prin care noi sa ne desenam acest univers. Una dintre ele o reprezinta primitivele. O primitiva este un tip de date care poate reprezenta o anumita valoare in sfera aplicatiei noastre. In tutorialul video am definit aceasta primitiva ca pe o cutie in care putem sa introducem diverse obiecte (valori).

Este important sa intelegi de la inceput ca, in Java, fiecare cutie poate tine un anumit tip de valoare. Este precum jocul ce incape intr-o valiza, unde valiza este primitiva, iar obiectele pe care incercam sa le introducem sunt valorile noastre.

Hai sa recapitulam primitivele din Java, abordate in acest tutorial:

  • int – este acel tip de primitiva care ne permite stocarea numerelor intregi, pozitive sau negative.
    • Exemple de valori: 5 -3 100 -88
  • double – este acel tip de primitiva care ne permite stocarea numerelor rationale (cele care sunt urmate de decimale), pozitive sau negative.
    • Exemple de valori: 5.3 2.7 -4.49 10.9 .
  • char – este acel tip de primitva care ne permite stocarea unui singur caracter. Acest caracter poate fi o litera sau un simbol. Valoarea se pune intotdeauna intre apostroafe simple si nu putem reprezenta mai mult de un singur caracter.
    • Exemple de valori: ‘a’ ‘#’ ‘+’ ‘2’.
  • String – este acel tip de primitiva (este un caz mai special, veti vedea) care ne permite stocarea unui cuvant, unui grup de cuvinte ori unei fraze intregi. Valoarea se pune intotdeauna intre ghilimele duble.
    • Exemple de valori: „Ana are mere” „cuvant”.
  • boolean – este acel tip de primitiva care ne permite stocarea unei valori de adevar (true / false).
    • Singurele valori: true si false.

Sa ne delectam cu o parte de cod:

int a = 5;
double b = -4.5;
char c = '@';
String d = "tutorial";
boolean e = true;

Reguli importante

  1. Numele variabilelor trebuie sa fie unic (daca am declarat un int care se cheama a, nu avem voie sa declaram alte variabile cu numele a). Daca facem acest lucru, compilatorul nu are de unde sa stie pe care dintre ele sa o foloseasca.
  2. O variabila de un tip isi pastreaza tipul pe tot parcursul executiei programului nostru. Astfel incat sa putem fi siguri ca un int nu va avea vreodata alta valoare decat un numar intreg (pozitiv sau negativ).
  3. Numele variabilelor nu trebuie sa contina cuvinte rezervate. Un cuvant rezervat este usor de depistat: are o culoare diferita fata de numele variabilelor, spre exemplu. Cuvintele rezervate pe care le-am folosit pana acum sunt int double char String =.
  4. Numele variabilelor trebuie sa fie intotdeauna lipsite de spatii, nu au voie sa inceapa cu un numar.
  5. Numele variabilelor nu au voie sa inceapa cu un simbol.

Exercitiu

Pentru a te obisnui cu primitivele, incearca urmatorul exercitiu: Uita-te in jurul tau, depisteaza 5-6 proprietati ale obiectelor (culoare, forma, vechime, producator, nume, este electronic?, etc.) si incearca sa le reprezinti in Java printr-o primitiva din cele pe care le-am abordat acum.

Poti adauga exemplele aici, pe blog, in sectiunea de comentarii, pe Youtube, sau prin email la adresa vlad@vladbutnaru.ro

Ce am invatat din 8 ani de tutoriale facute pe Youtube

Dupa cum spune titlul, primul tutorial pe care l-am publicat pe Youtube a fost acum 8 ani si se intitula „Tutorial Photoshop – Cum sa evidentiezi un obiect din imagine

Incep prin a spune ca pe atunci nu erau atat de multe tutoriale video in limba romana. Pentru cei mai batrani, 75% din tutorialele de pe Youtube erau facute de persoane care inregistrau o fereastra Notepad in care scriau in timp ce iti aratau cum se face un anumit lucru. Sursa de inspiratie a venit, bineinteles, din state, urmarind foarte mult video-uri publicate de Twit.tv, thenewboston, si altii din aceasta categorie.

Feedback-ul de la cei ce au vizionat tutorialul a fost unul pozitiv (avea 5/5 stele, pentu ca, pe atunci, platforma avea modalitatea veche (si buna) de a oferi feedback creatorilor de continut), iar comentariile (putine, intr-adevar), au fost si ele pozitive – asta m-a motivat sa incerc sa fac si alte tutoriale video, deoarece piata era deschisa.

Prima problema de care m-am lovit a fost cea a organizarii. Erau foarte multe idei, toate necesitant minim 10-15 inregistrari diferite si, fiind la inceput, am inceput sa le inregistrez deodata pe toate, nereusind sa termin niciuna.

A doua problema a fost timpul. Inregistrarea propriu-zisa dureaza cam de 2 ori cat este video-ul final, insa editarea, exportul, upload-ul si scrierea descrierilor adaugau destul de mult timp extra si, fiind inca la scoala, imi era imposibil sa ma organizez pentru a le urca pe Youtube.

A treia mare problema a fost frica de concurenta si frica de comentarii negative. Daca v-ati expus vreodata intr-un video, stiti foarte bine ca, oricat de bine considerati voi ca a iesit produsul finit, tot apare o oarecare frica de renumitii hateri. Cu toate astea, m-am impacat cu gandul ca nisa pe care mi-am ales-o nu prea atrage astfel de specimene. Am gasit prin comentarii atat incurajari, cat si sugestii de imbunatatire – dintre care cea mai importanta a fost eliminarea muzicii de fundal – un exemplu de idee care mie mi s-a parut inspirata, insa celor de acasa li s-a parut deranjanta.

Acum, dupa 8 ani de incercari si experimente, plus 2 generatii (2 ani) de trainuit offline grupe de studenti in tehnologia Java, consider ca este timpul pentru o imbunatatire a contentului livrat. De aceea am decis sa incep un nou canal pe care sa public content mult mai calitativ decat cel vechi. Topic-ul va ramane acelasi: tutoriale de programare si tips&tricks, dar voi adauga si alte idei mai interesante pe deasupra.

Pssst… s-ar putea sa facem si live streamuri in care sa scriem cod impreuna! Va tin la curent!