パルカワ2

最近はFlutterをやっています

Obsidianを使い始めた

課題感

ノートアプリは、Craftを使うようになっていたが、微妙に使いにくくて結局Notionで書いたりしていた。あまり自分の知見として貯まっている感じがせず、必要なときに必要な情報を取るみたいなのが出来ず、メモを書いたような気がするがどこへ………となったり、自分で記憶しておく必要があるということが時々あった。というか記憶していないものは大体なかったことになっている。

Obsidian

https://obsidian.md/

今年の10月に1.0.0がリリースされ「なんかよくなった」という雑な噂を聞いたので触ってみたところ、自分が触った時よりも自分が求めている動きをしていたのでいいじゃんと思って移行を検討し始めた。

Obsidianが僕の第二の脳になるらしい。脳は、情報の記録や取得はもちろん一つの情報から関連した情報を高速に取り出せるので、そういうことができるという話だろうと理解した。求めているものだ!

オレオレルール

Obsidianを第二の脳にするためには、関連のある情報同士が紐付いていないといけない。 またObsidianはコミュニティプラグインの開発が盛んでほしいと思ったものは大体ある。逆に言えばやろうと思えばなんでもやれてしまう気がするので、シンプルに使わないと途中で挫折すると思った。

それらを意識したオレオレルールを設ける必要がある。

とにかくリンクを貼る

関連のある情報同士を紐付けるために内部リンクを利用する。内部リンクを利用することで、情報同士が関連付けされ表示されるようになる。

また存在しているページだけではなく存在していないページにもどんどんリンクを貼る。

2ホップリンクを有効にする

2ホップリンクがあることで、より関連した情報を取得しやすくなる。

Obsidianでは、公式には対応していないがコミュニティプラグインがあるのでそれを利用する。リリースされているバージョンは表示バグがあるので、Githubにあるバージョンを使った。

具体的な物事のページ・抽象的な概念のページを作る

2ホップリンクを効果的に利用するために

タグは使わない

Obsidianには、タグがあるが使わない。内部リンクを利用する。理由は以下

  • 内部リンクならページなので物事に対する説明や考えてることが書けるし、エイリアスもつけれる
  • 使う概念を減らせて、ドキュメントを書く時にタグかページかで悩まなくてすむ
  • タグにはネスト出来たりタグペインなるものがあったりするが今のところ不要だと思う
  • タグと比べて入力文字数が多い、見た目は悪い、タイトル特有の禁止文字があるのが欠点

階層は基本使わない

Obsidianには、フォルダを分けることで階層を作れるが 画像を保存するassets, テンプレートを保存するtemplatesだけ用意する。理由は以下

  • 階層があることで、どこに保存するべきか悩む
  • 重要なのは情報を素早く取り出せることだが、階層があっても素早く取り出せないことがすでにわかっている
  • ドキュメントはすべて同じ階層に置くので、タイトルは被らせることは出来ないのが欠点

フロー情報かストック情報かを明確にする

Notionの検索で苦しむ理由の1つは、ストック情報がほしいのにフロー情報が出てくるからだと思っている。例えば「勤怠登録ってどうやるんだっけ〜」と勤怠登録の仕方(ストック情報)を探したいと思ったときに「勤怠登録」と検索すると同僚の勤怠登録タスクが出てきてやれやれだぜと思うみたいな。勤怠登録をタスクにしてる人はまあいないだろうけど、似たようなことが多々ある。

なので、ストック情報を探したい時は、明確にフロー情報を避けれるようにする。

ちなみにObisidianで扱うフロー情報とは、Daily noteだけだと思っている。会社のMTGの議事録などはみんなが見えるところで書きたいのでNotionで書く。

  • フロー情報の場合は、内部リンクで [[flow]]と記載する
  • ストック情報には何もつけない。両方に必ずつける運用はつけ忘れが発生するし、Daily noteはテンプレから自動生成が出来るので、自分でつける必要がない。なので、フロー情報にだけつけるのがよいと考えた
  • ストック情報を検索したい時は、-[[flow]] とすればいい

フロー情報とストック情報を1つのページに混ぜない

検索容易性をあげるために混ぜない。Daily-noteに書いても必要だと思ったらストック情報として切り出していく。

ページは細かく分ける

Notionの場合、ページ同士の関係を表示するのが苦手なので1ページにまとめた方がいいのではないかと思ってるけど、Obsidianの場合は細かく分けてリンクするのが関連した情報として出てきやすいので、いいのではないかと思った。

前のデータは引き継がない

邪魔になるだけだと思ったので引き継がないことにした。手元には置いといて必要になったら持ってくる形にする。

なんでもできるけど、なんでもやらない

Obsidianに限らずなんでもできると楽しくなってなんでもしたくなる。重要なのは必要な情報を得れることなので頑張りすぎない。

所感

  • 上記ルールに則って運用してみているが、結構いい感じな気がする。
  • Obsidian自体に最初から機能が揃っているという感じではなく、コミュニティプラグインを有効にしていくことでまともになっていくという印象だった。正直IDEなど最初から設定されているものに最近は慣れていたので設定がめんどくて投げ出しそうになった
  • 書きやすさに関してはNotionのほうが書きやすいと思っていて、Notionはリンクを貼る時とかそのあたりの気の利きようはすごいな〜と改めて思いました
  • 値段は、仕事に関することを書くと年50ドル払う必要があり、更にSyncを使うと年96ドルかかるので、合計146ドルかかり年2万円くらいかかるのでなかなか高い
    • Syncはコミュニティプラグインでどうにか出来る説はある
  • ちゃんと確認したわけではないけど、チームで使うのは書きやすさ・設定の大変さ・同時編集などがないあたりで厳しいのかなと思った
  • はてなブログに書く内容をどこで書くかは悩ましい。はてなブログに出すならはてなブログで書けば良い気がしてきた
  • Daily noteをどこで書くかは結構悩んでいて、Obsidianじゃなくてよくね?と思いつつ、振り返りやすいように設定してしまったのでまあいいかとなっている
  • いい感じに自動でリンクになってもいいのでは?と思ったけど、それってはてなキーワードじゃね?

まとめ

CraftからObisidianに移行した。とにかくリンクを貼るというのが大事な気がするので、無意識に出来るくらいになるとよさそう。そんなこと言って2ヶ月後には使ってない可能性もある。

話は変わるけど、仕様書同士や設計書同士の関係性をどう表すのか難しいと思っていたけど、バックリンクや2ホップリンクなど関係を一覧にするのはかなりいいなと思った。

Dartのextensionについてぼんやり思っていること

Dartには Extension methods | Dart というのがある。ぼんやり思っていることをメモしておく

前提

extensionは

  • クラスにメソッドを追加することができる
  • テストするためにクラスを作る必要がある
  • インスタンスフィールドは持てない
  • クラスの責務の大きさはextensionで切り出しても小さくならない

思っていること

変更できないクラスにどこでも使えるメソッドを生やすのはいいと思う

  • 変更できないクラスとは、StringやListなどDartが提供しているクラスやライブラリが提供しているクラス
  • どこでも使えるメソッドとは、Listをsliceするとか特定のドメインを扱う時のみ利用するメソッドではないもの

ほとんどがdartxdart:collectionにあると思われる。

逆に言えば、以下のようなパターンはextensionは使わずクラスを定義したほうがよいと思う

  • 自分が定義したクラス
  • 特定のドメインのみを扱う時に利用するメソッド

別クラスとして定義して、テストをする時に依存する情報を減らしたりクラス自体を小さくしたほうがいいと思う。

一応例外はあって、enumは自分が定義していて特定のドメインでのみ扱う場合でもextensionを使っている。そうしないとenumにメソッド生やせないので。

extensionを定義する場所をまとめる

様々な箇所でextensionを実装すると似たようなextensionが生えたり別でクラスを作ったりしてしまいそうなので、すべてまとめておいてまとめてexportする形にしておくのがよかったかもしれないと思っている。

変更できないクラスにどこでも使えるメソッドを生やすというルールだったらそれが出来る気がする。

リファクタリングをするために"一時的に"別ファイルに持って行くために利用する

リファクタリングを行う時に変更回数が多い+コードの行数が長いファイルをまず別ファイルに切り出してから少しずつリファクタリングすることがある。extensionを使えば簡単にクラスから別ファイルに切り出すことができる。ただ切り出し方にも工夫は必要で、例えばたくさんある切り出したいメソッドをまとめて別ファイルに切り出すというようなやり方をしてしまうと結局大きなファイルになってしまうのでクラスとして切り出すことを想定して切り出す必要はある。

また切り出して終わりにするとクラスは責務過多のままなので、ちゃんとリファクタリングしていく必要がある。

まとめ

僕はDartのextensionはあんま使う必要がないなと思っていますがみなさんはどうでしょうか

FlutterKaigi 2022で「Dartにおける静的解析」を話してきた

speakerdeck.com

初の動画撮影だったんですが、mmhmmで細切れで撮影したのでむしろ楽だったかも。最初は頑張って話そうとしてたんですが、録画していると思うと緊張して全くうまく話せなかったので、スクリプトを書いて読む形にしたりした。

内容的には、custom_lintcodemodを知らなかったとかコメントがあったりしたので話して良かった。

反省としては、時間的制約があって色々話せなかったこともありanalyzer pluginの説明をバッサリ端折ったので意味わかんない人は意味わかんなかったかも。端折るところ間違えたかもしれない。あとanalyzer pluginのメモリ消費多いよ問題の話も話してないので、興味ある人はイシューを読んでください。

運営のみなさん、ありがとうございました!

GoogleカレンダーからHourStackのEntryを作成した時にプロジェクトを自動で付ける

HourStackでタスクと時間の管理をしている。

HourStackは、Zapierと連携が出来て色々自動化出来るので、Googleカレンダーで作ったEntryはプロジェクトを自動で付けるようにした。

  • HourStackのEntry CreatedをTriggerに選ぶ
  • Source Prov が google-calendar のときのみ実行するようにフィルタ
  • Project が Does not exist のときのみ実行するようにフィルタ
  • GoogleカレンダーからFind Event
    • Search Termに作成したEntryの Name を指定
    • Start Time に Start Date と Start Timeをスペース区切りで指定
  • Run Python
    • Googleカレンダーの色分けからプロジェクトを決める
    • Inputには Color ID, Start Date, Start Timeを指定する
  • Update Entry in HourStack
    • 何も指定しないと指定していない状態で更新されるので、Entry Createdの情報を指定する
    • Start AtをRun PythonでOutputした start_at を指定する。Start Onを指定しない。
    • Project IDには、Run PythonでOutputした project を指定する

Run Pythonに書くコードは以下の通り。Project IDは自分で指定する。

from datetime import datetime
from dateutil import parser
import math

color_id = "0"
if "color_id" in input_data:
  color_id = input_data['color_id']

start_at = ''
if "start_time" in input_data:
  start_at = f"{input_data['start_date']} {input_data['start_time']}+00:00"
 
project = {
  "0": "<Project ID>",
  "1": "<Project ID>",
  "2": "<Project ID>",
  "3": "<Project ID>",
  "4": "<Project ID>",
  "5": "<Project ID>",
  "6": "<Project ID>",
  "7": "<Project ID>",
  "8": "<Project ID>",
  "9": "<Project ID>",
  "10": "<Project ID>",
  "11": "<Project ID>",
}[color_id]

output = {'project': project, 'start_at': start_at}

HourStackのProject IDは、Update EntryでProject IDを指定しようとすると出てくる。 GoogleカレンダーのColor IDは Google カレンダーの色 - SAKI Web Design を参考にした。

Googleカレンダーの色分けとHourStackのプロジェクトの色を同じにしている。こんな感じでカラフルになってかわいい

Mimestreamを使い始めた

Mimestream | A native macOS email client for Gmail

  • 会社MacChromeでは、会社のGoogleアカウントでログインして使っている
  • 会社のGoogleアカウントでChromeにログインしていると個人アカウントにログインできない
  • なにかに登録やログインする時に個人アカウントで基本登録しているので、メールを見るために個人アカウントのChromeプロファイルに切り替えている
  • めんどくさすぎるのでどうにかしたい
  • メールのクライアントを使うのがよさそう
  • Gmailのフィルタを結構がっつり使っているのでGmailに特化したものがほしい
  • MimeStreamというのがあるらしい

という感じで使い始めた。

FlutterでMacアプリをビルドしてFirestoreにつなげようとすると固まる

趣味でMacアプリでも作ってみるかと思ったら早速ハマってしまった………

Firebase準備

  • プロジェクトを作る
  • Firestoreのデータベースを作成する

コマンド

cd app
flutter create --org com.hisaichi5518 --platforms=ios,macos .
firebase login
dart pub global activate flutterfire_cli
flutter pub add firebase_core
flutter pub add cloud_firestore
flutterfire configure --platforms=ios,macos --ios-bundle-id=com.hisaichi5518.app --macos-bundle-id=com.hisaichi5518.app

macos/PodfileにてFirestoreが依存する最低バージョンに書き換える

platform :osx, '10.12'

アプリを立ち上げたらFirestoreのドキュメントが作られるコードを書いてみる

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';

import 'firebase_options.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  final db = FirebaseFirestore.instance;
  final user = <String, dynamic>{
    "first": "Ada",
    "last": "Lovelace",
    "born": 1815
  };
  final doc = await db.collection("users").add(user);
  print('DocumentSnapshot added with ID: ${doc.id}');
  runApp(const MyApp());
}

Macアプリの場合は、無が表示されてしまう。ログすら出ないので困った。

iOSアプリはうまくドキュメントが作成されて画面も表示される。

アプリが作成された時点ではBundleIdが、 ios, macosともに com.hisaichi5518.app になっているのでそれぞれ変更してみたけどダメだった

またFirebaseは無料版はアプリが3個しか登録できない。flutterfire configureがよしなに作成してくれるが3個以上作ってもエラーにならないので注意

追記: 解決方法

macos/Runner/DebugProfile.entitlements に以下の設定を追加してあげれば動いた。

<key>com.apple.security.network.client</key>
<true/>

SocketException: Connection failed (OS Error: Operation not permitted, errno = 1) with flutter app on macOS - Stack Overflow

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.3.2, on macOS 12.5.1 21G83 darwin-arm, locale ja-JP)
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 14.0)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2021.3)
[✓] Android Studio (version 2021.2)
[✓] IntelliJ IDEA Ultimate Edition (version 2022.2.2)
[✓] IntelliJ IDEA Ultimate Edition (version 2022.2.2)
[✓] IntelliJ IDEA Ultimate Edition (version 2022.2.1)
[✓] VS Code (version 1.71.2)
[✓] Connected device (3 available)
[✓] HTTP Host Availability

• No issues found!

サンプルアプリは動く

flutterfire/packages/cloud_firestore/cloud_firestore/example at master · firebase/flutterfire · GitHub

関連

Add Firebase to your Flutter app

まとめ

flutterfire configureが便利だった。 FlutterFireのmacOS対応はまだβ版らしいので本格的に使うのはまだ先かなぁ

VSCode環境改善活動

定期的にVSCodeやInteliJでGitの操作をしたい期がやってくる。4年前も挑戦して挫折している。

最近はInteliJを使ってなくてVSCodeだけになってる。Gitの操作をするときは、VSCodeからiTerm2に移動していてまあそれでも大きくは困ってないんだけど、VSCodeからiTerm2に移動するときはVSCodeで開いてるディレクトリでGitを操作すること以外していないのでVSCodeで完了させたい気がしてきた。

VSCodeGUIでGitを操作することもやってみたけど、自分には無理だったのでVSCodeのTerminalを使うことにする。

TerminalとEditorの移動をキーバインドでできるようにする

VSCodeのUserInterfaceドキュメントを見て何から何に移動したいのか確認する。以下を満たしたい。

  • 特定のEditor GroupsからPanel(Terminal)に移動する
  • Panel(Terminal)から特定のEditor Groupsに移動する

キーバインドの設定を検索する。

  • Terminal: Focus Terminalというのがあったのだけど、デフォルトではキーバインドが設定されていない(!)
  • パネルのターミナルにフォーカスを当てると ^` と表示されていてcontrol+@で移動できるのでこれで良い
  • Editor Groupsには、command+1-9で移動できる

ちなみにcommand+0でサイドバーに移動できる。エクスプローラーとか具体的なのは command+shift+eとか。

また他のパネルは、command+shift+mなどなのでcommand+shift+なんかに統一したい気持ちを抑えてcontrol+@を使う。

ただターミナルにフォーカスが当たっているときにcontrol+@したらEditor Group 1に戻れるように追加した。

[
    {
        "key": "ctrl+[BracketLeft]",
        "command": "workbench.action.focusFirstEditorGroup",
        "when": "terminalFocus"
    }
]

Terminalを開いたらtmuxを開くようにする

tmuxのキーバインドに手が慣れているのでそうした。すでにセッションがある場合は、attachするなどは不要だと思ったのでやっていない。複数のディレクトリをVSCodeで開くのでattachされるとむしろ困るかもしれない。

  • コマンドパレットを出して、Terminal: Select Default Profile を選択
  • tmuxを選択

Terminalを開いたらVSCodeで開いてるディレクトリを開く

VSCodeでTerminalを操作するときは、ほぼ確実にVSCodeで開いてるディレクトリに移動している。

設定に以下を追加

    "terminal.integrated.cwd": "./",

ちゃんとキーバインドを覚える

環境というか自分の問題である…………。

InteliJからVSCodeを使うようになってからキーバインドがわからないままになってたりしてたんだけどちゃんと確認した。

あと最近もともと使えてたキーバインドが使えなくなったりして困ってたんだけどちゃんと原因を調べたりした。Karabiner-Elementsの設定がオフになってた……。

TerminalからVSCodeを開くようにする

日々何個かのディレクトリを行き来している。たくさん開いてると重くなる気がするので不要になったらウインドウを閉じている。再度開く必要があるとき毎回マウスでポチポチしていたけど、fzfで移動出来たら便利じゃんと思ったので作った。 ちなみにすでに開いてるとそのウインドウに移動してくれる。

control+@ -> control+v -> 文字入力 -> 移動 という感じになって楽

fzf-open-vscode() {
  local repo=$(ghq list | fzf --preview "ghq list --full-path --exact {} | xargs exa --color=never --no-permissions --no-user --no-filesize --git-ignore --sort name --tree --level 2")
  if [ -n "$repo" ]; then
    repo=$(ghq list --full-path --exact $repo)
    BUFFER="cd ${repo} && code . && cd -"
    zle accept-line
  fi
  zle clear-screen
}
zle -N fzf-open-vscode
bindkey '^v' fzf-open-vscode

まとめ

手癖でiTermを開いてしまうことがあるけど減らしていける気がする