Life is Really Short, Have Your Life!!

ござ先輩の主に技術的なメモ

良かれと思ってはビジネスではないな。。。

自分の悪い癖をメモっておこう。。。

  • 良かれと思って、詰めきれていないものをクシュってまるめてしまい、巻き取ってしまう。
  • 相手の都合にただ合わせて線を引いているだけなので、自分を責任を全うできてねぇ。逆説的だけど。
  • あれも取れそうこれも取れそうで、目先のものを掴みにいきすぎてしまって、時間軸の組み立てが崩壊してしまい、いい加減な仕事に結果的になってしまう。

ことし1年、これをぶら下げておこう。忠告してくれた恩人に圧倒的感謝。

需要の心配ではなく、供給の心配をする時代に

考えてみたら当たり前のことなんだが・・・

これまでのデフレーション時代において、企業が最も警戒していたのは、需要の縮小だった。産業の担い手となる生産者が減少する一方で、需要や供給も縮小し、例えば花屋やスーパーの売り場も少なくなると予想されていた。しかし実際は、むしろ医療や介護だけでなく、電気や水道、ガス、道路等のインフラ、そして生鮮食料品花き卸売市場のエッセンシャルワーカーのサービス需要が旺盛でありながら、それを支える人手が足りなくなるという供給面での制約だった。 地域の要となる市場の生産性向上 - 株式会社大田花き

需要が無いのではなく、供給が追いつかないから需要が消えて生産が進まない、それが今。需要が消えることはない、供給が追いつかないから需要の花が開かず根から朽ちてしまう。

供給が追いつかないから、数少ない生産・資本を奪い合う状態になるので、価格が上がるわけか・・・

供給の受け皿が小さすぎてもだめなんよね、ある程度のキャパを抱えられる会社が増えないといけないけど、資本効率の観点からSaaSクラウドのようなサービス開発に走ってしまう。ウチのように数名しかいない会社ばかりが増えてもしょうがない(自分で言ってて虚しくもなるが、事実だからしょうがないw)

生成AIである業界向けのシステムのカスタマイズなどが可能になる枠組みを技術的に作れる気がするが、DB設計から始めないといけないので、これはこれでハードルが高い。今のiPhoneにあるように、チップやカメラのマイナーチェンジに近しいことを今後繰り広げて行くような気がする、生成AI。革新性は今の延長線上に存在しないから。

生成AIのイノベーションのジレンマは、来年辺りから始まる気がするな。

ま、それは、おいといても、こちらの記事には色々考えさせられることがあった。でも、業界の構造変えるなら、業界の外からズラしていかないと、変わらないよね。僕は園芸・花卉業界でIT目線で禄を食んでいるので、引き続き、いろんなことを考えていきたい。

A Tour of Go First Impression

バックエンドでGo Langを使う案件や会社のお付き合いが最近ぐっと増えたため、Go Langの基礎文法を学びます。A Tour of Goをざっと回したので、メモ。

変数の型推論と初期化

:=を使うことで、変数の型推論と代入が可能。

「短変数宣言(short variable declaration)」と言うらしい。また、この宣言はグローバルにはできず、関数内部が最大のスコープとなる。

 a,b,c := 10, "10", false;

簡単にdeferが使える

TypeScriptでは、async/awaitが必須のdeferがこれだけで実現できるのは驚き。意味合い的には、try-catchfinallyに近いなぁ。 deferは後入れ先出しで、最後にdeferしたものから順番に実行される。

package main

import "fmt"

func main() {
    fmt.Println("start")

    defer fmt.Println("end") // ← 最後に実行される

    fmt.Println("middle")
}

固定長の配列は、array。可変長はslice

a := [3]int{1, 2, 3}

s := make([]int, 3)

for文は、rangeを使う

// for..in的なループ
// 自動的に第1引数にindexが入る
for index, value := range items {
    fmt.Println(index, value)
}
// index使わない場合はこ
for _ , v := range nums {
    fmt.Println(i, v)
}
m = make(map[string]int)
// mapはこうなる
for key, value := range m {
    fmt.Println(key, value)
}
// Pythonと同じでStringも回せる
for i, r := range "GoLang" {
    fmt.Println(i, string(r))
}

Goの関数はクロージャ

func counter() func() int {
    x := 0
    return func() int {
        x++
        return x
    }
}

func main() {
    c := counter()

    fmt.Println(c()) // 1
    fmt.Println(c()) // 2
    fmt.Println(c()) // 3
}

cxの内容を常に記憶してるわけですな。

Struct

  • Goにはクラスがない。それは全然OK。クラスに紐づけた関数を作る場合は、レシーバーつき関数を作ることで代替するらしい。謎い。
  • 参照渡しをしないと、Structで定義した変数の中身が変わらない。値渡しをするケースがあまり想像できないな。
type User struct {
    Name string
}

func (u User) ChangeByValue() {
    u.Name = "Value"
}

func (u *User) ChangeByPointer() {
    u.Name = "Pointer"
}

func main() {
    user := User{Name: "Init"}

    user.ChangeByValue()
    fmt.Println(user.Name) // Init (変更されない)
    user.ChangeByPointer()
    fmt.Println(user.Name) // Pointer(変更される)
}

interface

  • implementsがない。シグネチャが同じなら同じTypeだとみなされるようだ。へー。
type Greeter interface {
    Greet() string
}

type User struct {
    Name string
}

// Structに紐づいた関数Greetが、interfaceのGreetと同じシグネチャ
// UseはGreeter interfaceを実装したものとみなされる
func (u User) Greet() string {
    return "Hello, " + u.Name
}

func PrintGreeting(g Greeter) {
    fmt.Println(g.Greet())
}

func main() {
    u := User{Name: "Taro"}
    PrintGreeting(u) // User は勝手に Greeter とみなされる
}

アサーション

  • 変数がどの型かを示す構文がちゃんとある。
  • Switch文でパターンマッチ的なこともやれるが、TSほど厳密じゃない。
var x any = "hello"

// okで型がマッチしたかどうかが代入される
// 例外が存在しないGoらしい考え方だ。
s, ok := x.(string)
fmt.Println(s, ok) // "hello" true
// x が取りうる型の「Union」を型制約として定義
type Printable interface {
    ~int | ~string | ~[]int
}

// x は Printable だけに限定
func printType[T Printable](x T) {
    switch v := any(x).(type) {
    case int:
        fmt.Println("int:", v)
    case string:
        fmt.Println("string:", v)
    case []int:
        fmt.Println("slice:", v)
    default:
        fmt.Println("impossible (for now)")
    }
}

GoRoutine

  • これが一番Go言語の強みに見える。
  • チャネルという機構を使って、Pub/Subする。
  • チャネルはスレッドセーフで、同期される。受信しないとルーチンの実行で止まる。
  • selectを使うことで、チャネルのパターンマッチができる。
ch := make(chan int)

// {}()で無名関数を作成し、funcに渡している
// goroutine を作るには「関数を渡す必要」がある
go func() {
    ch <- 10  // 10 を送信
}()

v := <-ch    // 10 を受信
fmt.Println(v)
func fetch(ctx context.Context, ch chan string) {
    select {
    case ch <- "done":
    case <-ctx.Done():
        fmt.Println("canceled:", ctx.Err())
    }
}

Error

  • 例外機構がないから、throwもない。
  • 例外を投げることを禁じることで、何かしらエラーを表現する型を返す文化。ええやん。
  • interfaceだからError()をメソッドで実装して任意の型を表現するのが良さそう。
type error interface {
    Error() string
}

type ValidationError struct {
    Field   string
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("validation failed: %s - %s", e.Field, e.Message)
}

まとめ

  • Goの思想、すこ。例外なんていらん。
  • 関数型にかぶれている僕は全部immutableにしたいときがありますが、Goは並行処理も強いし、レシーバーの値渡しがそれに近いので、基本、ミュータブルでよさげ。
  • Goroutineが最も特徴的な言語仕様だ。なるほどなぁ。並行処理がマストなバックエンドでよー使われるのがわかる。
  • あとは実際にWebアプリケーション作ってみて、API/DBなどの非同期I/Oをどうさばいていくのか、それぐらいかな。

素晴らしいまとめ

このエントリのお陰で更に解像度あがった。

zenn.dev

とうとうNext.jsに手を染めることになりました

ReactRouterを敬愛する私ですが、案件の都合上Next.jsに手を染めることに。。。案件の数は全然違いますしね、こんなVercel専用フレームワークの何が!とか思いつつも、ちゃんとプロダクションでリリースしてからだな!

採用したほうが会社の基盤が安定する

盲点だったな。。。固定費は少ないほうがいいと思ってたが、業務委託ビジネスだと、ひとがいないと新しい大手の付き合いができない。 年間3千万 x 3社(エンプラ) を6〜7名、受託を年間1千万叩けば、1億が見える。それを叩いたほうが絶対に良いわ。そのコネもあるし。というわけで、リファラル前提で採用を加速する!!

売上が足りないのにコストダウンしたら栄養失調で死ぬだけ

表題は、99%の社長が勘違いしてること、という本の一節。本当にその通りだと思う。前職、そして、自分で会社をやって、腹落ちできた。

売上が足りないからコストダウンでしのいだとしても、ご飯の量が足りないから栄養失調になるだけだ。自分で立ち上がれないなら死んだのと同じで、死んでない分、タチが悪い。何かを削れば利益が出るって考えたら先細りするだけだよ。ジリ貧になっちゃう。ジリ貧ってのは入口を間違えているんだから、そこから改めないと。

栄養は、簡単に言えば現金(現金化できる資産)のこと。本にもあったけど、預金が1010万だが1000万借金と、預金10万で無借金なら、どう考えても1010万が良い。そもそも、60回分割で返せるんだから。7年が多いらしいけど。

コロナ融資で600万引いた。その600があるおかげで自分が何を売るべきか(当時はFlutterを先行着手してアプリ開発の案件を取るという決断をした)を考えて、その準備に時間を裂けた。その結果、Flutterで3年飯が食えて、次に自分が作るべきソフトウェアとそれを可能にする技術を磨く時間を稼げた。時間を稼げれば先に繋げられるんだなと、良い学びになった。現金がないと時間も稼げない。

売上が低調だからコストダウンしよう(失うものが怖い)のは、人間の本能に近い部分なので、どうしても先にそれが出る。コレ、間違いだ。賭け金は多い方が良いに決まってる。

自転車操業になったらどうしよう?回すだけです、どんな形であれ。あんまり意味のない問いです。資金を引いても同じことをやってて何も新しい成長にベットするものがないなら、引いても苦しい。でも、時間が稼げます。1ヶ月後に何かを見つけられるかもしれない。資金繰りから解放されて、時間の使い方を変えることで。

お金は栄養なんだから、採らないとね。取り続けないといけないのがミソだけど、僕も公庫や信金さんと、来月から相談会だ〜