27 czerwca 2013

Pauzowanie projektowe i przedwakacyjne zmiany służbowe = opuszczam IBM

10 komentarzy
Minęło parę już dni od ostatniego wpisu z cyklu "moje pierwsze kroki przy tworzeniu aplikacji pisanej w Scali, której daję czas od pomysłu do realizacji najwyżej 1 miesiąc." I nic się nie pojawiło od owych kilku dni! Projekt zamarł...niestety, bo obowiązków sporo i to rodzinnych głównie!

Najpierw zaczęło się od wyjazdu weekendowego, podczas którego napracowałem się bardzo. "Upodliłem" się pracując fizycznie i kiedy dopadłem już kompa, zaraz zatwittowałem o moim powrocie.

Powrót nie trwał jednak długo :(

We wtorek żonka obchodziła urodziny, więc znowu przytrafiło mi się odciąć od sieci. Dosłownie. Nie miałem ze sobą komputera, a w dodatku padła mi komórka, więc sieci nie widziałem przez dobre 2 dni! Odświeżające. Najbardziej zachwycona była moja żoncia (której nota bene też padła komórka!)

I tak dobrnąłem do czwartku, w którym również nie znalazłem wiele czasu na boje projektowe przy taskassinie. Widziałem komentarz Radka dotyczący stworzenia cechy (trait), który podzielam, ale niestety i dzisiaj przyszło mi zająć się innymi sprawami.

Z dniem jutrzejszym, 30 czerwca, kończę pracę w IBM.

Postanowiłem podreperować moją znajomość branży finansowej i od 1 lipca (poniedziałek) przechodzę do Citi na stanowisko (użyję mojego tłumaczenia) szefa technicznego zespołu programistycznego (Credit Front Office - Warsaw Team Lead).

Będzie Scala, Clojure i problemy analizy dużej ilości danych finansowych. Będą też ludzie, których znam osobiście i z którymi zawsze marzyłem usiąść przy jednym kompie, aby spędzić kilka dłuższych chwil, chociażby na dyskusji o niczym. Teraz dostaję to na tacy! Raportuję do kierowników w Londynie i Nowym Jorku, co podtrzymuje mój entuzjazm doskonalenia języka angielskiego. Słowem wszystko, co dusza moja pragnęła bardzo. Dodać należy również, że zawsze zastanawiało mnie, jak to jest być po drugiej stronie flanki - poza sektorem IT. Teraz będzie okazja zmaterializować marzenia.

Nie zostawiam WebSphere i rozwiązań IBM, bo uważam je za stosunkowo dobre, aby poświęcać im swój czas. Przyjdzie moment, w którym rozważę "kapitalizację" swojej wiedzy, ale na razie odkładam to na półkę z pomysłami. To z pewnością będzie ciekawie doświadczenie móc obserwować rozwój rynku WebSphere nie będąc już IBMerem.

Mówi się, że do końca roku zespół programistyczny ma liczyć 40 osób i potrzeba osób do programowania, jak i prowadzenia zespołów programistów od strony technicznej. Jeśli uważasz, że to robota dla Ciebie, napisz. Skontaktuję Cię z moim szefem, który zawiaduje procesem rekrutacji. To będzie niezwykła grupa pod względem osób i stosowanych technologii. Wprost robota marzenie (technicznie).

Dla zainteresowanych wycinki z opisu stanowisk:

"We are seeking highly motivated candidates to join on the ground floor of building our Framework Development Team in Warsaw, Poland.

The candidates will have responsibility for leading a team focused on development of core technology used by Citi’s Credit Trading business.

The Credit Front Office Development Team supports Credit Trading businesses in London, New York, and Asia.

Global Credit Technology is establishing a development center in Warsaw to work on core technology for our Credit Trading Businesses. This work will provide critical components for our new global strategy.

Thorough familiarity with algorithms & data structures.

Exposure to any of the following technologies is a bonus: WPF/XAML, Clojure, Scala, Hadoop, Apache Camel, HBase"

20 czerwca 2013

Dzień 7 z taskassin - wsparcie dla zadań cyklicznych

3 komentarzy
Przez ostatnie dni doświadczam powtarzającego się olśnienia użyteczności testów pisanych przed pisaniem kodu produkcyjnego. Pozostawię purystom językowym rozwikłanie zagadki, czy można być oświecanym tym samym zdarzeniem wielokrotnie (bo w końcu raz oświeconym trudno oczekiwać, że można zostać nim ponownie powtórnie przez to samo wydarzenie) i wracam do taskassin, w którym pojawiło się wsparcie dla...powtarzających się...zadań (a niechby to były zadania olśniewające).

I tu pojawia się dylemat młodego (stażem) programisty scalowego - czy, aby nie przeładowuję klasy pl.japila.taskassin.Task nadmiarowymi atrybutami? Dzisiaj dodałem recurring, recurTimes oraz intervalUnits. Czy, aby nie za wiele jak na jedno pojęcie w aplikacji?! Co zasugerujesz młodszemu (stażem)?

Dodatkowym problemem mentalnym jest jednostka czasu, która się pojawia tu i tam. Na razie jest to po prostu Int, ale coś mi mówi, że powinienem już teraz zwrócić uwagę na wyrażenie czasu w bardziej specjalizowany sposób, np. z użyciem faktycznych jednostek czasu jak minuta, godzina, nawet jeśli jedyną byłaby godzina lekcyjna (aka kwadrans). Sugestie rozwiązań wielce pożądane.
case class Task(label: String, due: DateTime, timeUnits: Int = 6,
  recurring: Boolean = false, recurTimes: Int = 0, intervalUnits: Int = 0)

object TaskUtils {

  def collectTasks(ts: List[Task], hours: Int): List[Task] = {
    @tailrec
    def collectTasks(ts: List[Task], accTs: List[Task], remHours: Int): List[Task] = {
      ts match {
        case t :: tail if (remHours >= 0 && remHours - t.timeUnits >= 0) =>
          if (t.recurring) {
            val tt = t.copy(recurTimes = t.recurTimes - 1)
            val tss = tt :: tail
            collectTasks(tss, t :: accTs, remHours - t.timeUnits - t.intervalUnits)
          } else
            collectTasks(tail, t :: accTs, remHours - t.timeUnits)
        case _ => accTs reverse
      }
    }
    collectTasks(ts, Nil, hours)
  }
}
Całość dostępna jako projekt taskassin na GitHubie.

19 czerwca 2013

Dzień 6 z taskassin w Scali - funkcja zliczająca zadania z @tailrec

3 komentarzy
Ależ to mi czasu zajęło, aby wpaść na pomysł skompletowania zadań na zadaną liczbę godzin! Próbowałem foldLeft i takeWhile z List, ale potrzebowałem nie tylko gromadzić dane o wielu elementach w liście (tutaj foldLeft mógłby być pomocny), ale również przerwać jej przetwarzanie w momencie zebrania wystarczających danych (takeWhile tylko z nazwy tutaj pasował, ale operuje wyłącznie na pojedynczych elementach). Co skłoniło mnie do intensywniejszej pracy umysłowej było obsłużenie sytuacji, w której należałoby przerwać przetwarzanie przy obsłudze list nieskończonych. Paradoks polegał jednak na tym, że najprawdopodobniej taka sytuacja nie ma prawa nastąpić, albo przynajmniej nie jest tematem w obecnym stanie aplikacji (!)

Rozwiązaniem okazało się stworzenie funkcji z rekurencją ogonową (użyłem dodatkowo @scala.annotation.tailrec dla wymuszenia tej cechy podczas kompilacji), której warunkiem końcowym byłoby właśnie zebranie wystarczającego zbioru zadań na daną jednostkę czasu.
object TaskUtils {

  def collectTasks(ts: List[Task], hours: Int): List[Task] = {
    @tailrec
    def collectTasks(ts: List[Task], accTs: List[Task], remHours: Int): List[Task] = 
      ts match {
        case t :: tail if (remHours >= 0 && remHours - t.timeSpanInHours >= 0) =>
          collectTasks(tail, t :: accTs, remHours - t.timeSpanInHours)
        case _ => accTs reverse
      }
    collectTasks(ts, Nil, hours)
  }
}
Uwagi i spostrzeżenia są wielce pożądane. Całość dostępna w projekcie taskassin na GitHubie.

18 czerwca 2013

taskassin na GitHubie dzień 3-5 = trait do zestawienia środowiska testu oraz ignore

4 komentarzy
Kontynuuję moje boje przy realizacji pomysłu napisania aplikacji w Scali - taskassin - w jeden miesiąc i mimo braku spektakularnych postępów, w pewnym sensie jestem zadowolony - zaczynam dostrzegać zalety pisania testów zanim powstanie kod produkcyjny aplikacji.

Lektura scaladoc dla org.scalatest.FunSpec zwróciła moją uwagę na Instantiating fixture traits jako mechanizm tworzenia środowiska wykonania testu. W ten sposób zarzuciłem cechę org.scalatest.BeforeAndAfter.
trait Fixture {
  val now = DateTime.now
  val t1 = new Task("t1", now, 10)
  val t2 = new Task("t2", now + 2.hours)
  val t3 = new Task("t3", now - 2.hours)

  def compByDueDate(t1: Task, t2: Task) = t1.due < t2.due
  val ts = List(t1, t2, t3) sortWith compByDueDate
}

describe("List of three tasks (with 2 hours in between)") {
  it("should pop tasks by due order") {
    new Fixture {
      assert(ts.head === t3)
    }
  }
}
Już widziałem taką konstrukcję w trakcie kursu Functional Programming Principles in Scala, ale nie bardzo rozumiałem tej konstrukcji. Tym razem trafiłem na nią z innej strony - jakby od dołu, gdzie trafiłem na problem, którego rozwiązaniem było właśnie zastosowanie tej konstrukcji z utworzeniem instancji cechy. To lubię!

Poza tym przez moment mogłem nacieszyć się z dobrodziejstw metody ignore dla nowej funkcjonalności, którą niestety nie wiedziałem, jak oprogramować. Piszę test, aby się dowiedzieć - liczę, że implementacja wyjdzie w praniu, kiedy będę realizował stronę użytkownika (czym jest właśnie test). Tylko dlaczego nie mogę znaleźć scaladoc dla ignore?! Może ktoś mógłby mi pomóc, proszę?

Zmiany są dostępne w projekcie taskassin na GitHubie.

15 czerwca 2013

Męk intelektualnych kontynuacja - taskassin na GitHubie dzień 2

5 komentarzy
Wczorajszych, piątkowych męk intelektualnych związanych z tworzeniem aplikacji taskassin w Scali nie mniej i dzisiaj, w sobotę. Mimo braku czasu na specjalnie długie zastanawianie się, co i jak należałoby zrobić, aby poprawić moją sytuację, usprawniłem TaskListTest, w którym próbuję się odnaleźć i przekuwam idee w kod.

Dzisiaj postanowiłem zanurzyć się w dokumentacji ScalaTest, aby nie skończyć z przekopiowaniem części kodu testu. W ten sposób znalazłem metodę pending, która (jak możnaby wywnioskować z jej nazwy) w ciele metody testującej pozwala na opóźnienie momentu, w którym test faktycznie powstanie. Innymi słowy, wiesz, że taki test musi powstać, ale nie bardzo wiesz, jak należałoby go napisać (aka zaimplementować). Sprytne.

W ten sposób powstał test jak poniżej.
describe("List of three tasks (with 5 minutes in between)") {
  it("should return the tasks for today") (pending)
}
Wykonanie takiego testu przechodzi poprawnie, ale oznaczone jest żółtym kolorem.

To lubię!

Skorzystałem również z potrójnej równości, która przy niepomyślnym porównaniu wyświetla różnice w bardziej zrozumiałej postaci, z dokładną informacją o różnicy.

Ostatnią zmianą było użycie before z traitu org.scalatest.BeforeAndAfter.
before {
  val t2 = new Task("t2", DateTime.now + 2.minutes)

  /* http://mkaz.com/solog/how-to-sort-collections-in-scala */
  /* sort by due date */
  def compByDueDate(t1: Task, t2: Task) = t1.due < t2.due

  ts = List(t2, t1) sortWith compByDueDate
}
Krótka lektura Getting started with FunSpec, która zajęła mi bagatela 10 minut, a wiedzy i zmian ogrom (na długie godziny). Niestety kodu produkcyjnego wciąż mało. Zmiany są dostępne w projekcie taskassin na GitHubie.

14 czerwca 2013

Taskassin na GitHubie dzień pierwszy (oficjalnie)

0 komentarzy
Cóż za kuriozalna sytuacja! Wiem, że potrzebuję aplikację, potrafię ją napisać, a jednak wciąż nie wiem, od czego zacząć. Mam wszystko, a jakbym nie miał niczego.

Ktoś z głową powiedziałby, że wystarczy przecież zacząć od pierwszej funkcjonalności, która miałaby znaleźć się w aplikacji. A mimo wszystko, nie wiedziałem wciąż, jak zacząć. To znaczy, wiem, co chcę, ale nie wiem, jak zacząć.

Nie miałeś/-aś tego wcześniej? Mnie ciągle dopada. A szczególnie, kiedy znajduję się w nowym środowisku, a Scala właśnie takim środowiskiem jest...wciąż.

To był ten właśnie moment, w którym zacząłem zastanawiać się nad stworzeniem testów, które "wymusiłyby" na mnie napisanie wyłącznie koniecznej funkcjonalności mojej przyszłej aplikacji. To jest nie pierwszy już raz, kiedy doświadczam tego olśnienia, w którym przekonuję się o słuszności metody "najpierw testy, później kod aplikacji".

I tak właśnie zacząłem moje pierwsze kroki przy tworzeniu aplikacji pisanej w Scali, której daję czas od pomysłu do realizacji najwyżej 1 miesiąc. Nie będzie lekko, ale muszę spróbować. Właśnie teraz jest odpowiedni moment.

Zaintrygowany/-a? Można śledzić moje poczynania na GitHubie - projekt taskassin.