CTO の id:motemen です。先日募集開始した、はてなリモートインターンシップ2021のカリキュラムをお知らせします。はてなインターンのカリキュラムでは、参加する学生のみなさんに「モダンなウェブアプリケーション開発の学習」と「実際のプロダクト環境におけるサービス開発体験」の2つを持ち帰ってもらえるよう、毎年工夫をこらしています。
講義
全3週間のうち、前半1週間は講義フェーズです。以下のように、豊富かつ濃密な講義を予定しています。
Web API
RDBMS
フロ…
CTO の id:motemen です。先日募集開始した、はてなリモートインターンシップ2021のカリキュラムをお知らせします。はてなインターンのカリキュラムでは、参加する学生のみなさんに「モダンなウェブアプリケーション開発の学習」と「実際のプロダクト環境におけるサービス開発体験」の2つを持ち帰ってもらえるよう、毎年工夫をこらしています。
講義
全3週間のうち、前半1週間は講義フェーズです。以下のように、豊富かつ濃密な講義を予定しています。
Web API
RDBMS
フロ…
はてなで働くエンジニアにアンケートシリーズ第16回は、はてなブックマークチームのWebアプリケーションエンジニアのid:yigarashiに話を聞きました。
社内のはてなidの分類では「jkondoスタイル」
突然新卒での応募をしたところ、通年採用のフローに
チームのデータ転送基盤の開発を主導+スクラムマスターとしてリーダーの立ち回り
適度にコンテキストスイッチをしながらいろいろな仕事をするのが好き
スクラム運営の強度が大きく向上+Embulkを用いたデー…
こんにちは.マンガチームの id:mangano-ito です.最近は GraphQL API の開発を担当しており,GraphQL に関することを勉強したり実践したりしています.今回は開発ツールについてのお話です.
graphql/graphiql: GraphiQL & the GraphQL LSP Reference Ecosystem for building browser & IDE tools.
GraphQL API の使いやすい GUI クライアントです.GUI クライアントなので GraphQL ではなく Graph i QL となっているのがポイントですね.
余談ですが「グラフィキューエル」と呼んでいたら「グラフィクル」だという声をいただき,「グラフィカル」にかけていると気づきました(ちなみにREADME
では読み方が/ˈɡrafək(ə)l/
と示されています).
ライブデモがあるので,どのようなものかはブラウザ上で確認できます.また Electron で実装されたアプリもあり,デスクトップ上でも使うことができます.
まず GitHub API の Explorer を見てみてください.これは GitHub の GraphQL API をブラウザ上でテストできるツールです.
GitHub にサインインしていれば,自分のアカウントを使って GraphQL API をテストすることができます.実際のデータで確認できて便利です.
お気づきかと思いますが,ここに埋め込まれているクライアントは GraphiQL です.つまり GraphiQL を自分のウェブページにマウントすることができるということが,この例からわかります.
こうなるとこの例と同じように,開発しているサービスに特化した GraphiQL を便利に使えるようにしてみたいですね.どのようにすれば使うことができるでしょうか……
より詳しい情報はREADME
をあたっていきましょう.GraphiQL をモジュールとして使うための方法が書かれています.
graphiql/graphiql – GraphiQL (README.md)
ここにお試しで掲載されているケースでは,ただ CDN で配布されたスクリプトを読み込み,ReactDOM.render
で GraphiQL のコンポーネントを任意の要素にマウントすればそれで完了です!
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Simple GraphiQL Example</title> <link href="https://unpkg.com/graphiql/graphiql.min.css" rel="stylesheet" /> </head> <body style="margin: 0;"> <script crossorigin src="https://unpkg.com/react/umd/react.production.min.js"></script> <script crossorigin src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"></script> <script crossorigin src="https://unpkg.com/graphiql/graphiql.min.js"></script> <div id="graphiql" style="height: 100vh;"></div> <script> const fetcher = GraphiQL.createFetcher({ url: '<GraphQL API エンドポイントの URL>' }); ReactDOM.render( React.createElement(GraphiQL, { fetcher: fetcher }), document.getElementById('graphiql'), ); </script> </body> </html>
▲ Usage: UMD Bundle over CDN より
React のコンポーネントをマウントする形になっているのはユニークですね.これだけで GraphiQL の機能がひと通りそろっていて,クエリもできるし,ドキュメンテーションもしっかりと表示できる状態になっています.
もちろんパッケージをnpm install
して使うこともできます,本格的に組み込んで使える場合はこちらが都合よさそうですね.
import React from 'react'; import ReactDOM from 'react-dom'; import GraphiQL from 'graphiql'; import { createGraphiQLFetcher } from '@graphiql/toolkit'; const fetcher = createGraphiQLFetcher({ url: '<GraphQL API エンドポイントの URL>', }); ReactDOM.render( <GraphiQL fetcher={fetcher} />, document.body, );
▲ Usage: NPM module より
fetcher
は,対象となる GraphQL API のエンドポイントを指定しリクエストするために必要なものです.
const fetcher = GraphiQL.createFetcher({ url: '<GraphQL API エンドポイントの URL>' });
以降のコードではこの基本形を基にして拡張してみます.
React のコンポーネントになっていることで,さらに面白い点としては,自分が作って任意のコンポーネントを GraphiQL 上に追加することができることです.
GraphiQL
コンポーネントの属性により注目してみましょう.
<GraphiQL fetcher={fetcher} toolbar={toolbar} />
toolbar
という属性があります.これはその名の通り,ツールバーの設定を記述するための属性です.ここにadditionalContent
という属性を持ったオブジェクトを与えることで,任意の React コンポーネントを追加することができます.
const toolbar = { additionalContent: ( <div> <GraphiQL.Button label="ボタンA" onClick={() => window.alert('こんにちは!')} /> <GraphiQL.Button label="ボタンB" onClick={() => window.alert('さようなら!')} /> </div> ), }; const Editor = () => ( <GraphiQL fetcher={fetcher} toolbar={toolbar} /> ); ReactDOM.render( <Editor />, document.getElementById('graphiql'), );
例えばこのようなコードを書いてみます.GraphiQL.Button
は GraphiQL のツールバーボタンのコンポーネントです.ツールバーに2つのボタンが追加されていることが確認できます.
コードから予想できるように,ボタンをクリックするとアラートが表示されます.
他に,ボタン以外のコンポーネントもあります.メニューは便利そうですね.
const toolbar = { additionalContent: ( <GraphiQL.Menu label="メニュー"> <GraphiQL.MenuItem label="おはよう" onSelect={() => alert('おはよう')} /> <GraphiQL.MenuItem label="おやすみ" onSelect={() => alert('おやすみ')} /> </GraphiQL.Menu> ), }; const Editor = () => ( <GraphiQL fetcher={fetcher} toolbar={toolbar} /> ); // ReactDOM.render 以下省略……
実はロゴ部分を変えることもできたりします.面白いですね.
const Editor = () => ( <GraphiQL fetcher={fetcher} toolbar={toolbar}> <GraphiQL.Logo>マイ GraphiQL</GraphiQL.Logo> </GraphiQL> );
これで任意の機能をツールバーに登録することができることがわかりました.
ところで,冒頭にご紹介した GitHub の例ではログイン状態を反映することができていました.
仮にログイン状態のためのAuthorization
ヘッダーが API に必要だとしましょう.私たちが作る GraphiQL にその情報を追加するにはどうすればよいでしょうか?
GraphiQL
コンポーネントの他の属性を見てみましょう.headers
という属性があります.ここにヘッダーの内容を示す JSON 文字列を与えることで,任意の値を追加することができます.
const headers = { 'Authorization': 'Bearer MY_TOKEN', }; const Editor = () => ( <GraphiQL fetcher={fetcher} headerEditorEnabled="true" headers={JSON.stringify(headers, null, 2)} /> );
開発者ツールでリクエストを確認すると,ヘッダーに指定したAuthorization
の値が設定されていることがわかります.
またheaderEditorEnabled
で,リクエストヘッダーがエディター上に表示され,編集もできるようになります.
さらに,この値に state 変数を使うとリアクティブ変化するので……
const MyTokenButton = ({ setToken }) => ( <GraphiQL.Button label='トークンをセット' onClick={() => setToken('NEW_TOKEN')} /> ); const Editor = () => { const [token, setToken] = React.useState(''); const headers = { 'Authorization': (!!token ?`Bearer ${token}`: undefined), }; const toolbar = { additionalContent: <MyTokenButton setToken={setToken} />, }; return ( <GraphiQL fetcher={fetcher} toolbar={toolbar} headerEditorEnabled="true" headers={JSON.stringify(headers, null, 2)} /> ); };
ボタンを押すとヘッダーにトークンが設定されるようになりました.
クエリも同様にquery
属性を設定でき,onEditQuery
で編集されたイベントを受け取ることもできます.
const FavoriteQueryButton = ({ setQuery }) => ( <GraphiQL.Menu label="お気に入りクエリ"> <GraphiQL.MenuItem label="その1" onSelect={() => setQuery("{ favorite1 }")} /> <GraphiQL.MenuItem label="その2" onSelect={() => setQuery("{ favorite2 }")} /> </GraphiQL.Menu> ); const Editor = () => { const [query, setQuery] = React.useState(''); const toolbar = { additionalContent: <FavoriteQueryButton setQuery={setQuery} />, }; return ( <GraphiQL fetcher={fetcher} toolbar={toolbar} query={query} /> ); };
このようにして任意のヘッダーやクエリを設定することができました.よく使うアクションやサービス特有のテンプレートをツールバーボタンから設定できると便利になりそうですね.
最後に,自分が担当しているサービスでの実例を紹介します.
GraphiQL に,開発用に以下の3つの機能を追加してみました.
この中で3番目の「書いたクエリを共有」というのは,上図のように特定の URL でクエリが記入された GraphiQL を開くことができるものです.確認用のクエリを Pull Request で共有できて便利だったりします.
実装はごく単純で,URL の GET パラメーターにクエリを持たせてやりとりしているだけで,簡単に実現できます.
/** * ?query=... に今のクエリを設定する * @param {string} query 更新されたクエリ */ const onQueryUpdated = (query) => { const url = new URL(document.location); url.searchParams.set('query', query); window.history.replaceState(null, null, url); }; /** * ?query=... のクエリを取得する * @returns {string|null} クエリ */ const getCurrentQuery = () => ( new URL(document.location).searchParams.get('query') ); // あとはこれを使うだけ const Editor = () => { const [query, setQuery] = React.useState(getCurrentQuery()); return ( <GraphiQL fetcher={fetcher} query={query} onEditQuery={onQueryUpdated} /> ); };
まだできていないこととして,あらかじめよく使うクエリを何らかの手段で参照できるようにして,スニペットとしてサッと使えるようにしてみたいと思っています.
GitHub API の Explorer では,次のようにExplorer
ボタンからクエリをお手軽に構築できる機能があり,こういう形でスニペットを挿入するイメージです.
GraphiQL 自体が React を使って柔軟に自作コンポーネントを追加できるので,生の要素や状態を管理することなく拡張できて便利です.思いがけず簡単に導入することができたのは面白い体験でした.
*1:隠したり文言を少し変えたりしています
id:mangano-ito
マンガーノ・伊藤、伊藤聡介。アプリケーションエンジニア。マンガチーム所属。2019年12月入社時より現職。
Twitter: @mangano_ito
GitHub: mangano-ito
blog: マンガ〜ノ伊藤ノ〜ト
Mackerelチームでアプリケーションエンジニアをやっているid:lufiabbです。
Mackerelでは、ホストのメトリックを送信するためのエージェントや各種プラグインなどをOSSとして公開しています。現在の公式サポートはヘルプにある対応環境の通りですが、サポート外ではあるもののFreeBSDや32bit Windowsなどにもプログラムを提供している場合があります。
こういったOSSの一部、特にGo言語で書かれたプログラムのCIをGitHub Actionsへ移行した際に、32bitバイナリの生成についていくつか調べたことがありますが、あまりインターネットで見かけない情報だったので、今回は一般的な情報として共有してみようと思います。
この記事では、ディスクの残り容量を調べるプログラムの64bit版と32bit版をLinux用とWindows用にビルドする方法を例に、以下の場合にそれぞれ何が必要になるのかを見ていきます。
具体的な方が伝わりやすいと思うのでGoのコードも書いていますが、この記事の主題はビルド方法なので、サンプルコードの内容は雰囲気で読んでいただいても大丈夫です。なお、説明で使ったコードは以下のリポジトリで公開しています。段落ごとにコミットしているので、興味があれば眺めてみてください。
ビルド制約(Build constraint)は、ファイル名に_linux_amd64と入れたり、ファイルの先頭に// +build linux,amd64
と書いて、ビルド対象となるファイルを切り替えるものです。
// main.go func main() { root := Fsroot() fmt.Println(root) }
上記のようにファイルシステムのルートディレクトリを取得する場合、UnixやPlan 9では次のように単純に/を返せばいいでしょう。
// +build linux // fs_linux.go package main func Fsroot() string { return "/" }
Windowsの場合は、ドライブレターを含むのでビルド制約で切り替えます。ドライブレターは変えられるので本当は環境変数SYSTEMDRIVEなどを使った方がいいのですが、以下はサンプルなのでCドライブで固定です。
// +build windows // fs_windows.go package main func Fsroot() string { return `C:\` }
この場合、GitHub Actionsのワークフローは素朴にmatrixを使うだけで済みます。
jobs: test: strategy: matrix: GOOS: ['linux', 'windows'] GOARCH: ['amd64', '386'] include: - GOOS: windows X: .exe runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - uses: actions/cache@v1 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - uses: actions/setup-go@v2 with: go-version: 1.16.x - run: | mkdir -p dist go build -o dist/hdb-$GOOS-$GOARCH$X env: GOOS: ${{ matrix.GOOS }} X: ${{ matrix.X }} GOARCH: ${{ matrix.GOARCH }} shell: bash - uses: actions/upload-artifact@v2 with: name: dist path: dist/hdb-*
このワークフローが正常に終われば、Actionsにアップロードされたzipファイルに4つの実行ファイルが入っていることが確認できます。
なお、Go 1.4以前は$GOROOT/src/make.{bash,bat,rc}でクロスコンパイルのターゲットを用意しておく必要がありましたが、現在は不要です。
次に、システムコールやWin32 APIを使う場合です。
例として、ファイルパスを与えると、そのファイルが含まれるディスクの空き容量を返す関数を作ります。使う側はこんな雰囲気です。
// main.go func main() { log.SetFlags(0) size, err := DiskAvail(Fsroot()) if err != nil { log.Fatalln(err) } fmt.Println("avail size(GB)", size/1024/1024/1024) }
ディスク容量を調べるため、Linuxの場合はStatfsシステムコールを使います。同じものはsyscallパッケージにもありますが、これはGoのサポートに必要なものしか含まないので、一般的な用途ならgolang.org/x/sysを使いましょう。
// fs_linux.go import "golang.org/x/sys/unix" func DiskAvail(path string) (uint64, error) { var s unix.Statfs_t if err := unix.Statfs(path, &s); err != nil { return 0, err } return s.Bavail * uint64(s.Bsize), nil }
Windowsの場合は、Win32 APIを使います。以下の例では、uintptrにキャストするためunsafeを使っていますが、この用途であれば安全です。
// fs_windows.go import ( "unsafe" "golang.org/x/sys/windows" ) var ( modkernel32 = windows.MustLoadDLL("kernel32.dll") GetDiskFreeSpaceEx = modkernel32.MustFindProc("GetDiskFreeSpaceExW") ) func DiskAvail(path string) (uint64, error) { var size int64 upath := windows.StringToUTF16Ptr(path) if r, _, err := GetDiskFreeSpaceEx.Call(uintptr(unsafe.Pointer(upath)), 0, 0, uintptr(unsafe.Pointer(&size))); r == 0 { return 0, err } return uint64(size), nil }
この場合も、前述したビルド制約の場合と同じワークフローで全てのバイナリをビルドできます。
Windows版のコードではDLLをロードしているのでcgoが必要かと思いましたが、どうやらそうでもないようです。
cgoを使うと、GoからCのライブラリをリンクできます。上記の例ではunix.Statfsシステムコールを使いましたが、Cライブラリのstatvfsを使いたい場合があるかもしれません1。もっと実用的なものでは、グラフィックスライブラリを使う場合でしょうか。
cgoでは、import "C"
した上で、次のようにコメントの中にCのコードを書きます。
/* #include <stdlib.h> */ import "C"
これは#include
するだけのCコードですが、これをfs_linux.goとfs_windows.goに入れてビルドしてみましょう。
この場合、前述したワークフローのままでは、Linuxの64bit版を除いて以下のエラーで失敗します。
./main.go:11:15: undefined: DiskAvail ./main.go:11:25: undefined: Fsroot
この動作は、import "C"
を含む場合の暗黙的なビルド制約と、クロスコンパイル時の環境変数$CGO_ENABLEDによるものです。まず、import "C"
を含むファイルにはcgoビルド制約がセットされるため、CGO_ENABLEDが1の場合にのみビルド対象として含まれます。
ところが、$CGO_ENABLEDはビルドするホスト($GOHOSTOS、$GOHOSTARCH)とターゲット($GOOS、$GOARCH)が同じならば1がデフォルトですが、クロスコンパイルする場合にはデフォルトが0になります。
つまり、cgoの記述を含むファイルは、クロスコンパイルする場合にデフォルトでビルド対象から外されます。
上記のワークフローはubuntu-20.04でビルドしているので、32bit版のLinuxバイナリをビルドする場合にfs_linux.goはビルド対象に含まれません。同じように、Windowsでは32bitと64bitのどちらも、fs_windows.goが含まれなくなります。このため、一緒に定義している関数も定義されなくなって、上記のエラーになります。
次のように、ワークフローでCGO_ENABLEDを1にセットしましょう。
- run: | mkdir -p dist go build -o dist/hdb-$GOOS-$GOARCH$X env: GOOS: ${{ matrix.os.GOOS }} X: ${{ matrix.os.X }} GOARCH: ${{ matrix.GOARCH }} CGO_ENABLED: 1 shell: bash
次は、Windows版をビルドする場合に下記のエラーが発生すると思います。
gcc: error: unrecognized command line option ‘-mthreads’; did you mean ‘-pthread’?
Windowsでcgoを使う場合、Cコンパイラに-mthreadsオプションを渡すようになっていますが、このオプションはMinGWのgccで用意されているもので、Linuxにはありません。
-mthreadsは、gccのmanページによると次の記述があり、他にもWindowsのマルチスレッドライブラリを参照するように切り替えたりなどするようです。
Support thread-safe exception handling on MinGW. Programs that rely on thread-safe exception handling must compile and link all code with the -mthreads option.
Linuxにgcc-mingw-w64などをインストールしてMinGWのバイナリを作ることもできますが、GitHub ActionsにはWindowsホストも用意されていますし、Windowsホストの場合はWiXでインストーラを作ったりなどもできます。
このためMackerelのOSSではワークフローのジョブを分けて、Windowsホストを使うようにしました。こちらはLinuxの場合のジョブです(主な変更だけ)。
jobs: build-linux: runs-on: ubuntu-20.04 steps: - run: | mkdir -p dist go build -o dist/hdb-linux-$GOARCH env: GOARCH: ${{ matrix.GOARCH }} CGO_ENABLED: 1 shell: bash
こちらがWindowsの場合です(主な変更だけ)。
jobs: build-windows: runs-on: windows-2019 steps: - run: | mkdir -p dist go build -o dist/hdb-windows-$GOARCH.exe env: GOARCH: ${{ matrix.GOARCH }} CGO_ENABLED: 1 shell: bash
これで、LinuxとWindowsのどちらでも、64bit版はビルドが通るようになります。しかし、32bitの場合は両OSともまだエラーになります。
Linuxの32bit版バイナリを生成するときのエラーは、以下のような内容です。
In file included from _cgo_export.c:3: /usr/include/stdlib.h:25:10: fatal error: bits/libc-header-start.h: No such file or directory 25 | #include <bits/libc-header-start.h> | ^~~~~~~~~~~~~~~~~~~~~~~~~~ compilation terminated.
このエラーでは、文字通りファイルがないと言っています。Linuxにはmultilibといって、異なるアーキテクチャのバイナリをビルドまたは実行する仕組みがあります。Ubuntuの場合、bits/libc-header-start.hはgcc-multilibに含まれているので、これをインストールすれば解決します。
- run: | sudo apt-get install gcc-multilib g++-multilib
以上で、cgoを使う場合でもLinux版は32bitと64bitに対応できるようになります。
Windowsの32bit版バイナリを生成するときのエラーは、以下のような内容です。
C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: skipping incompatible C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/libmingwthrd.a when searching for -lmingwthrd ...このようなエラーがいっぱい... collect2.exe: error: ld returned 1 exit status
../が含まれていて長いので、要約すると次のようになります。
/mingw64/x86_64-w64-mingw32/bin/ld.exe: skipping incompatible /mingw64/x86_64-w64-mingw32/lib/libmingwthrd.a when searching for -lmingwthrd
mingwthrdを検索してlibmingwthrd.aが見つかったけど、互換性がないのでスキップすると言っていますね。これは32bit版のバイナリをビルドするときのCコンパイラを、32bitターゲット用のi686-w64-mingw32-gccに変更するとよいです。ちなみに64bitターゲットのgccは、x86_64-w64-mingw32-gccです。
cgoは、特定環境用の環境変数$CC_FOR${GOOS}${GOARCH}があればCソースコードをコンパイルするときに使いますし、$CC_FOR_TARGETがあれば$CCに優先して使います2。この場合は次のように指定しましょう。
- run: | mkdir -p dist go build -o dist/hdb-windows-$GOARCH.exe env: GOARCH: ${{ matrix.GOARCH }} CGO_ENABLED: 1 CC_FOR_windows_386: i686-w64-mingw32-gcc shell: bash
基本的にはこれでよいはずですが、エラーメッセージはまだ変わりません。対応を次で見ていきます。
ところで、x86_64-w64-mingw32-gccというコマンド名には32や64という数字がいくつか入っていますが、これは何でしょうか。ターゲットアーキテクチャを表す文字は、先頭のx86_64またはi686の部分だけで、他はターゲットに関係ないようです。もともとmingw32という名前で、64bit Windowsに対応したフォークがmingw-w64なのでその辺りが由来かなと思いますが、他にもパス部分にmingw32やmingw64表記などもあったりしていて分かりづらいですね。
Mingw-w64 – GCC for Windows 64 & 32 bits [mingw-w64]
どうやらGitHub ActionsのWindows環境には、i686-w64-mingw32-gccは入っていないようです。MinGWに含まれるpacmanを使えばパッケージの追加はできるみたいですが、MSYS2公式のmsys2/setup-msys2アクションを使った方が簡単そうだったので、これを使うことにします。
setup-msys2で追加したMinGWはテンポラリディレクト置かれていて、gccにPATHは通っていないので、シェルの指定をshell: msys2 {0}
とする必要があります。
結果、ワークフローは以下のように変わります(変更のある部分だけを抜粋)。
strategy: matrix: GOARCH: ['amd64', '386'] include: - GOARCH: amd64 MSYSTEM: MINGW64 - GOARCH: '386' MSYSTEM: MINGW32 - uses: msys2/setup-msys2@v2 with: msystem: ${{ matrix.MSYSTEM }} path-type: inherit install: mingw-w64-i686-gcc - run: | mkdir -p dist go build -o dist/hdb-windows-$GOARCH.exe env: GOARCH: ${{ matrix.GOARCH }} CGO_ENABLED: 1 CC_FOR_windows_386: i686-w64-mingw32-gcc shell: msys2 {0}
注意するべき点としては、msys2シェルを実行すると、デフォルトではWindowsでセットしているPATHを含みません。
Goの環境はactions/setup-goで入れていて、これはMSYS2のデフォルトではPATHに含まれないので、path-type: inherit
としてWindows側のPATHもmsys2シェルへ引き継ぐようにしています。また、mingw-w64-i686-gccは/mingw32以下にインストールされるので、MSYSTEM: MINGW32
で/mingw32/binをPATHへ追加しています。
これで、cgoを使う場合でもクロスコンパイルできるようになりました。とはいえcgoを使うと、それだけで環境を用意するのも大変だし、ビルドも遅くなるので、どうしても必要な場合を除いてcgoは使わない方が良いと思います。
id:lufiabb
門多恭平。2018年12月の入社時より、Mackerelチームのアプリケーションエンジニア。OSのPlan 9を愛用し、Go言語では並列性を利用した大規模プロダクトを手掛けた経歴もある。
Twitter: @plan9user
GitHub: lufia
blog: Plan 9とGo言語のブログ
はてなで働くエンジニアにアンケートシリーズ第15回は、マンガサービスのiOS/Androidアプリエンジニア、id:nabe1216に話を聞きました。
「関モバ」などのイベントではてなの話を聞いた
Androidアプリ開発をメインに、iOSアプリ開発にも関わる
頭を仕事モードに切り替えてからタスクに着手
GraphQL導入で「一歩外の世界へ」
人見知りでなかなか懇親会まで参加できない
ユーザーが直接触れるアプリのデザインや使い心地を大切にする
…
こんにちは。はてなチーフエンジニア 兼 Mackerel プロダクトマネージャーの id:wtatsuru です。4月27日(火)に Hatena Engineer Seminar #16 をオンラインで開催します!今回はMackerelのサービスを支えるアプリケーションエンジニアとCRE(Customer Reliability Engineer)2名によるトークをご用意いたしました。Mackerelの仕組みや開発の裏側から、ユーザーを支えるMackerelならではCREの取り組みなど、はてなのエ…
CTO の id:motemen です。このたび、はてなリモートインターンシップ2021の募集を開始しました。2021/8/16(月)~2021/9/3(金)に開催する長期インターンシップとなります。「はてなリモートインターンシップ2021」は、全日程をオンラインで開催する3週間、15日間のインターンシップです。 Webサービス開発の技術を学ぶ前半パートと、開発チームに配属されてサービス開発を実践する後半パートで構成されます。
前半日程は、Webサービスの開発・運用について、講義と課題による集中…
はてなで働くエンジニアにアンケートシリーズ第14回は、はてなブログのWebアプリケーションエンジニア、id:polamjagに話を聞きました。
はてなidの由来は秘密
2016年のインターンからアルバイトを経て入社
チーム全体でデータと触れ合っていけるようにしたい
テックリードには広い視野が必要、だけど……
チーム内で「データドリブンな意思決定」の方向にうまく動けた
「データドリブンな意思決定」の成果を出すにはまだ道半ば
「毛色が違うこと」…
シニアエンジニアの id:astj です。ISUCON は予選上位までいけるものの本選には届かないことが多いです。先日、昨春入社したアプリケーションエンジニアを対象としたエンジニア新人研修*1の一環で株式会社はてな 社内 ISUCON を id:dekokun id:hokkai7go と3人で企画・開催しました。このエントリではその様子について紹介しようと思います。※「ISUCON」は、LINE株式会社の商標または登録商標です。
ISUCON についての詳細は ISUCON公式ブログでご確認くだ…
こんにちは、CTO の id:motemen です。
はてなは今年も、学生を対象としたエンジニア向けの夏のインターンシップ、「はてなリモートインターンシップ2021」を開催します。
現時点での新型コロナウイルス感染拡大状況などを考慮し、リモートでの短期インターンの実施を企画しています! 今年のインターンでは、8月後半、3週間程度のプログラムとなる予定です。
リモート開催に最適化したカリキュラムを用意します。
前半はWebアプリケーション開発のオンライン講義を実施後、数日かけて課題に取り組んでもらい、はてなのエンジニアスタッフによるコードレビューや面談でフィードバックを行います。
後半はチーム開発体験です。「フレキシブルワークスタイル制度」という在宅勤務・出社を全スタッフが選択可能な制度を採用しています。これに基づいたリモートワークでのチーム開発に参加していただき、実際のプロダクションのコードを使った開発を体験していただこうと思っています。
開催時期、応募方法などの詳細については、4月中旬をめどにこのブログでお知らせします。インターンシップへの参加にご興味のある方は、以下のフォームからメールアドレスを登録いただくと、詳細情報を公開した際にメールでお知らせします。ぜひご登録下さい。
(追記)募集サイトを公開いたしましたのでフォームはクローズいたしました。上記リンクより募集サイトへ遷移ください。
インターンの情報は、Twitter アカウント @hatenatech でも積極的に発信していきます。興味のある方は是非フォローしてください!
2008年より毎年開催され、今年で14年目となるインターンシッププログラムです。はてなスタッフが講師・メンターとなり、学生のみなさんにWebサービス開発者としての技術を身につけていただくための、オリジナルのプログラムを提供しつづけてきました。若き皆さんのための強烈な体験を提供し、業界に優秀なエンジニアを送り出す試みです。
過去のインターンの様子は、下記のレポート記事をご覧ください。