2020年2月29日土曜日

Programming Kubernetes: Developing Cloud-Native Applications

Programming Kubernetes

by Stefan Schimanski, Michael Hausenblas
Released July 2019
Publisher(s): O'Reilly Media, Inc.
ISBN: 9781492047094
Explore a preview version of Programming Kubernetes right now.

O’Reilly members get unlimited access to live online training experiences, plus books, videos, and digital content from 200+ publishers.What the book is for?
The books describes about how to customize kubernetes engine itself. It doesn't describe about how to make an application on kubernetes. Thus it helps to understand how kubernetes controllers and components works.

Programming Kubernetes

Who should read the book?

Anyone who would like to understand controllers and components running under the hood.
Anyone who would like to the architecture of kubernetes.
Anyone who would like to make custom controllers. 
Anyone who aspires to be a kubernetes contributer.
Anyone who would like to know about client-go library. 



Impression

The book is for advanced level kubernetes developers. Before reading the book, it is recommended to have understanding on what kubernetes controllers, API servers and Operators are and how they behave. Some experience of kubernetes application development might be good to understand the book deeply.




2019年12月22日日曜日

Designing Distributed Systems

Designing Distributed Systems

Patterns and Paradigms for Scalable, Reliable Services
By Brendan Burns
Publisher: O'Reilly Media
Release Date: February 2018
Pages: 166

Without established design patterns to guide them, developers have had to build distributed systems from scratch, and most of these systems are very unique indeed. Today, the increasing use of containers has paved the way for core distributed system patterns and reusable containerized components. This practical guide presents a collection of repeatable, generic patterns to help make the development of reliable distributed systems far more approachable and efficient.What the book is for?
The book describes about example of architecture which is assumed to be built on kubernetes. Yaml files for kuberenetes are also included with explanation as well as the codes.

Who should read the book?

Anyone who would like to know design and architecture patterns for kubernetes.


Impression

It's good as a recipe book. Some basic and easy to apply architecture patterns are described with use cases. It should be one to be recommended to every kubernetes application developers.


2019年8月12日月曜日

SCRUM BOOT CAMP THE BOOKを読んでみた

SCRUM BOOT CAMP THE BOOK




スクラムについて一通り学べる。基礎編と実践編の二部構成になっている。
基礎編で用語や概念が説明され、実践編ではそれをどのように適用していけばよいかが説明されている。

座学で得られる限りの情報はこの本で学べるのではなかろうか。

特に実践編ではスクラムを現場にどのように導入していく様子が漫画のストーリで描かれており、イメージが付きやすい。

スクラム導入のための本としては良本。

2019年1月12日土曜日

「エンジニアのためのマネジメントキャリアパス」を読んで管理職について考えてみた


エンジニアのためのマネジメントキャリアパス ―テックリードからCTOまでマネジメントスキル向上ガイド


を読んでみた。

入社されたばかりの被管理者であるSoftware Engineerから始まり、チームを束ねるTech Lead(TL)、管理職や管理職の管理職、そしてVP of Engineering(VPoE)やCTOなどの役職について、期待される役割や課題などを説明している。ざっくりと昨今のTech界隈の役職を俯瞰するのには最適の一冊であろう。

よくまとまってて読みやすい書籍ではある。ただ、ちょっと身も蓋もない言い方になるのだが、会社の役職なんて同じ名前でも役割が違うので、これを読んでどう活用するかは若干難しい。原著は米国の書籍であるので、当然のこととして、日米の文化的・法律的な差異もあるはずである。技術書のように、これを教科書として絶対視しても意味がないので、著者の界隈ではこういう共通認識で回ってるのだろう、といった参考程度に勉強するのが好ましいのであろう。


一点だけ大きく興味をそそられた箇所があった。
5.1節の「ITスキルの維持」の記述のところである。

管理職に転向した後の技術的知識のアップデートに関する主張であり、これ以上コードを書いても技術力が頭打ちになるラインまでは管理職になってもコードを書き続けよう、ということであった。技術力がしっかりと身につくまでは、管理職としても大成できない。そして上級の管理職になってからも何らかの技術的コミットメントを続けるべきだ、と。この意見はとても正しく思える。

私もソフトウェアエンジニアとしてのキャリアの中で、エンジニアから管理職に転向した方を多く知っている。ほとんどの方は、Mangerに転向したのを機にコーディングを行わなくなる。その結果、例えば20世紀にWindowsアプリの開発を行っていた人が、Windowsアプリのパラダイムのままネットの技術を語ったり、クラウド以前のInternet上でWebアプリを開発していた人が、その価値観のまま、クラウドの技術を捉える、といった状況に多く遭遇した。表面的な知識は間違ってないのだが、「それは根本的に考え方が違うんだよなあ」、と突っ込みたくなる状況である。

もちろん、管理職という立場で時間の許す限りキャッチアップは続けているのだろうが、Webの前後、あるいはクラウドの前後、そしてマイクロサービスの前後といったような大きなパラダイムの変換があるときには、業務を前提に深くコードを書いていない限り自分の中の技術的パラダイムはアップデートできない。プライベートな時間で自分しか見ないレベルのコードを書いたとしても、当然のこととして仕事で向き合うのと理解の度合いは違う。業務外でコミットしているオープンソースがあったり、副業としてエンジニアを続けているのでない限り、どの立場になってもコードを書き続けない限りいずれその人の技術的価値観は時代遅れのものになるのだろう。


ただ、言うのは簡単だが、マネージャ業務をしながら開発業務にもコミットし続けるのはとても厳しい。解決策としては、マネージャとエンジニアを数年おきに、すっぱりとJob Changeするくらいしかないかもしれない。米国ではよく(たまに?)あるとは聞くが、少なくとも日本ではあまり聞いたことがない。もしかしたら今後はこのようなJob Rotationが必要とされるかもしれない。


2018年12月16日日曜日

Golangのfake google searchフレームワークをjavaで書いてみた。その2

その1を投稿したあと、某友人から「CompletableFuture使ったらもっとスッキリできるよ」って情報もらった。なので、それ使って書き換えてみた。

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
import java.util.function.Supplier;

class FakeSearch implements Supplier<String>{
    String name = null;
    public FakeSearch(String name){
        this.name = name;
    }
    @Override    public String get() {
        try {
            Thread.sleep((new Random().nextInt(10) * 1000));
        }catch (Exception e){

        }
        return name;
    }
}

public class CmpGoChannel2 {
    public static void First(Supplier<String> supplier1,Supplier<String> supplier2) throws Exception{
        CompletableFuture<String> future1 =
                CompletableFuture.supplyAsync(supplier1);
        CompletableFuture<String> future2 =
                CompletableFuture.supplyAsync(supplier2);

        CompletableFuture<Object> future3 = CompletableFuture.anyOf(future1, future2);
        System.out.println(future3.get());
    }

    public static void main(String... args) throws Exception{
        FakeSearch web1 = new FakeSearch("Web1");
        FakeSearch web2 = new FakeSearch("Web2");
        FakeSearch image1 = new FakeSearch("Image1");
        FakeSearch image2 = new FakeSearch("Image2");
        FakeSearch video1 = new FakeSearch("Video1");
        FakeSearch video2 = new FakeSearch("Video2");


        CmpGoChannel2 c = new CmpGoChannel2();
        List<Future<String>> list = new ArrayList<>();

        First(web1,web2);
        First(image1,image2);
        First(video1,video2);

    }

}
while(true)と終了フラグで乗り切ってた汚い部分がだいぶきれいになった。

public static void First(Supplier<String> supplier1,Supplier<String> supplier2) throws Exception{
    CompletableFuture<String> future1 =
            CompletableFuture.supplyAsync(supplier1);
    CompletableFuture<String> future2 =
            CompletableFuture.supplyAsync(supplier2);
    CompletableFuture<Object> future3 = CompletableFuture.anyOf(future1, future2);
    System.out.println(future3.get());
}


行数もざっくり60行程度まで収まった。

2018年12月15日土曜日

Golangのfake google searchフレームワークをjavaで書いてみた。その1

Go concurrency patternsで触れられていたGoogle SearchのFake frameworkのコードが非常にすっきり記載されていて感動したので、これをJavaで書いたらどうなるんだろうと好奇心から書いてみた。

まず、Go言語の方のやつを、書き出してみる。

package main

import (
   "time"   "math/rand"   "fmt")

var (
   Web1 = fakeSearch("web1")
   Image1 = fakeSearch("image1")
   Video1 = fakeSearch("video1")

   Web2 = fakeSearch("web2")
   Image2 = fakeSearch("image2")
   Video2 = fakeSearch("video2")
)

type Result string

type Search func(query string) Result

func fakeSearch(kind string) Search {
   return func(query string) Result {
      time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
      return Result(fmt.Sprintf("%s result for %q\n", kind, query))
   }
}

func First(query string, replicas ...Search) Result {
   c := make(chan Result)
   searchReplica := func(i int) { c <- replicas[i](query) }
   for i := range replicas {
      go searchReplica(i)
   }
   return <-c
}

func Google(query string) (results []Result) {
   c := make(chan Result)
   go func() { c <- First(query, Web1, Web2) } ()
   go func() { c <- First(query, Image1, Image2) } ()
   go func() { c <- First(query, Video1, Video2) } ()
   timeout := time.After(80 * time.Millisecond)
   for i := 0; i < 3; i++ {
      select {
      case result := <-c:
         results = append(results, result)
      case <-timeout:
         fmt.Println("timed out")
         return      }
   }
   return}

func main() {
   rand.Seed(time.Now().UnixNano())
   start := time.Now()
   result := First("golang",
      fakeSearch("replica 1"),
      fakeSearch("replica 2"))
   elapsed := time.Since(start)
   fmt.Println(result)
   fmt.Println(elapsed)
}


コードの解説はスライドに譲るとして、First関数の中での、return <-c の使い方が素晴らしい。

で、これをJavaで書いてみた。

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

class Web1 implements Callable<String>{

    public String call() {
        try {
            Thread.sleep(10*1000);
        }catch (Exception e){

        }

        return "Web1";
    }
}


class Web2 implements Callable<String>{

    public String call() {

        return "Web2";
    }
}

class Image1 implements Callable<String>{

    public String call() {
        try {
            Thread.sleep(10*1000);
        }catch (Exception e){

        }

        return "Image1";
    }
}


class Image2 implements Callable<String>{

    public String call() {

        return "Image2";
    }
}

class Video1 implements Callable<String>{

    public String call() {
        try {
            Thread.sleep(10*1000);
        }catch (Exception e){

        }

        return "Video1";
    }
}


class Video2 implements Callable<String>{

    public String call() {

        return "Video2";
    }
}

public class CmpGoChannel {

    public static void First(ExecutorService executor1,Callable<String> callable1, Callable<String> callable2) throws Exception{
        List<Future<String>> list = new ArrayList<>();

        list.add(executor1.submit(callable1));
        list.add(executor1.submit(callable2));

        boolean loopDone = false;
        while(true) {
            for (Future<String> f : list) {
                System.out.print(".");
                if (f.isDone()) {
                    System.out.println(f.get());
                    loopDone = true;
                    break;
                }
            }
            if(loopDone){
                break;
            }
        }
    }

    public static void main(String... args) throws Exception{
        ExecutorService executor1 = Executors.newFixedThreadPool(2);
        ExecutorService executor2 = Executors.newFixedThreadPool(2);
        ExecutorService executor3 = Executors.newFixedThreadPool(2);

        CmpGoChannel c = new CmpGoChannel();
        List<Future<String>> list = new ArrayList<>();

        Callable<String> web1 = new Web1();
        Callable<String> web2 = new Web2();

        First(executor1,web1,web2);

        Callable<String> image1 = new Image1();
        Callable<String> image2 = new Image2();

        First(executor2,image1,image2);

        Callable<String> video1 = new Video1();
        Callable<String> video2 = new Video2();

        First(executor3,video1,video2);


        executor1.shutdown();
        executor2.shutdown();
        executor3.shutdown();
    }
}


まず気づいたのが、Javaにchannelに相当する仕組みがなかったこと。JavaのConcurrencyはそんなに人気のあるものではなかったが、そうは言ってもそれなりに使われている実績はあるので、書こうとしてみて「そういや、なかったな」みたいな気付きがあった。

なので、ここは

while(true) {
    for (Future<String> f : list) {
        System.out.print(".");
        if (f.isDone()) {
            System.out.println(f.get());
            loopDone = true;
            break;
        }
    }
    if(loopDone){
        break;
    }
}

といった感じで while(true)と終了フラグで乗り切るというちょっと汚いコードで対応した。
このあたりですでに、簡素なコードを書けるというGoの魅了が十分に表れている。



2018年11月29日木曜日

GraphQLを触ってみた

The better Restとの触れ込みのあるGraphQLを触ってみた。

GraphQLとは何か?

ここ数年、Webではスタンダードとして使われていたRest APIに対する不満から生まれたバックエンドとフロントエンド間の通信規約である。具体的には主に下記のようなものを課題として捉えている。

課題1 endpointから返されるデータを全部使わない(Over-fetching)

たとえばユーザのプロフィール画面を作りたくて、/user/profiesのエンドポイントを叩いたとする。大体の場合は、これのレスポンスに含まれるすべてのデータは必要とせずに、一部のデータのみ使うであろう。使われないデータは無駄であり、結果として効率的でない通信のやり取りに繋がる。

課題2 endpointをいくつも叩かなければいけない(Under-fetching)

Over-fetchingと表裏一体ではあるのだが、一つの画面に必要となるデータをやり取りするにも、 user/<id>を叩き、次にuser/<id>/profiles、そして最後にuser/<id>/photosの3つのendpointを叩く必要になることがある。これは一つのendpointから返されるレスポインスでは足りないがために起き、そのため複数のendpointへの通信が過剰に走ることになる。パフォーマンスの観点からは基本的にフロントエンドとバックエンド間の通信は少なければ少ないほど好ましい。

課題3 endpoint作成のコストが高い

endpointを一個作るにはフロントエンド・バックエンド側双方の調整が必要となるため、作成のコストが高い。


実際に作ってみた

GraphQLを推進する会社にApollo社がある。Apollo社が提供するApollo Serverを使うと比較的かんたんにGraphQLを試すことができる。

Getting started

出だしに書いてあったとおり、本当に10分で雰囲気がつかめる。もしかしたら10分もいらないかも。

感想

npmで初期化するだけで、playgroundがついてくるのは便利。ただ、ドキュメントが不親切で断片的なコードしか書いてないため、ちょっとした改良をするにも試行錯誤が必要。急がばまわれ的に、まずはapollo serverを使わない素のgraphql.jsなどを触って基礎を先に身につけたほうが良さそう。