夢のかけら

Goエンジニアの技術ブログ

Goに入門したので備忘録を書く

パッケージ

  • 同じパッケージに属するなら、そのパッケージ内で変数や関数を参照できる。
  • つまりパッケージとは1つのファイルを複数に分割する仕組み。

文字列

  • Goの文字列はかなり特殊なので挙動に注意する。
  • イミュータブル。
  • 値型なのに関数の引数に渡してもコピーがされない。
  • だからポインタがいらない。

マップ

  • マップは存在しないキーを指定すると初期値が返ってきてしまう。
  • これを防ぐために引数を2つ受け取り、エラーハンドリングを行う。
m := map[int]string{ 1: "A", 2: "B"}
if _, ok := m[1]; ok {
  // mにはキー1が存在する
}

チャネル

  • チャネルとはゴルーチン間でデータを共有する仕組み
  • チャネルから受信する=他のゴルーチンからデータが来るのを待つ
  • 双方向のチャネルは受信専用・送信専用、どちらの型にも代入できる

構造体

  • Goの構造体は省略記法として、ポインタと実態を気にすることなくメソッドを呼び出せる。値も代入できる。
  • 構造体に定義するメソッドのレシーバは原則ポインタ型にする。そうしないと破壊的変更ができない。
  • 構造体のフィールド(キー・インスタンス変数みたいなやつ)は初期値を持っている。
  • フィールド名 型名が同じときはJSのオブジェクトと同じ省略記法が使える。
  • 省略記法を使うと、hoge.huga.namehoge.nameのように階層を飛ばしてアクセスできる。

値型と参照型

  • Goの型は値型と参照型に分類される。値型は関数の引数として渡すとき、コピーとして渡されてしまう。値型を参照渡しとして破壊的変更を関数内で行うためには、ポインタを使う。
  • 参照型はスライス、マップ、チャネルの3つのみ。自分で定義する独自型も含めて、他は全て値型となる。
  • スライス、マップ、構造体では構造体の型名を省略できる。
m := map[int][]string {
    1:  {"hoge"}, // []string{"hoge"}と同じ
    2: {"huga", "piyo"}
}

独自型

  • type (定義する型) (既存の型)のような文法。
  • 独自型を作ったり既存の型にエイリアスを与えることができる。

インターフェース

  • インターフェースとは「異なる型に共通の性質を付与する」ための機能。ダッグタイピングと似ている。
  • あるインターフェースにあるメソッドを全て実装すると、自動的にそのインターフェースに属することができる。
  • インターフェースによって、第二・第三の型を与えることができる。

【Golang】構造体はなぜポインタ型に値を代入できるのか

f:id:lampler:20210928210714j:plain

構造体がわからない

↓のような超絶簡単なコードだが、どうもしっくりこなかった。

type Person struct {
    Name  string
    Age   int
}

func main() {
    lamp := new(Person)
    fmt.Println(lamp)  // => &{ 0} (ポインタ型)

    lamp.Name = "lamp" // どうしてポインタに代入できるの!?
    fmt.Println(lamp)  // => &{lamp 0}
}

lamp.Name = "lamp" ここがよくわからない。ポインタとは変数の型と変数が格納されているメモリのアドレスのこと。 このコードは変数の実態に直接代入しているように見える。

これなら理解できる

lamp := Person{}
lamp.Name = "lamp"
fmt.Println(lamp) // => {lamp 0}

結論:おそらくGoの省略記法

これは省略記法ではないかと思う。(ソースを見つけられていないので真実は不明)

lamp := new(Person)
fmt.Println(lamp)  // => &{ 0} (ポインタ型)
fmt.Println(*lamp) // => { 0}
(*lamp).Name = "lamp"
fmt.Println(lamp) // => &{lamp 0}

省略せずに書くと (*lamp).Name = "lamp"だが、 lamp.Name = "lamp"でもOKになってるのではないだろうか。

配列へのポインタ

配列でも同じことが起こる。 ↓のコードではpがポインタ型であることをコンパイラが検知して、自動的に (*p)[0]に変換してくれる。

p := &[3]string{"a", "b", "c"}
fmt.Println(p[0])    // => a (省略記法)
fmt.Println((*p)[0]) // => a (こちらが本来の書き方)

エンジニアに転職して5ヶ月が経ちました

f:id:lampler:20210829210543p:plain

はじめに

フィヨルドブートキャンプを卒業してエンジニアになって5ヶ月が経ちました。 仕事についていけるの?仕事は楽しい?エンジニアになってよかったこと・悪かったことなどを書いていこうと思います。

仕事はついていけるのか?

ついていける。が、とても難しい😅 でも基本的に1人でタスクを完遂できる。たくさん質問して大量に先輩の時間を奪う、マイナスの戦力では決してない。 自分に関しては、難しいタスクを渡されても(泣きながら)こなしてしまうので、「お、こいつ1年目やけどめっちゃ使えるやん!」ってことになって、さらに難しいタスクが降ってくる。 この好循環で自分がいくら成長しても、全く仕事が楽にならない。という状況が今の近況である。常に「カラダもってくれよ!! 3倍界王拳だっ!!!!!」という感じ。なので、体が潰れないように毎日9時に寝て、5時に起きて、ランニングして、朝風呂に入って、というようにかなり健康に気を使っている。健康は最大の資産。健康があれば何でもできるけど、健康を失ったら何もできない。健康を損なわないギリギリのラインで、仕事に全集中している。

エンジニアになってよかったこと

スーツを着る必要が無くなったこと

自分はスーツが大嫌い。小・中・高とずっと制服で、小学校の時から常に着心地の悪い服装にストレスを感じていた。私服ならばもっと高いパフォーマンスを出せるのに...とずっと思っていた。 年収500万の私服勤務と年収1500万のスーツ勤務なら迷わず前者を選ぶくらいだ。それくらい人生の大半をスーツで過ごすのは自分にとっては辛いことだった。スーツを全て捨てただけでQOLが爆上がりした。

働く時間が自由になったこと

今の職場はコアタイムがない。出勤・退勤の時間を打刻することもない。完全な成果主義である。私はだらだら仕事をするより、短期集中したい人なので本当に働きやすい。 子どもが2人もいるので子どもの世話もしやすい。本当に助かっている。

働く場所が自由になったこと

エンジニアの仕事は在宅勤務と非常に相性がいい。出社しないとできない仕事はないと思う。今は3LDKで家賃が65000円くらいの田舎に住んでいる。昔は会社の場所に合わせて、住みたくもない場所に住む必要があった。 これからは生涯好きな国・地域に住んでいい。これも幸福度が爆上がりした。

給料が上がったこと

エンジニアになる前にやっていた仕事は完全な年功序列だった。そして昇級ペースが亀よりも遅かった。新卒で入社して12年働いてやっと年収400万になるくらいに低かった。とても家族を養っていくのは無理だった。私の前の手取り給料は15万だった。 貧乏すぎて常に嫁と喧嘩していた。子どもが生まれても金がなさすぎて離婚しそうになるくらい揉めていた。今はエンジニア1年生で年収400万は超えた。これで嫁と揉めることはなくなった。心に余裕ができて毎日がとても楽しい。年齢ではなく技術力一本で評価してくれるので嬉しい。完全成果主義は高いパフォーマンスを出せる私と非常に相性がいい。

自分の市場価値が毎日上がること

未経験で転職活動をしていたときは市場価値は0に近かった。私の相手をしてくれる企業はほとんどなかった。でも実務経験が2ヶ月を過ぎた頃からwantedly, green, folkwellでスカウトが来るようになった。4月に入社したばかりだが、6月に日本橋のスタートアップからオファーを頂いた。8月入社で1ヶ月働いた。緊急対応を裁きながらメインの難しいタスクを頑張ってやってる。すごく大変だけど、とても毎日が楽しい。

エンジニアになって悪かったこと

人と話す機会がほぼ無くなったことw

今働いているFin Techのスタートアップも、前働いていた受託開発も90%以上は1人でプログラミングをしている。今の職場はデイリースクラムがないので誰とも話さない日が多い。 悪かったこと、と書いているがこれは人によってはいいことになり得る。私も家に嫁と子ども2人がずっといて騒がしいので、寂しいということはない。

仕事が難しい

エンジニアの仕事は難しい。100%頭脳労働なので考えることが苦手な人にはきついと思う。エンジニアになる前の仕事では時間の切り売り感が強かったので8時間毎日座っていれば仕事は終わった。 だが今は違う。何時間かけてもコードが書けないと仕事をしていないことと同じである。質問してもすぐに返ってくるわけではないので高い自走力と根性が必要である。最近ちょっと疲れてきたので気晴らしにポエムを書いている。

悪かったことがほぼない

良かったことだけを書くと胡散臭いかな?と思い、上の二つは無理矢理作り出した。しかし自分にとってぶっちゃけ悪いことが一つもない。仕事が難しいのはちょっと大変だけど、難しいからこそ楽しい、みたいなことはある。 逆に簡単なバグ潰しとかやってても毎日がつまらない。「大きな仕事に取り組め、小さな仕事は己を小さくする」大きな仕事の方が圧倒的に楽しい。

結論:Web系エンジニア最高

  • 将来性
  • 働き方の柔軟性
  • 仕事の楽しさ
  • 毎日成長を実感できる喜び
  • 単価の高さ

などなど、エンジニアは本当にいい仕事だと思う。少なくとも自分は転職する前の幸福度を1だとすると今は300くらいある。だから1500hの勉強は非常にコスパのいい投資だった。 プログラミングが面白くなかったらできなかっただろうけど、幸い自分はプログラミングを楽しめるし技術も好きである。もちろん万人に向いている仕事ではないと思うが、向いている・向いていないを決めるのは自分である。他人から向いてないとか言われても気にする必要はない。世の中の大部分はノイズなのでいらないものをそぎ落とし、自分が信じる道を突き進むのみ!勇往邁進!

VSCodeでGoを書いてgit pushするとインデントがおかしくなる時の対処法

f:id:lampler:20210704100053p:plain 次のお仕事でGolangを使うのでGoを勉強中です。しかし困ったことがありました。

起こったこと

  1. VSCodeでGoを書く
  2. 保存してgit pushする
  3. Git Hub上でコードをみる
  4. 何じゃこのアホみたいなインデント!!

f:id:lampler:20210704094306p:plain

原因

VSCode拡張機能、Goが保存時にインデントをスペースからタブへ変更していた。

そのタブはVSCode上の見た目では分からない。(Tabは→、Spaceは・で見ることはできるけど)

Githubではタブは8スペースで表示される。

対策

その1 Goの拡張機能をOffにする

極めて微妙。せっかくの拡張機能がなくなってしまう。 ↓の記事にgo.formatOnSavefalseにすればいけるよ、って書いてあるけどsetting.jsonに書いても動かなかった。

Indentation is replaced with tabs from spaces on save regardless of editor settings when this extension is enabled. · Issue #1930 · microsoft/vscode-go

でも普通に保存時のコード整形は欲しい。

その2 諦める

Goではインデントにタブ(4スペース前提)を使うことが推奨されている。だから強引にスペースにするのがそもそも間違っていた。 素直にフォーマッターに従うべきだ。

その3 Git HubのTabスペースを変更する

クエリパラメーターで?ts=2とか?ts=4とすると見た目を変更できる。だが毎回こんなことできるわけがない。 Chrome拡張機能を見つけた。これを使うか〜 Githubのタブが8文字で見にくいのでextensionで解決 - Qiita

【React】Hooksを使って関数コンポーネントに状態を持たせる

f:id:lampler:20210613072539p:plain

昔の話

昔は関数コンポーネントとクラスコンポーネントは明確に違った。

関数コンポーネント

  • 状態を持たない
  • ライフサイクルメソッド(componentDidMountなど)使えない

クラスコンポーネント

  • 状態を持つ
  • ライフサイクルメソッドが使える

このような違いあった。しかしHooksが導入されてから、関数コンポーネントでもクラスコンポーネントと同じことができるようになった。

なぜHooksが導入されたのか

クラスコンポーネントは難しいから

ベテランエンジニアにとっては慣れているかもしれないが、クラス構文は駆け出しエンジニアには理解しづらい。またJavaScriptのクラスはRubyのようなオブジェクト指向言語のクラスとは違う。JavaScriptのクラスはコンストラクター関数の糖衣構文にすぎないのだ。

コードの記述量を減らすため

クラスコンポーネントには決まり文句のようなコードが多い。そして、その量が無駄に多いのである。しかしHooksを使うとコードの記述量を減らすことができる。

Hooksを使ってみる

import React, { useState, useEffect } from 'react'

function Counter(props) {
  // useStateの引数には初期値を渡す
  // 初期値(state)と値を更新する関数を変数に代入
  const [count, setCount] = useState(0)
  const [name, setName] = useState('')

  // componentDidMount
  // componentDidUpdateと同じ役割
  // つまり、コンポーネントがレンダリングされる度に呼ばれる
  useEffect(() => {
    document.title = `${name}が${count}回クリックしました!`
    // componentWillUnmountはここに書く
    return () => console.log('お掃除しました!')
  })

  return (
    <>
      <input type="text" onChange={e => setName(e.target.value)}/>
      <p>{name}{count}回クリックしました!</p>
      <button onClick={() => setCount(count + 1)}>増やす</button>
    </>
  )
}

export default Counter

useEffectは再利用ができる

useEffect()をラップした新しい関数を作成して別ファイルに切り出す。その関数をimportすれば異なるコンポーネント間での再利用が可能になる。これもHooksを使う大きなメリットになりそう。

【React】高階コンポーネントを使ってみる

f:id:lampler:20210605070153p:plain

高階コンポーネントって何?

高階コンポーネント高階関数と似ている。高階関数とは関数を戻り値とする関数のこと。

高階コンポーネントは引数でコンポーネントを受け取り、戻り値として新しいコンポーネントを返す関数のこと。

どんな時に使うの?

クラスの継承と似ていると思う。親クラスに状態(state)やメソッドを定義して、子クラスで使い回す。似たような処理を機能を持つコンポーネントを複数個作成する時に使える。

サンプルコード

ルートのコンポーネント:App.js

import Movie from './hoc/Movie'

function App() {
  return (
    <Movie id={1}/>
  )
}

export default App

高階コンポーネント:withTooltip.js(withから名前をつけるのが慣例) 引数で受け取るコンポーネントの親になる。

import React from 'react'

function withTooltip(Component) {
  return class withTooltip extends React.Component {
    state = { showTooltip: false}
    mouseOver = () => this.setState({ showTooltip: true })
    mouseOut = () => this.setState({ showTooltip: false })

    render() {
      return (
        <div>
          <p>マウスを乗せると答えが出るよ</p>
          <Component
            onMouseOver={this.mouseOver}
            onMouseOut={this.mouseOut}
            showTooltip={this.state.showTooltip}
            {...this.props} // 親からもらったデータを全て渡す
          />
        </div>
      )
    }
  }
}

export default withTooltip

最下層の子コンポーネント: Movie.js

import React, { Component } from 'react'
import withTooltip from './withTooltip'

class Movie extends Component {
  render() {
    return (
      <div>
        <span>id: {this.props.id}</span>
        <p
          onMouseOver={this.props.onMouseOver}
          onMouseOut={this.props.onMouseOut}
        >
          高級コンポーネントとは?
        </p>
        {this.props.showTooltip && <p>コンポーネントを返す関数だよ</p>}
      </div>
    )
  }
}
export default withTooltip(Movie)
// 戻り値はWithTooltipにラップされたMovieコンポーネント
// つまりMovieコンポーネントを子に持つWithTooltipコンポーネントである

親子関係はこの通り。Appで渡したidもしっかりとMovieへ渡すことができている。

f:id:lampler:20210605065947p:plain