lasciva blog

開発して得た知見やwebビジネスのストック

「Effective Java 第3版」を読んだ

Effective Java 第3版

Effective Java 第3版

  • 作者:Joshua Bloch
  • 発売日: 2018/10/30
  • メディア: 単行本(ソフトカバー)

目的、モチベーション

Javaの理解を深める。

全体の感想

冗長な表現が多く読みにくいが、知らなかったことも多かったので読んで良かった。Java特有でない項目も結構あるので、省略してもよい項目も結構あった。
Javaは歴史があるが故に言語自体に負債もあり、その負債を回避するための項目もあり、辛みを感じた。
業務で扱う場合は、必須レベルな本ではあると思うので、他の言語経験者は2冊目ぐらいに読むには良い本だと思った。

目次

概要

第1章 はじめに

第2章 オブジェクトの生成と消滅

項目1 コンストラクタの代わりにstaticファクトリーメソッドを検討する
項目2 多くのコンストラクタパラメータに直面した時にはビルダーを検討する

引数が多くなるとバグのもとになるし、コンストラクタの種類がどんどん増えていく。
また、JavaBeansパターンだと、不変性が担保できない。

public class Sample {
    // 不変性を担保できる
    private final int size;
    private final String color;
    private final String brand;
    private final String category;

    public class Builder {
        // require
        private final int size;
        private final String color;
        // optional
        private String brand = "";
        private String category = "";

        public Builder(int size, String color) {
            this.size = size;
            this.color = color;
        }

        public Builder brand(String brand) {
            this.brand = brand;
            return this;
        }

        public Builder category(String category) {
            this.category = category;
            return this;
        }

        public Sample build() {
            return new Sample(this);
        }
    }

    private Sample(Builder builder) {
        this.size = builder.size;
        this.color = builder.color;
        this.brand = builder.color;
        this.category = builder.category;
    }
}

// 可読性も高い
Sample sample = new Sample.Builder(0, "blue").
            brand("brand").category("category").build();
項目3 privateのコンストラクタがenum型でシングルトン特性を強制する

enumは特に簡潔に書ける。

public enum Singleton {
  INSTANCE;

  public void hoge() {}
}
項目6 不必要なオブジェクトの生成を避ける

できるだけ自動ボクシングされた型よりも、プリミティブ型を使うなど。

項目7 使われなくなったオブジェクト参照を取り除く

参照を配列内の要素を nullにしないとメモリが開放されない。
陥りがちなのは、以下の3パターンが多い。

  • 独自のメモリを管理しているとき
  • キャッシュ( WeakHashMapを使うと、自動で取り除いてくれる)
  • リスナー、コールバック(弱参照 java.lang.ref.WeakReferenceを使うべき)
項目8 ファイナライザとクリーナを避ける

ファイナライザは実行が保証されないので、避ける。
オブジェクトの生成から開放まで数十倍のオーダーでコストがかかる。

項目9 try-finallyよりもtry-with-resourcesを選ぶ

try-finallyでは、 finally内で例外が発生すると、 try内のエラーが捕捉できなくなる。
try-with-resourcesを使えば簡潔になる上に、スタックトレースに追加される。

第4章 クラスとインタフェース

項目15 クラスとメンバーへのアクセス可能性を最小限にする

カプセル化のメリットなどが書かれていた。

項目17 可変性を最小限にする

但し、オブジェクトの生成にコストがかかる場合は、可変を許可することを考える。

項目18 継承よりコンポジションを選ぶ

継承でoverride等をすると、スーパークラスの変更による挙動の保証が難しい。ラッパークラスを作り、メンバーとしてインスタンスを保持して必要な転送メソッドを実装した方が安全。

項目19 継承のために設計および文書かする、でなければ継承を禁止する

継承によって、オーバーライドするメソッドが、想定していない箇所に影響を及ぼす可能性があるので、危険。
やるなら、副作用がでないと確証できるところだけオーバーライドする(現実にはかなり難しい)こと。
protectedメソッドで公開するのは最小限に抑え、複数のサブクラスのテストを書くこと。

これらを遵守し始めると、継承のメリットがなくなるので、基本的にはやらない方がベター。

項目20 抽象クラスよりインタフェースを選ぶ

複数の異なる抽象クラスを継承しないといけない場合、階層関係が生じてしまう。

項目24 非staticのメンバークラスよりstaticのメンバークラスを選ぶ

4種類のネストしたクラスがある。

  • staticのメンバークラス: ネームスペースがあるだけで、親クラスへはアクセスできない。基本的にはこれを使うべき。
  • 非staticのメンバークラス: 親クラスのインスタンスへ関連付けられ、アクセスできる。したがって、参照も持つのでGCにも負荷がかかる。
  • 無名クラス: メソッド内に属しているべきで、1箇所からのみインスタンスを生成すべきで、型がすでに存在している場合に使うべき。
  • 内部クラス: メソッド内に属しているべきで、1箇所からのみインスタンスを生成すべきで、型がすでに存在していない場合に使うべき。

第5章 ジェネリック

項目31 API柔軟性向上のために境界ワイルドカードを使う

PECS(producer-extends, consumer-super)の規則に則る。

public void pushAll(Iterable<? extends E> src) {
  for (E e: src) {
    push(e)
  }
}
public void popAll(Collection<? super E> dst) {
  while (!isEmpty()) {
    dst.add(pop())
  }
}

型パラメータがメソッド宣言中に一度しか現れない場合、それをワイルドカードで置き換えた方が柔軟性のあるAPIとなる。
しかし、以下のようなswapメソッドは素直にはコンパイルできないので、コツが必要。

// コンパイルエラー: 
public static void swap(List<?> list, int i, int j) {
  list.set(i, list.set(j, list.get()))
}

public static void swap(List<?> list, int i, int j) {
  swapHelper(list, i, j)
}

private static <E> void swapHelper(List<E> list, int i, int j) {
  list.set(i, list.set(j, list.get()))
}

第6章 enumアノテーション

項目34 int定数の代わりにenumを使う

Stringから変換する実装

// Implementing a fromString method on an enum type
private static final Map<String, Operation> stringToEnum =
  Stream.of(values()).collect(
    toMap(Object::toString, e -> e));

// Returns Operation for string, if any
public static Optional<Operation> fromString(String symbol) {
  return Optional.ofNullable(stringToEnum.get(symbol));
}

メンバーに応じて関数などの振る舞いを変えたい場合、switchだとメンバーを追加した際に漏れる可能性があるのでよろしくない。
privateなenumを定義して、それをメンバーに持つように強制する。

// The strategy enum pattern
enum PayrollDay {
  MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY(PayType.WEEKEND), SUNDAY(PayType.WEEKEND);

  private final PayType payType;
  PayrollDay(PayType payType) { this.payType = payType; }
  PayrollDay() { this(PayType.WEEKDAY); } // Default

  int pay(int minutesWorked, int payRate) {
    return payType.pay(minutesWorked, payRate);
  }
  // The strategy enum type
  private enum PayType {
    WEEKDAY {
      int overtimePay(int minsWorked, int payRate) {
        return minsWorked <= MINS_PER_SHIFT ? 0 : (minsWorked - MINS_PER_SHIFT) * payRate / 2;
      }
    }, WEEKEND {
      int overtimePay(int minsWorked, int payRate) {
        return minsWorked * payRate / 2;
      }
    };
    abstract int overtimePay(int mins, int payRate);
    private static final int MINS_PER_SHIFT = 8 * 60;

    int pay(int minsWorked, int payRate) {
      int basePay = minsWorked * payRate;
      return basePay + overtimePay(minsWorked, payRate);
    }
  }
}
項目36 ビットフィールドの代わりにEnumSetを使う

EnumSetの存在自体知らなかった。

項目37 序数インデックスの代わりにEnumMapを使う

EnumMapの存在自体知らなかった。

第8章 メソッド

項目49 パラメータの正当性を検査する
  • @throws
    • Javadocに記載できる(ex. @throws FileNotFoundException 指定のファイルが見つかりません)
  • Objects.requireNonNull
    • 引数が nullのときに NullPointerExceptionを投げてくれる
  • assert
    • 起動時に java -eaなどオプションをつけてON/OFFを切り替えることができる
項目50 必要な場合、防御的にコピーする

private finalなどのメンバーでもimmutableでない可能性がある。
java.util.Dateはimmutableではないので、基本的には Instantを使うべき。

public class Hoge {
    private final Date date;

    /*
     下記で書き換えられる可能性があるのでインスタンスをコピーする
     Date date = new Date()
     Hoge hoge = new Hoge(date)
     date.setYear(2009)

     ※ cloneだとsubclassが返る可能性があるので避ける
     */
    public Hoge(Date date) {
        this.date = new Date(date.getTime());
    }

    // hoge.date().setYear(2009)などで書き換えられる可能性があるのでインスタンスを生成
    public Date date() {
        return new Date(date.getTime());
    }
}
項目52 オーバーロードを注意して使う

期待していない挙動を起こすもとになるので、基本的には同じ引数の数を持つメソッドは定義しないこと。

第9章 プログラミング一般

項目60 正確な答えが必要ならば、floatとdoubleを避ける
  • 9桁を超えない => int
  • 18桁を超えない => long
  • 18桁を超えうる => BigDecimal
    • 内部で floatdoubleの処理を行ってくれる
項目61 ボクシングされた基本データよりも基本データ型を選ぶ

基本データ型に対するボクシングされた基本データの特徴

項目63 文字列結合のパフォーマンスに用心する

文字列の結合は、 +よりもStringBuilderを使ったほうがパフォーマンスが良い。

第10章 例外

項目73 抽象概念に適した例外をスローする

低レベルの例外は、使う側の関心に応じて高レベルの例外に変換して返すべき。
使う側で、詳細なレベルの例外の取り扱いをすべきでない。

try {
  ... // Use lower-level abstraction to do our bidding
} catch (LowerLevelException e) {
  throw new HigherLevelException(e);
}
項目77 例外を無視しない

基本的には、例外をcatchで潰さず、適切に処理するかログを吐くかなど対応しないといけない。
それでも稀に意図的に無視するケースでは、 ignoredを使って明示する。

try {
  numColors = f.get(1L, TimeUnit.SECONDS);
} catch (TimeoutException | ExecutionException ignored) {
  // Use default: minimal coloring is desirable, not required
}

第11章 並行性

項目78 共有された可変データへのアクセスを同期する

別スレッドでの値の変更を正しく参照するには、同期が必要。synchronized経由で参照、書き込みを行えばよい。

volatile修飾子は相互排除は行わないが、フィールドを読み込むスレッドから最後に書き込まれた値が見えることを保証する。

// 不完全: ++は読み込みと書き込みの2つの操作からなるため、同時にアクセスされると同じ値が生成されうる
// volatileの代わりにsynchronizedを使うべき
private static volatile int nextSerialNumber = 0;

public static int generateSerialNumber() {
  return nextSerialNumber++;
}

// better
private static final AtomicLong nextSerialNum = new AtomicLong();

public static long generateSerialNumber() {
  return nextSerialNumber.getAndIncrement();
}

第12章 シリアライズ

項目85 Javaシリアライズよりも代替手段を選ぶ

攻撃的な操作を含むオブジェクトやコストのかかるオブジェクトをデシリアライズさせる脆弱性のもとなので極力使わず、JSONやprotobufの使用を検討すること。 どうしても使わないといけない場合は、 java.io.ObjectInputFilterを使って対象とするclassを絞ること。

項目86 Serializableを細心の注意を払って実装する

実装自体は容易だが、クラスの互換性を担保しないといけなくなったりするので、長期的にはコストがかかる。

項目88 防御的にreadObjectメソッドを書く

コンストラクタ内で値の検証を行っているクラスは、シリアライズする際にデフォルトでは検証されない。
readObjectメソッドで、final修飾子は取り除いた上で防御的にコピーして、そのあとに検証を行って保護すること。

項目89 インスタンス制御に対しては、readResolveよりenum型を選ぶ

シングルトンパターンでは、enumの方が簡単に安全性を担保できる。

項目90 シリアライズされたインスタンスの代わりに、シリアライズ・プロキシを検討する

直接シリアライズの実装を行わず、シリアライズ用のプロキシとなるクラスを作成して、そのクラス経由でシリアライズさせると、安全かつ簡単。

class Hoge {
  private final Date date;

  private void readObject(ObjectInputStream stream) throws InvalidObjectException {
    throw new InvalidObjectException("Proxy required");
  }

  private void writeReplace() {
    return new Proxy(this);
  }


  private static class Proxy implements Serializable {
    private final Date date;

    Proxy(Hoge hoge) {
       this.date = hoge.date;
    }

    private void writeReplace() {
      return new Hoge(date);
    }

    private static final long = 11111111111111111L
  }
}

次のアクション

JVMGC周りの理解を深めたい。

Effective Java 第3版

Effective Java 第3版

  • 作者:Joshua Bloch
  • 発売日: 2018/10/30
  • メディア: 単行本(ソフトカバー)

「IntelliJ IDEAハンズオン――基本操作からプロジェクト管理までマスター」を読んだ

目的、モチベーション

vimが一番好きだが、Javaの開発とイマイチ相性が良くない気がして、Intellijを使っていてあまり使いこなせてないので。

全体の感想

ものすごいカスタム方法が載っているのかなと思っていたが、あまり触れられていなかった。
IDE上でgitやDBの使い方を知りたい方は買ってもいいかもしれないが、ショートカットのコマンドはネットの記事で十分な気がした。

目次

概要

第3章 ファイルの編集

3.2 編集・補完
  • Postfix completion
    • arg1>arg2.ifと入力すると、ifの構文に変換される
  • Expand Selection
    • Option + ↑ で、ダブルクォートや括弧のなかを選択できる

第5章 プロジェクト内の移動(Navigation)

5.1 シンボル間のNavigation
  • シンボル定義箇所へジャンプ: Command + B
  • ジャンプ前のコードに戻る: Command + [
5.2 ファイルのNavigation
  • 直近のファイルを一覧: Command + E
5.3 ディレクトリのNavigation
  • ナビゲーションバーにフォーカス: Command + ↑

「アフターデジタル」を読んだ

目的、モチベーション

そんなに明確に目的がある理由ではなく、最新の中国の事例やサービスの考え方を知りたかったため。
また、周囲に読んでいる人がいて、オススメしていた。

全体の感想

中国の事例が多く紹介されていて、「アフターデジタル」の概念を少しずつ理解できた。
データやAIが前提となっていて、技術的には本当に差がこんなにもあるんだなと感じた。
決済サービスはデータ収集や支払いのインフラとなっていて、それをベースに開発されているサービスも多く、日本の決済サービスもまだまだ序盤でこれからの展開がどうなるか楽しみになった。

目次

メモ

印象に残っている箇所をまとめました。

第1章 知らずには生き残れない、デジタル化する世界の本質

1-5 デジタル中国の本質 データが市民の行動を変え、社会を変える

DiDiではジャイロセンサーGPSで運転手の運転マナーを評価している。

第2章 アフターデジタル時代のOMO型ビジネス~必要な視点転換~

2-1 ビフォアデジタルとアフターデジタル

オンラインを中心に展開する前提で、リアル店舗は信頼を獲得したりする手段にすぎない。

2-2 OMO:リアルとデジタルを分ける時代の終焉

OMOの発生条件

  • スマホとネットワークの普及
  • モバイル決済浸透率の上昇
  • 幅広い種類のセンサーが高品質で安価に手に入り、偏在する
  • 自動化されたロボット、人工知能の普及

リアルはユーザインターフェイスの一つにすぎないから、オンラインとオフラインを区別するのはナンセンス。

2-3 ECはやがてなくなっていく

フーマーはアリババのデータを元に出店を決めてる。結婚した若者の多い地域に出店するなど。データが豊富で正確に予想できるため、黒字になる前提で出店している。

2-4 転覆され続ける既存業態

飲食店は、デリバリーサービスがある前提で設計されたスタンド型の店舗が増えてきている。回転数や座席数に依存せず客の数を増やしたり、味に注力できたり、狭い土地に出店できるように前提が変わる。

第3章 アフターデジタル事例による思考訓練

3-1 GDPR vs 中国データ共産主義 〜データの取り扱いをめぐる議論〜

一部の学校ではカメラを設置してAIで表情から態度を評価する。常に見張られているようで気持ち悪くも感じるが、教師の主観や把握しきれていないところも平等に評価できる。また、表情から理解の度合いを把握して、授業のペースをコントロールできる。

3-2 「レアな接点」に価値がある時代

無人レジというと、無人になってコストが減るのが主な目的と思われがちだが、コスト削減は副次的なもので本当に取りたいのは、購入する際の行動のデータ。

「入門UNIXシェルプログラミング」を読んだ

目的、モチベーション

今まではググりながら雰囲気でシェルスクリプトを書いていて、最近業務で使うことが増えてきて、シェル使いになりたいと思ったから。

全体の感想

一通りの文法がまとまっていたので、この1冊を理解すれば、ソースコードもガンガン読んでいけるレベルにはなると思う。
リダイレクトとかは特に雰囲気で使っていたレベルだったので、ちゃんと理解できてよかった。 たまに見る、 /dev/nullの意味もわかったので、これからはガンガン使おうと思う。

目次

概要

第1章 書き方にかかわる基本的な説明

1.4 ファイル名称の補完
ワイルドカード 説明
* 文字列全部
? 1文字
[...] の中に含まれている文字のどれか一つ
[!...] の中に含まれてない文字
1.5 引用符の使い方

シングルクォートの中で変数を展開したい場合

'Part1'"$VAR"'Part2'
1.9 コマンドのグルーピング
  • ()によるグルーピング: サブシェルで実行する。現在の環境を変えずに実行したい場合などに便利。
  • {}によるグルーピング: 現在のシェルで実行する。コマンドの結果をひとまとめにしたい場合などに便利。
1.10 制御文

testコマンドは []と同じ。

第2章 シェル変数

変数を明示的に使うには、{}で囲む。

$ FOO=abc
$ echo ${FOO}abc
2.5 位置パラメータ, 2.6 特殊な変数
変数 説明
$# 引数の数
$* 引数全体。ダブルクォートで括ると、一つの文字列として扱われる。
$@ 引数全体。ダブルクォートで括ると、それぞれが文字列として扱われる。
$? コマンド実行時の終了ステータス
$$ プロセスID
$! &でバックグラウンド実行させたときのプロセスID
$- 実行中のシェルのフラグの一覧

第3章 シェル関数、組み込みコマンド

3.1 シェル関数

3.1.4 関数をカレントシェルで利用すること
通常、シェルスクリプトに含まれるコマンドはそのシェルスクリプト内で動作し、起動したシェル上で動くわけではない。
カレントシェルで実行させるには .という組み込み関数を使用する。

$ . script_file
3.2 組み込みコマンド

3.2.1 ヌルコマンド(:)
何もしないが、いつも成功を返すコマンド。

# 無限ループ
while :
do
  if .....
  then
    break
  fi
done

# 空ファイルの作成
$ : > file

3.2.7 evalコマンド
複数の変換処理を一度に実行。

$ VAR1=val
$ VAR2=$"$VAR1"
$ echo $VAR2
$val
$ eval echo $"$VAR2"
val

3.2.10 exportコマンド
引数に指定した変数を、他のコマンドやシェルからも利用できるようにする。

3.2.12 readコマンド
キーボードからの入力を変数にセットする。

#!/bin/sh
echo -n "enter yes or no -->"
read ANSWER

3.2.13 readonlyコマンド
変数を書き換え不可にする。

3.2.19 typeコマンド
コマンドの取り扱いを表示。

$ type echo cd
echo is a shell builtin
echo is /bin/echo
cd is an alias for nocorrect cd
cd is a shell builtin
cd is /usr/bin/cd

3.2.20 umaskコマンド
ファイル生成時にどういうモードで作るかを決めれる。
ファイルの場合は666からumaskで指定した数字を指定したものができる。
デフォルト値は022なので、644のファイルができる。

$ umask
022
$ touch hoge
$ ls -l hoge
-rw-r--r--  1 user1  staff  0  2 10 10:34 hoge
$ umask 002
$ touch foo
$ ls -l foo
-rw-rw-r--  1 user1  staff  0  2 10 10:34 foo

3.2.21 unsetコマンド
変数や関数を消去する

3.2.22 waitコマンド
引数に渡したプロセスIDのプロセスが終了するまで待つ。

第4章 リダイレクションによるファイル操作

4.1 ファイルディスクリプタ
  • 0: 標準入力
  • 1: 標準出力
  • 2: 標準エラー
4.2 リダイレクト

リダイレクトとは、通常はキーボードからの入力を端末に出力するが、その入力元や出力先を変えること。

# 標準出力と標準エラーの両方をリダイレクト
$ cat abc def > nnn 2>&1
記法 説明
>file 標準出力をfileというファイルに書く
>file 標準出力をfileというファイルに追加書きする
>&m 標準出力をm番のファイルディスクリプタに書く
>&- 標準出力をクローズする
<file 標準入力をfileというファイルから読み込む
<&m 標準入力をm番のファイルディスクリプタから読み込む
<&- 標準入力をクローズする
<<word 標準入力をヒアドキュメントから読み込む
4.6 execコマンドとリダイレクション

execコマンドは、現在のシェルのプロセスをそのまま置き換えて新しいコマンドを実行させる。

# 標準出力を非表示に
exec > /dev/null

# 標準出力と標準エラーを非表示に
exec > /dev/null 2>&1 

# fileから入力する
exec < file

# n番目のファイルディスクリプタを使ってファイルをオープン
exec n> file
4.7 ファイルからの読み込み
# fileから一行ずつ読み込んで処理
while read LINE
do
   .....
done < file
4.10 ヒアドキュメント
# $VARは展開される
command << END
hoge is $VAR
END

# $VARは展開されない
command << \END
hoge is $VAR
END

# $VARは展開されない
command << 'END'
hoge is $VAR
END

# -をつけると行頭のtabが無視される
command <<- END
<tab>hoge is $VAR
END

# パイプにわたす
command << END | command
hoge is $VAR
END

第5章 環境

5.3 ユーザ情報、マシン情報

5.3.1 ユーザ名の取得
USERやLOGNAMEという環境変数でも取得できるが、書き換えられるので信用はできない。

$ whoami
hoge_foo
$ logname
hoge_foo
$ sudo su -
# whoami
root # 切り替わる
# logname
hoge_foo # もとのまま

スーパーユーザのみで実行させたい場合は、ユーザidで判断する。

if id | grep "^uid=0(" > /dev/null 2>&1
then
  echo "Is superuser"
else
  echo "Is not superuser"
fi
5.4 シグナルの処理

プロセスはシグナルを受け取ると実行を中止する。ハンドリングするためには trapコマンドを使う。

trap command-list signal_number # シグナルを受け取って処理する
trap '' signal_number # シグナルを無視する
trap signal_number # シグナルをリセットする

# シングルクォートで渡して、後ほど展開させる
trap 'rm -f /tmp/*.$$; exit 1' 1 2 3 15
数字 種類 説明
1 ハングアップ(SIGHUP)
2 割り込み(SIGINT) キーボードからの割り込みで中断させるためのキー。Ctrl-C
3 クイット(SIGQUIT)
9 キル(SIGKILL) プロセスを強制終了させる。trap等でも捕まえることはできない。
15 終了(SIGTERM) アプリケーションを終了させるときに用いられる。

第6章 コマンド行の解析、処理

6.2 コマンド行の書き方

引数が -でスタートするとオプションとして認識されてしまうため、 --を前につける。

$ mkdir -- -p
6.3 シェルスクリプトでのオプション処理

getoptsコマンドを使う

FLAG=FALSE
VALUE=
OPT=
while getopts fv: OPT
do
  case $OPT in
    f) FLAG=TRUE ;;
    v) VALUE=$OPTARG ;;
    \?) echo "Usage: $0 [-f] [-v value]" 1>&2
         exit 1 
         ;;
  esac
done
shift `expr $OPTIND - 1`

第7章 フィルタの使用法

7.2 sedコマンド
# 以下は同じ
cat file | sed -e 's/abc/ABC/'
sed -e 's/abc/ABC/' < file

# 慣習として使われてるだけで `/`のデリミータは任意の文字列でも大丈夫。
sed -e 's%abc%ABC%' file
7.3 sed を使っての編集
# 先頭に文字列追加
sed -e "s/^/top/"

# 末尾に文字列追加
sed -e "s/\$/top/"

# Pattern1とPattern2に囲まれてる部分の削除
sed -e "s/Pattern1*.Pattern2//"

# 大文字小文字の変換
cat file | tr '[a-z]' '[A-Z]' > upperfile

# タブをスペースに置換
sed -e "s/<tab>/<space>/"

# ホワイトスペースをスペースに置換
sed -e "s/[<tab><space>][<tab><space>]*/<space>/g"

# 空白行の削除
sed -e '/^[<tab><space>]*$/d'

# 行の指定
sed -e '5,$s/<tab>/<space>/g'

# 行の削除
sed -e '5,$d'

# 1行目からn行目まで表示
sed -n '1,np'

# BeginからEndの行を削除
sed -e '/Begin/,/End/d'

# ファイルを後ろから表示
grep -n '.*' | sort -n -r | sed 's/^[0-9]*://'

第8章 シェルのいろいろな機能

8.6 ファイルとディレクト
# ファイル名やディレクトリ名の単体での取得
basename `pwd`
# ディレクトリ名の取得
dirname `pwd`

# dir以下のファイルとディレクトリをすべて表示
find dir -print

# カレントディレクトリ以下のディレクトリのみすべて表示
find . -type d -print

# カレントディレクトリ以下のファイルのみすべて表示
find . -type f -print

# カレントディレクトリ以下の.swiftファイルのみすべて表示
find . -type f -name '*.swift' -print 

第11章 デバッグの手順、手法

11.2 デバッグオプション
  • -vオプション: 何を実行しようとしているのかが表示される
  • -xオプション: 実行している途中経過が出色される
$ cat shscript
#!/bin/sh
ABC=0
for i in 1 2 3
do
  ABC=`expr $ABC + $i`
done
echo $ABC

$ sh -v shscript
#!/bin/sh
ABC=0
for i in 1 2 3
do
  ABC=`expr $ABC + $i`
done
expr $ABC + $i
expr $ABC + $i
expr $ABC + $i
echo $ABC
6

$ sh -x shscript
+ ABC=0
+ for i in 1 2 3
++ expr 0 + 1
+ ABC=1
+ for i in 1 2 3
++ expr 1 + 2
+ ABC=3
+ for i in 1 2 3
++ expr 3 + 3
+ ABC=6
+ echo 6
6

「berlin.tech.meetup #1 ベルリンでエンジニアとして働く」に参加してきた

connpass.com

目的、モチベーション

海外で働きたいと思っていて、Twitterで拝見していたベルリンで働いてる方のお話を聞きたかった。

ベルリンは、ビザ取得のハードルが比較的低そうで、技術レベルが高そうで待遇も良ければ働いてみたいなという温度感だった。

感想

ベルリンでエンジニアとして実際に働くために必要な情報が広範に網羅されていて参考になった。

ビザの取得のしやすさばかりに気を取られていたが、実際に住んでみる上での話はあまり調べられてなかったので、面白かった。 例えば、働く上でドイツ語はあまり必要ないとの話は聞いていたが、レイオフされたときに補償を受けるためなどで役所の手続きではドイツ語が必要になるなど、考えれば当たり前のことかもしれないが想像できていなかった。

また、エンジニアの人気都市の比較の紹介もあり、「海外で働ければどこでもいいや」ぐらいの温度感だったので、考えが甘かったなと思ったw

ベルリンに住んで週末はLCCでヨーロッパに出かけてる方がいると聞いて、以前は海外移住をハードルが高いものに思っていたが、1,2年だけ旅行気分で働くのもアリなのかなと思えた。
私は独身で身軽なので、英語と覚悟さえあれば、ベルリンで働けそうだと思った。

メモ

※ 悪意はないですが、ビザ情報等は必ずしも正確とは限らないので、一次情報を必ず参照してください。

「ベルリンでエンジニアとして働く」発表

クイズコーナー

ベルリンの最多外国人: トルコ人
移民政策の影響らしい。

ベルリンのテック企業のエンジニアチームの特徴
  • 外国人が多い
    • ドイツ人0の職場もある
  • なぜ英語が使われるのか?
    • スタートアップの急増加して、外国人雇用が増える
    • ビザが比較的簡単
    • 元々、多様性のある都市(ベルリン崩壊で、東側の経済が崩壊して、いろんな人が集まった)
エンジニアの人気都市の比較

シリコンバレー

  • スタートアップ、大企業が多い
  • 競争が激しい、ハードワークが求められる
  • 給料も家賃も高い
  • GAFAの1会社では、中国・インドの移民が半分ぐらい占める

ロンドン

  • スタートアップ、大企業結構多い
  • そこそこの給料、高い物価
  • Brexitによるビザへの影響

パリ

  • 政府がスタートアップ都市を推進
    • スタジオや、ビザとかのサポート
  • 結構ドメスティック
    • 英語OKの就労先が限定される
どうやって都市を選ぶ?

文化、環境に馴染めそうか

  • ワーク以外
    • 外国人、アーティストが多い
    • 多様性がある(LGBT、移民)
    • 政治意識の高さ(移民政策、気候変動)
    • 自然が多く、四季がある
    • ドイツの首都、歴史がある
    • 夜に遊べる、ナイトクラブ、地下鉄24h、ビールで賑やか
  • ワーク
    • 有給25日以上(アメリカは半分ぐらいのイメージ)
    • 病欠は別扱い(2,3日の場合は、医者の証明書が必要)
    • 残業が少ない(9時スタート、18時にサクッと帰るイメージ)
    • 個人のタスクが決まってる
    • 多様性、フラット(イベントでダイバーシティ枠など)
    • リモートワークも割と普及してる

就職先が多いか

  • AWS, Facebook, Microsoft, Zalando(社員1万人規模), Klarna(エンジニア300人ぐらい)などなど
  • 失業、転職の際のリスクヘッジ
  • 会社間の競争がまして、条件がよくなる(転居サポート)
  • コミュニティの充実

ビザが取りやすいか

  • ブルーカード(大卒以上、最低年収4.2万ユーロ)
    • 最初は3,4年が多い
    • 2,3年で無期限許可を取れる(ドイツ語が中級以上だと)
    • EU永住許可もとれるので、他の都市で働けるようになる
  • 就労ビザ
    • 2,3年
  • ワーキングホリデー
    • 1企業で働けるのは半年ぐらい
  • 求職ビザ
    • 現地で就活するための一時的なビザ
お金について

給与レベル

  • 平均: 60k€
  • ジュニアで35k〜50k
  • ミドル: 50k〜65k
  • シニア: 6.5k〜
  • 90k以上は結構頑張らないといけない

税金

未婚30歳で、ジュニア:36%, ミドル:40%, シニア: 42%

住宅費

人数 費用
一人暮らし、シェア 400-700€
一人暮らし、専用 500-1000€
ファミリー向け 800-2000€

生活費

  • 1ヶ月乗り放題定期(地下鉄、バス) 80€
  • ケバブ 4€, コーヒー2€
  • ビール 1€
  • ジム 20-100€
  • 一晩の遊び代 10-50€

モデルケース: 年収60k 独身エンジニアの場合

項目 費用
給料 額面5000€, 手取り3000€
家賃 900€
電気、通信費、テレビ代合計 100€
ジム 50€
交通費 80€
ランチの外食費 150€
食費 150€
その他交際費、旅行費など 500€
貯蓄 / 投資 1000€
仕事を見つける上で

必要なこと

業界、利用技術

  • 増加傾向はフィンテック、モビリティ
  • スタートアップ多め
  • backend: JS&Node.js, Java, Rust
  • front: React(Native), Vue

よく使われるサイト

情報収集

  • TechCrunchなどで調達調達
  • Glassdoorのレビュー
  • LinkedInですぐやめた人or内部の人を探して、コンタクトを取る

履歴書&カバーレター

  • 履歴書は簡潔に1-2P
  • カバーレターは各社カスタマイズするだけで目立てる
  • Novoresumeなど便利なツールを活用する

面接

  • 電話面接(自己紹介、ポジション 15-30分)
  • オンラインコーディングチャレンジ codewars 6-9級が目安?
  • 課題&オンサイト
  • 最終面接

日本からの就職活動

  • 半分ぐらいの日本人は日本で行ってから移住
  • スタートアップなので渡航費は基本期待できない
厳しい現実

ドイツ語

  • 意外と「ドイツ語オンリー」な状況(病院、役所)
  • 超ローカル情報はドイツ語のみなことが多い
  • 1,2年ならドイツ語をやらないと割り切るのもアリかも

住宅難

  • 高騰する家賃
  • 良い物件を見つけるまで時間がかかる
    • 最初はairbnbで短期で借りて、期待せずじっくり探すとかが良いのでは

6ヶ月の試用期間

スタートアップでは結構簡単に切られる

不安定なスタートアップ

  • あっさりと行われるリストラ
  • 1年働けば、半年の失業保険がでる

テクノロジーの活用に消極的

  • 遅い、つながらないネット(地下鉄、)
  • キャッシュ文化(カード使えない場所も多い)
  • 書面重視の文化(郵送で問い合わせしないといけないとか)
  • プライバシー重視(GAFAはあまり好まれておらず、Facebookでもなかなかつながらない)

寒くて暗い冬

  • 短い日照時間
  • 冬季うつ(ビタミンとったり、対処方法はある)
東京とベルリンの必須
  • 色々な国の文化に触れられる、多様性
  • 働く時間が減った: ワークライフバランス
    • 一方で、緩いと感じる人も
  • 気軽に旅行ができる
    • LCCで数千円で週末旅行できる
自己紹介

Q&A

  • Q. 大学が無償というのを聞いたのですが、ベルリンのIT企業で働きながらベルリンの大学(コンピューターサイエンスなど)に無償で通う人はどのくらいいますか?
    • A. 普通の学生は多いが、働きながら通う人は聞いたことない。
  • Q. 就労ビザの取得において、仕事内容と自分の持つ学位の関連性はどれくらい影響してきますか?修士or学士の違い、分野が異なる場合 の影響が知りたいです
    • A. ブルーカードは多少関係することもあるが、学士があれば文系でも就労ビザはとれる
  • Q. 例えばNZではエンジニアとしての実務経験があっても、コンピュータサイエンスまたはそれに近い学士が就職に必要だったりしますが、ドイツの場合は?
    • A. 2問目と同じ