tech.guitarrapc.cóm

Technical updates

Azure Bicep の設計 Resource編

前回は、Bicep の性質から、どういう基本設計でIaC を指向するか書きました。

tech.guitarrapc.com

今回は、実際に Bicep Resource を使って書くときに、どういう工夫が必要なのかメモしておきます。

tl;dr;

  • Preview リソースは ARM Template を見つけるところから気を付けよう。
  • Bicepモジュール粒度はTerraform のモジュール粒度と同じコンセプトでよく機能する。
  • param で object を使うときにはデフォルト値とaray of objectが使いにくい。
  • Role のような GUID が name のリソースでは、逆引きできるように設計が必要。

Bicep Resource

IaC で一番重要なのが、Resource Reference はどこを探せばいいのかの確認だ。

Bicep Resource は ARM Temaplte と相互に変換ができる。 ということで、Mirosoft は ARM Template の Reference に Bicep の定義も配置している。

Azure Resource Manager template reference - ARM template reference | Microsoft Docs

型定義は、次の通り。改行に意味がある構文なので、慣れてない内は、ふとした変数定義でエラーになる。

Bicep functions - objects - Azure Resource Manager | Microsoft Docs

Preview リソースと ARM Template

Previewは、Azureと付き合っていくうえでめんどくさい側面の一つだ。

Azure は Preview じゃないと使いたい機能がない、というケースが多い。(それ自体はいいが、プレビューが長いのがAzureを使っていてつらいところ) ということで Previewも扱えないか考えていこう。

Azure の ARM Template ページには「Previewを除くAzure リソース」は記載されているが、Previewリソースはここにない。 Preview リソースは、それぞれのPreview リソースの説明ページに存在する。

例えば、PostgreSQL Flexible Server は Preview なので、こっちを見ることになる。

クイック スタート:Azure DB for PostgresSQL フレキシブル サーバーを作成する - ARM テンプレート | Microsoft Docs

Previewページは手薄

Preview は、AWS だろうとどこだろうとAPIからドキュメントに至るまで何かと手薄だが、Azure も例外ではない。

このPreview のページには Database などの追加 ARM Templateの記載はもちろん、言及すらない、探す難易度が高い。そして Configuration に至っては存在しない。 幸いにして、ドキュメントになくてもVS Codeのbicep補完でリソースが出る。インテリセンスに頼ってエスパーしよう。

こういうところが Preview を使う上で本当に苦しいだろう。そしてPreview は長い、先が見えない不安が付きまとう。

細かいように思えるが、このドキュメントの一貫性の欠如はAzureを学ぶ上で、探すコストが著しく高く厳しいものがある。 Preview も同じARM template reference に置いて、定義をみるべき場所を減らせばいいと思うがしない理由もあるのだろう。

Bicep Module 粒度

BicepのModule は、Terraform 同様にある程度の粒度で組むのがよさそう。 いわゆる 1 Resource で 1 Module というのはなるべく避けるべきだろう。(拡張性が事実上ない) ただ、隠蔽するという意味では十分拡張性があってメンテコストが低いならあり。(resource を露出させたくないのもわかる)

ダメな例

Subnet が array of object を受け付けるが、1subnet 固定 + vnet が同時に作成される前提になっている。 これでは利用者は 1 vnet に n subnet はできず、かならず vnet に 1 subnet が強制されるだろう。

@description('Specifies the Azure location where the key vault should be created.')
param location string =resourceGroup().location
@description('Tag information for vnet')
param tags object = {}
@description('Virtual network name')
param virtualNetworkName string
@description('Address prefix for virtual network')
param addressPrefix string = '10.0.0.0/8'
@description('Subnet name')
param subnetName string
@description('Subnet prefix for virtual network')
param subnetPrefix string = '10.1.0.0/16'

resource vn 'Microsoft.Network/virtualNetworks@2020-06-01' = {
  name: virtualNetworkName
  location: location
  tags: tags
  properties: {
    addressSpace: {
      addressPrefixes: [
        addressPrefix
      ]
    }
    subnets: [
      {
        name: subnetName
        properties: {
          addressPrefix: subnetPrefix
          privateEndpointNetworkPolicies: 'Disabled'
        }
      }
    ]
  }
}

output id string = vn.id
output name string = vn.name
output subnetIds array = [
  {
    id: vn.properties.subnets[0].id
    name: vn.properties.subnets[0].name
  }
]

複数の AKS を構成する必要がないなら、ACR や ACR Role Assignment など、関連するリソースをまとめてしまうほうがいいだろう。

// パラメーター

// リソース
resource vn 'Microsoft.Network/virtualNetworks@2020-06-01' = {
}

resource symbolicname 'Microsoft.ContainerRegistry/registries@2020-11-01-preview' = {
}

// 他隠蔽できるリソース... 

// アウトぷっと
output id string = vn.id

Terraform などを使っている人にとっては、Terraformモジュールと同じコンセプトで分離すればいい、といえば伝わるだろうか。

Bicep Parameter

Parameterで活躍するのが型システムだ。 型が強く機能すれば、どのパラメーターに何をいれればいいのか、インテリセンスがドキュメントとして機能する。 Bicep の型定義システム自体は決して強くない。だが、VS Code のLanguage Server が強力に機能しているので、インテリセンスだけを見ると Terraform よりも書きやすい。

Data types in Bicep - Azure Resource Manager | Microsoft Docs

string, int, bool の扱いやすさ

型を指定すれば、パラメーターを渡すとき、使うときに型チェックされて入力している値の型と合致しているか見てくれる。 terraform と同程度には扱えるし、便利。

param strParam string
param enable bool

また、attirbute で @allowed などをparamの上の行の書けば入力を enum 値で制限もできて便利だ。

@allowed([
  'apple'
  'orange'
])
param fruit string

パスワードのようなセキュアな値は、@secured() を付ければSecureString として扱われて Deploy History などに乗らないのでこれも便利。

@secure()
param password string

object型の型宣言が弱い

Bicep のobject型は、型宣言時にプロパティを宣言できないため使いにくいという印象がぬぐえない。

// 宣言時にデフォルト値をもってプロパティが決まる
param foo object = {
    str_prop = ''
    num_prop = 111
    bool_prop = true
    array_prop = []
}

なぜ、型宣言時にプロパティを宣言できないのが使いにくいのだろうか。

IaC で避けられるなら避けたほうがいいのは、デフォルト値の設定だ。 デフォルト値が、オフィシャルのARM Template の bicep Resource のような本体ならいいのだが、Module として提供する場合はデフォルト値を入れた/入れてないで事故が起こりやすい。

そのため、基本的にパラメーターで与えたいものはデフォルト値なしで、型宣言だけして与えるのがよいと、私が見てきた多くの現場ではプラクティスとして得ている。

例えばterraform では、変数の型宣言は次のようにデフォルト値なしで行える。

variable "foo" {
  type = set(object({
    str_prop    = string
    num_prop = number
    list_prop   = list(string)
    set_prop   = set(string)
    map_prop = map(string)
  }))

bicep も、object型宣言 時にプロパティと型を指定できれば事故を防げてうれしいのだが、できないので諦めよう。

array 型の型宣言が弱い

同じことは array 型にも言えるが、string や int などの単一の型なら推論が効くので何も問題がない。 だが、object の array となると完全に無力だ。parameter に渡すとき、parameterを使うときの両方でインテリセンスは沈黙する。

そもそもの型宣言が array でしかないので無力としか言えない、ここからプロパティを推論できるようになるといいのだが。

param foo array = [
  {
    str_prop = ''
    num_prop = 111
    bool_prop = true
    array_prop = []
  } 
]

terraform の list(map(string)) 型のインテリセンスの利かなさと同じといえばイメージしやすいだろうか。

実行時Parameter の渡し方

bicep は、実行時に2つの方法でパラメーターを渡せる。

  1. cli 引数
  2. jsonファイル参照

cli 引数は -p key=value で指定できるので使いやすくはじめのうちはこれが多い。

az deployment group create --resource-group dev-foo -f foo.bicep -p key=value -p key2=value2 --mode Complete

ただ、実際にCIで回し始めると dev や stg など、決まった環境に決まった実行を毎度行うことが多くなる。 ということで、いちいち引数設定せず json にしておいて実行引数はいつも同じになっていくだろう。

az deployment group create --resource-group dev-foo -f foo.bicep -p @param.json --mode Complete

json parameter がちょっと使いにくいのが、bicep で指定していない parameter が json に定義されていると引数が渡せずエラーが出ることだ。 設定ファイルを共通にして、いくつかの bicep ファイルに分ける (当然bicepごとにparamはそれぞれ違う)、という使い方には向いていないのでなんとももどかしいものがある。

az deployment group create --resource-group dev-foo -f foo.bicep -p @param.json --mode Complete
# foo とbar で同じ param じゃないとパラメーター渡しでエラー
az deployment group create --resource-group dev-bar -f foo.bicep -p @param.json --mode Complete

諦めて、それぞれの bicepごとにparam を用意することになったが微妙。

existing と リソースの存在保障

existing は、いわゆる terraform の data リソースのように、既存のリソースからリソース参照を拾ってくる使い方のために用意されている。

Referencing existing resources

たとえば、次のようなstorage account リソースを拾ってくる書き方ができる。

resource stg 'Microsoft.Storage/storageAccounts@2019-06-01' existing = {
  name: 'myacc'
}

では、subnet のように、他のリソース(subnetなら vnet ) の中にあるリソースはどうやってとってくるかというと、vnet を拾ってから subnet を拾うのがいいだろう。 例えば次のようにする。

resource vnet 'Microsoft.Network/virtualNetworks@2021-02-01' existing = {
  name: 'vnet-name'
}

resource subnet 'Microsoft.Network/virtualNetworks/subnets@2021-02-01' existing = {
  name: '${vnet.name}/my-subnet'
}

existing の実行成功は存在保障ではない

この existing 処理の問題点は、本当にそのリソースが取れたかの確証が取れないことだ。 通常 terraform や pulumi では、data resource で対象のリソースの取得に失敗した場合エラーで中断する。 だが、bicep では中断処理が行われない。

たとえば、先ほどの vnet を name ではなく id 参照にするとどうなるだろう。

resource vnet 'Microsoft.Network/virtualNetworks@2021-02-01' existing = {
  name: 'vnet-name'
}

resource subnet 'Microsoft.Network/virtualNetworks/subnets@2021-02-01' existing = {
  name: '${vnet.id}/my-subnet' // vnet.name から vnet.id
}

結果は、subnet が取れない、だ。それにも関わらずARM Template のデプロイ時にここはパスされて、後続の処理では「取れてないsubnet」を渡そうとする。結果、デプロイ自体はは、subnetを使うリソースで作成が失敗してエラーになる。

エラーメッセージもリソースが作れなかったことを示すのみで、それが subnet が取れなかったことには連想しにくい。 本来は、原因であるsubnet の取得で失敗してエラーになってほしいのは言うまでもない。

existing は、既存のリソースをとってくるが、とってきたことを保証しない。 これはIaC としては厄介な挙動で、what-if のような 実行前の確認で検知できないことを示している。 Terraform では data source を使うことで確証を取れるのだが、Bicep では実行前に az コマンドなどで取得してパラメーターに渡すぐらいしか確証とれなさそうだ。

なお、こういった subnet -> vnet という依存関係があるリソースは、id 上で {parent_id}/subnets/{subnet_name} のような resource id ルールが一般に存在するため、subnet を existing で拾う必要がない。 existing の現状の挙動では、無理して使う理由が乏しいので回避できるならするといいだろう。

Role Name の取得

Role には、Build-in Role と Custom Roleが存在する。 Azure のIAMはリソースごとに存在するので、RBAもリソースごとに他のリソースやRole と関連づけることになる。 つまり、role assignment は、リソースごとに行う。

参考: AWS の場合、IAM Role でリソースとアクションをポリシーとして集権して、IAM Role Arn をリソースに割り振る。

Role の特徴は、resourceIdの名前部分が GUID であることだ。 コマンドなら az role definition list --name 'ROLE_NAME' | jq -r .[].id のようにすることでRole名さえわかっていれば Role Idを取得できる。 だが bicepでリソースをとってくるときは、Microsoft.Authorization/roleDefinitions リソースで existing 経由で取得しようと思っても、subscriptionResourceId 関数で取得しようと思っても、GUIDがわからないと使えないことに気づくだろう。

// resourceSubscription関数で
subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ここに入れるGUIDをどう導き出すか')

// あるいは existing 使うなら
resource aksAcrPermissions 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = {
  name: 'ここに入れるGUIDをどう導き出すか'
}

Role がGUIDであるため名前から推測できない。 ということで、Built-In Role、Custom Role それぞれで既存Roleを参照するときに工夫が必要となる。

Built-in Role

Azure が提供している組み込みRole は、全アカウントで Role Name となる GUID が固定である。

一覧: Azure built-in roles - Azure RBAC | Microsoft Docs

固定値なので何も考えずに GUID を必要に応じて渡すか、Role Name から GUID を返すだけのModuleを用意すればいいだろう。 現実的に考えると、bicepのモジュールは関数的に使うには無駄にしんどいので、GUID をそのまま渡すのがいいだろう。(terraform や Pulumiを考えると、こういうAzureで決定しているものの取得はbicep が組み込み関数で用意するべきだと思う)

例えば、AKS Clusterから ACR のイメージを取得する Role Assignment を与えるRole Assignmentを行うことを考えてみよう。 ACR からの Pull権限は、Build-in Role AcrPull で提供されており、GUID は 7f951dda-4ed3-4680-a7ca-43fe172d538d とわかっているので次のように書くことになるだろう。

resource aks 'Microsoft.ContainerService/managedClusters@2021-03-01' = {
  // プロパティ
}
resource acr 'Microsoft.ContainerRegistry/registries@2020-11-01-preview' = {
  // プロパティ
}
resource aksAcrPermissions 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
  name: guid(aks.name)
  scope: acr
  properties: {
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')
    principalId: aks.identity.principalId
  }
}

Custom Role

Custom Role を定義した場合、その Role が同じModuleやリソースから参照できるならそれを使えばいい。 そうでなく、先ほどの Build-in Role のように既存の取得をしたい場合、Role作成時 の name 時点で工夫するしかない。

RoleDefinitions の name は、GUID だ。このGUID に bicep の Guid関数を利用し、引数に roleName を指定すればいい。 こうすれば、参照する側は roleName がわかっていれば、Guid関数で逆引きができる。

コードで見てみよう。 ロールを作成するときに工夫するのがすべてだ。

var role_name = 'my_awesome_role'
resource hoge 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' = {
  name: guid(role_name) // ここで role_name を知っていればguid が算出できるようにする。
  properties: {
    roleName: role_name
    // ほかのプロパティ
  }
}

あとは、resource が直接参照できなくても、次の方法で導き出すことができる。

// subscriptionResourceId 関数で取得
subscriptionResourceId('Microsoft.Authorization/roleDefinitions', guid('my_awesome_role'))

// existing で取得
resource aksAcrPermissions 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = {
  name: guid('my_awesome_role')
}

来てほしい機能

いくつか書いていてつらいのでサポートが欲しい機能。

Azure Bicep の設計

Azure の構成を IaC したいとなると、おおむね選択肢は次の3つになりそうです。

  • ARM Template
  • Terraform
  • Pulumi

Terraform と Pulumi はおおむね同じ性質ですが、Pulumi は Azure に対しては他のクラウドよりも優先的に機能が入るのでちょっと面白いです。 とはいえ、世の中的には Azure の構成は ARM Template が一番合ってるといわれるとかいわれないとか。

ARM Template は人間が使うフォーマットじゃないので一ミリも興味がでなかったのですが、Azure Bicep が DSL として出てきたこともあり、ここしばらくはAzure で Bicep を使って構成してみたので設計メモを書いておきます。

tl;dr;

  • Bicep を用いて、コードとリソースの一致を保証することは ARM Template の現在の性質ではできない。Microsoft は Deployment Stacks と呼ばれる仕組みで改善を検討している。
  • Bicep は、Complete modeを使うとコードとリソースが一致することがある程度保障できる。IaCとして使うなら Complete 一択。(それでもずれる)
  • Completeでは、最後に適用したBiepデプロイでリソースが決定されるので、Bicep スコープは狭く維持する。このため、ResourceGroup を target scopeにするのがいいだろう。Bicepを分ける = ResourceGroupをライフサイクルで分けることになる。

Bicep と ARM Template

bicep は、ARM Template の DSLでARM Templateに変換される。あくまでDSLなので、デプロイを含めた仕様、制約はARM Template に準じる

ARM Template の特徴は次の通り

Stateless

ARM Template は、State を持たず Template = リソース定義のJSON とリソースを一致させる動作を目指している。(Terraform/Pulumi/CloudFormationはState を持つ)

Bicep は、コードとリソースの一致保障が仕組みとして存在していない。この対策として、bicep及び ARM Template ライフサイクル全体への改善として Deployment Stacks が検討されている。

Any plans for destroy functionality? · Discussion #1680 · Azure/bicep

デプロイのスコープ

デプロイは、target scope で設定できる。ResourceGroup / Subscription / Tenant と広くなっていく。

デプロイモードによっては、target scope で 1deployしか適用できないケースがあるので、スコープの決定は設計に大きく影響を与える。

基本的に、Bicep を分ける = ResourceGroup を分ける = ライフサイクルごとの管理、になるだろう。

デプロイモード

ARM Template Deployにはモードが2つある。

  • Increment (デフォルト)
  • Complete

Incrementは増分デプロイで古いリソースはテンプレートからは消えてもリソースは残る。

Completeはテンプレートにないリソースを消すが、消されるリソースと消えないリソースがあり、その動作はリソース次第。

Complete mode deletion - Azure Resource Manager

デプロイによる一致保障

ARM Template のデプロイの仕組みから、Bicep コードと テンプレートは一致と冪等性が保障されているが、コードとリソースの一致と冪等性は保障されていない。

あくまでも「適用されているテンプレート × デプロイモード」によって、リソースの状態が決定する。

デプロイ方法と適用

それぞれのscope に対して複数のdeploy を適用できる。

ただし、どの deploy が適用されるかは、モードによって変わる。

  • Incrementを使うと、増分なのでそれぞれの増分が適用される。(複数のDeployが当たる)
  • Complete を使うと、最後に適用したdeploy でリソースが構成される。ほかのdeployで適用されたリソースは最後のdeployのテンプレート次第で消える。(複数は当たらない)

Complete を使うとコードとリソースの一致は、デプロイ時は保障できる。だが、Completeによる削除処理はリソースによって「消えない」ため、削除操作によってコードとリソースは乖離していく可能性がある。たとえば、StorageAccountは削除されるが、Blob は消えない、など。

Increment は、削除を絶対にしないので、コードとリソースはどんどんずれていく。IaC で目指すコードとリソースの一致とは、そもそも目指すところが違うのでIaCをするのであれば Increment は使う理由がない。

IaC としての Bicep

IaC は、コードでリソースの状態を明確に示すことが重要になる。コードでリソースの状態を明確に示すというのは、今のリソースがコード通りであるといえる。

これは「コード以外のリソースは認めている」が、一方で「コードで管理されていたリソースが外れるときにそのリソースを削除する」というのも期待している。

つまり、コードとリソースを一致させるには、コードとリソースの同期をどうとるのか、同期が取れないリソースをどう扱うかが重要になる。

削除

Azure では リソース名 = リソースの一意性を意味する。

Bicep で定義したリソース名 (resource id) が変更されたときに、リソースはどのようになるのかかが IaC としてのBicep を決定する。

デプロイモードで記載した通り、次の挙動になる。

  • Increment = 増分デプロイなのでリソースの名前が変わったことを検知せず、ただ 「Template に存在しないリソースが増えたと解釈」される。結果、古いリソースは放置、新しいリソースが構成される。もしテンプレートが既存リソースに対する定義だった場合、リソースの設定をTemplateで上書き構成する。
  • Complete = Template とリソースの一致なので、Template 通りにリソースを構成する。具体的には、テンプレートにないリソースは、仕様で削除対象になってれば削除、削除対象じゃなければ放置。もしテンプレートが既存リソースに対する定義だった場合、リソースの設定をTemplateで上書き構成する。

Increment では削除が起こらない。

Complete では、Template と一致するように 削除が起こるが、削除されないリソースが多く、削除されなかったら自分で削除が必要になる。(コードとリソースの一致を目指していないのでそうなる)

Destroy

削除の挙動から予想できる通り、Destroy は存在しない。

Bicep の定義をまとめて吹き飛ばしたいときは、リソースが空な Bicep を Complete モードでデプロイする。

すると、Complete で削除する仕様のリソースは消える。消えない仕様のリソースは残る。

Bicep や ARM Template は IaC なのか

コードとリソースの一致を目指すIaC というよりは、Template と リソースの一致を目指しそのTemplateを生成する TaC というのが適切だろう。

Bicep と State

コードとリソースが一致できないのは、 Microsoft も把握している通り、Stateless であるためのライフサイクルマネージメントの困難さに起因している。

このため、Deployments Stack がくれば Bicep はおそらく コードとリソースの一致ができるようになるようにライフサイクルが改良されるだろう。

同時に、Stateを持たないことで、Template通りに構成を実行する Control Plane が Managed な Azure Resource Management であったが、State をどこに置くかというのを考えることになるだろう。

Bicep で IaC っぽく使う

Bicep というより ARM Template の現状の挙動は、いわゆる IaC に期待する挙動とは乖離しており、コードとリソースの一致も保証できないという意味では難しい。

  • Subscription: --mode がないのでComplete の指定はできない。安全優先って感じ。
  • ResourceGroup: 基本的にComplete で利用し、消えないリソースは都度消す (これが怖い) ようにすれば、おおむね IaC っぽくは利用できるだろう。

まとめ

Terraform x Azure は、書きにくいけどまともなIaC 体験は得られます。 Bicep は ARM Template が Stateless という性質を指向しているがゆえに、コードとリソースの一致が約束されないのが IaC 体験としては悪いものがあります。 というか、リソースが残ってしまって、それを消すときに事故臭しかしない。

Bicep自体というより、ARM Template の性質の問題なので、Deployment Stacks によって Stack のコンセプトが来たら体験が変わるのを期待したいところです。

ロジクールMX Anywhere3 に変えた

普段からどうしてもほしいものはない、のですがマウスだけはずっと満足いかずたびたび探しています。

ずっと使っているのが、ロジクールMX Master / MX Anywhere シリーズで、職場と自宅などでシリーズ初めから使っています。 MX Master は大きいので、MX Anywhere が好みでここ数年は常に MX Anywhere 2を使ってました。

ふと、マウスに不満を覚えて探して比較するものの、結局 MX Anywhere に戻ってきてしまう。 それは今回もそうなのでした。

MX Anywhere 3

MX シリーズは、大きめサイズでハイエンドな性能詰め込みました的な MX Master と 小さめサイズでなんでもできるけど人間工学的なデザインがない MX Anywhere があります。

f:id:guitarrapc_tech:20210703015101p:plain
https://www.logicool.co.jp/ja-jp/products/mice/mx-anywhere-3.910-006005.html より

youtu.be

youtu.be

私が愛用しているのは MX Anywhere です。

www.logicool.co.jp

以前はUnity 使うときは MX Master で、それ以外は MX Anywhere だったのですが、MX Anywhere を布教しまくってどこでも使ってたら慣れてしまいました。

MX Anywhere 3 は、MX Anywhere の最新版です。 for Mac もあって、こっちは Unifying レシーバーがなく Bluetooth接続対応のみになります。Mac / Windows 両方使うのですが、Macは専用でなくても十分安定しているので通常のを選びました。

Bluetooth 接続は、Windows/macOS のいずれにおいても負荷が極めて高い時に安定性に欠ける一方で、Unifying は安定しており UEFI でも問題ない& USB切り替えで複数接続が気にならないというのがポイントです。(使い込むほどUnifying 一択)

MX Anywhere 2 からの変更点

MX Anywhere 2 との変更点は書いてる人はたくさん書いてるのでそれを見てください。

news.mynavi.jp

k-tai.watch.impress.co.jp

MX Anywhere 3 にしたのは、MX Anywhere 2 の不満が解消されていたからです。 MX Anywhere 2 には次の不満がありました。

  • ミドルクリックがマウスホイールクリックではなく、ホイール下の小さなボタン
  • 横スクロールのホイール横倒しがしんどい
  • 充電ケーブルが micro-USB
  • 充電しても電池切れ期間が短くなってきた

改善点1. ミドルクリック

一番厄介で、慣れてしまうまで MX Master にしていた最大の理由が、「ミドルクリックがマウスホイールクリックではない」ということです。通常ミドルボタンは、マウスホイールであることが多いかと思いますが、MX Anywhere 2 までは違いました。

MX Anywhere 2の マウスホイールクリックは「スムーズスクロールの切り替え」です、意味が分かりません。MX Masterのように、高速スクロールで自動的にフリースピンにシフトすればいいじゃない。

私はWeb画面やコードはミドルボタンで自動スクロールさせて読むので、ミドルクリックを多用する割に使いにくい配置で最悪だと思ってます。

f:id:guitarrapc_tech:20210703014647p:plain
https://www.logicool.co.jp/ja-jp/manuals/11892 より

MX Anywhere 3では、ついにマウスホイールでミドルクリックできるようになりました。高速スクロールで自動的にフリースピンにシフトするし、普通になった。

f:id:guitarrapc_tech:20210703015407p:plain
https://www.logicool.co.jp/ja-jp/products/mice/mx-anywhere-3.910-006005.html#specs より

改善点2. 横スクロールがスクロールホイールになった

MX Anywhere 2 も MX Master もマウスホイールを横に倒すと横スクロールができます。 これ、一見すると直感的でいいんですが、スクロール量の調整ができなくて私には使いにくいです。

MX Anywhere では、ホイールは横に倒せなくなり、代わりに親指付け根あたりの左/右のどちらかのボタンを押しながらスクロールで横スクロールになります。 スクロール量の調整は普通のスクロールと同じなので普通に使いやすいです。普通に使える、大事。

f:id:guitarrapc_tech:20210703015407p:plain
https://www.logicool.co.jp/ja-jp/products/mice/mx-anywhere-3.910-006005.html#specs より

改善点3. 充電ケーブルが USB-C になった

micro-USB がそろろそ根絶したい今日この頃ですがそうもいかないのが続きます。 MX Anywhere 2 もその一つだったのですが、ついに USB-C になったのでまた一つ減りました。普通、大事。

充電を取り戻す

MX Anywhere 2 は毎日ずっと使っているので、一月程度で充電が必要になってきました。

MX Anywhere 3 に変えることでリセットです。

電池寿命: 1回のフル充電で最大70日使用可能。1分間の急速充電で3時間使用可能

まとめ

MX Anywhere のこれまでの良さである、軽くて小さい、マルチペアリングと切り替え、Unifyingによる高い安定性などのメリットはそのまま。 MX Anywhere 2 の欠点をカバーしてきて、満足度とおすすめできる度が高くなりました。

残りは静音性が次にほしくなる時の鍵になりそうですね。(クリックを静かにしたい欲)

リモートワークで使えるイヤホン

以前の記事で、リモートワークでイヤホンをいろいろ試したことを書きましたが、実際使えるイヤホン、使えないイヤホンの個人的なポイントを書いておきます。 なお、イヤホンといいつつヘッドホンやヘッドセットも含まれます。

なお、イヤホンの接続先は MacBook Air M1 です。

tl;dr;

  • 優先/無線なら、無線を選ぶと便利かつ今なら音質な問題もない。
  • スピーカーは、ノイズキャンセリングがあると周りの音よりリモートの音に集中できる。
  • 最重要はマイク。ヘッドセットのような口元マイク(ブームマイク) + ノイズキャンセリングがついているのがいい。
  • 骨伝導ヘッドセットだと耳を覆わないので、長時間の着用がつらくない、家で周りの音も聞こえつつリモートの音に集中できてよい。

(よかった) Sony MDR-1000X

以前買っていた古いヘッドホンを引っ張り出して来たら、マイク、スピーカーともに優秀でした。(2017年2月購入) ワイヤレスノイズキャンセリングステレオヘッドセットとかいうだけあって、マイクの音もしっかり伝わり、スピーカーも問題ありません。 ノイズキャンセリング、大事。

www.sony.jp

今なら、正当進化したWH-1000Xシリーズでいいかと思います。

www.sony.jp

MDR-1000Xは好きだったんですが、筐体が弱く、イヤーパッドの上の本体部分の樹脂が割れてお蔵入りしていました。

f:id:guitarrapc_tech:20210604154213p:plain
壊れやすい箇所

飛行機でも音が気にならないので、本当にいいイヤホンです。(CES で気になって買ったやつでした)

(よかった) AfterShockz OPENCOMM

前回も書いた骨伝導イヤホンです。詳しくはそっちを見ていただければ。

同ブランドにAEROPEX というのもありますが、比較動画でわかる通りマイク性能が違います。

AEROPEXaftershokz.jp

リモートワークで気になるのが、話している相手の声、じゃなくてキーボード音なのですね。 OPENCOMM は、AEROPEX に比べて、スピーカー直と違和感ない程度には声が曇らず、キーボードのタイプ音も小さくなります。 OPENCOMM + Krisp のソフトノイズキャンセリングが組み合わさると、キーボード音がほとんど消えるのでこの組み合わせが気に入っています。 Aeroとの違いはマイク部分なので、なるほどブームマイク + ノイキャン効果ある。

www.youtube.com

ということで、キーボードタイプ音がうるさいか気になっている人は OPENCOMM 使うといいです。Krisp も組み合わせてください。 今一押しはこれですね。

ちなみに、マイク部分を上に上げると、外部の音がマイクから伝わりますが、マイクが口元にあるときは周辺の音がマイクから先に伝わりません。 普通にBGM鳴らしていても伝わらないので結構すごい。

(だめだった) WH-CH710N

いろいろ試そうと思って、MDR-1000Xよかったし、今の下位モデルでもいいのではと思って試しました。

www.sony.jp

スピーカーはいいのですが、マイクが壊滅的で、リモートワークでZoom/Meets/Teams ともに声が小さく、ぶつぶつ切れるという状況になりました。(krisp オフでも変わらず) マイクがほぼ機能しないので致命的でダメです。

(だめだった) HyperX Cloud Stinger

有線で、口元にマイクがあってよさそうじゃないですか。 無線より有線がいいという言説をよく聞くのでどうかなぁと思って試しました。 が、マイクがだめで声が大きくならずぶつぶつ切れるという状況になりました。(krisp オフでも変わらず)

www.hyperxgaming.com

スピーカーもノイキャン付きの Sony に比べて蒸れて熱くなりやすく、好みではなかったです。

まとめ

いまならオープンエアーかつノイキャン付きのAfterShockz OPENCOMM がいいですね。 部屋で閉じこもって、外の音を気にしたくないなら、WH-1000X でもいいかと思います。

AirPods も知人と試した感じだと問題ありませんでしたが、私は使ってないので記載していません。

そういえば、一時 Bose や Plantronics がリモートワークで使えると話題になったのできになるところですが、OPENCOMMベースで考えると満足できるのかな。 片耳はなんとなくずっと避けているのですが。

リモートワークでの切り替え

リモートワークが続いて1年余り経ちました。 ここ半年余りの課題は、仕事中の集中、切れ目の2つなのですが、解消するために何をしているか残しておきます。

tl;dr;

オフィスで集中で来ているなら、その状況を作れるように努力する、ということでいろいろやっています。

  • 机の上をオフィスと同じようにする。
  • 仕事前に身支度を整えて恰好から入る。
  • 一日の目標は意図的に細かく書き出して達成目指す。
  • Twitter は開かない。
  • 骨伝導ヘッドセットを付けて過ごすことにしたところ、以前オフィスで仕事をしていた時のように意識を切り替えるのが楽になった。
    • 骨伝導で 16時間使い続けられるのは本当に楽なのでよいです。
  • 昇降デスクや昼寝など、自分の癖にあった対策はする。
  • ごはんはサラダから (冗談のようで本気)

課題

結果は出す、けど自分が納得いく集中状態に入っていたかというと疑いがあるので、「リモートワークでの切り替え」でいかに集中状態にもっていくかが課題です。

もともと私はずっと仕事をしていても気にならないほうです。 これは、仕事と楽しいことが一致しているからなのですが、夢中になって気づいたら時間が過ぎていることがほとんどです。

ただ、リモートワークだと今までオフィスや深夜の集中で得ていたなにかと別の能力が求められるようです。 オフィスでの仕事だと簡単に集中に入るのが、リモートワークだとあと一歩足りないような。(語彙力) 時間は過ぎているけど、自分が自分に期待するだけの納得いく進捗を感じないような。(表現力)

深夜作業や緊急メンテなどで容易に得ている集中を継続的に再現したいです。

切り替えを促すためにやっていること

意識の切り替えは自分への暗示だと思っているので、いくつかやり方が思いつきます。 太字にしたものは、私が今行っていることです。

  • 机の上をオフィスと同じようにさっぱりと片付ける
  • カメラでずっと映るようにする
  • 常時オンライン雑談部屋に参加
  • 一日、あるいは単位時間の目標を常に示して細かく達成していく
  • 仕事と私生活の場を切り離す
  • スマホを見えないところに置いておく
  • Twitter を開かない
  • 仕事のトリガーを作る
  • 集中切れた、眠くなった対策

知人は、仕事用の部屋に移ってやることで完全に意識を切り替えているということで、これはいいなぁと思います。 ただ、あいにくと私はそういう部屋を設けているわけではないのでなしです。

やっていることを簡単に振り返っておきます。

(集中) 机の上をオフィスと同じようにさっぱりと片付ける

私の普段のデスクの状態です。 仕事場でもそうなのですが、私は極力ものを減らすのが好きなので机の上はキーボード、マウス、切り替え、お茶、スマホのみです。

オフィスと家で、同じように余計なものを置かないので代わり映えしないとも言います。

f:id:guitarrapc_tech:20210529015554p:plain
デスクの上

オフィスだとスマホはカバンにいれているので、スマホはノイズですが、後述します。

(集中/切れ目) 常時オンライン雑談部屋に参加

常時オンライン雑談部屋に参加していると、いつ声がかかってもいいようになります。という意味で、結構切り替えを促してくれています。 一緒の部屋で仕事をしている、というほどではないのですが、一緒にやっているという空気感はあるようです。

もちろん、必ずしも雑談しないといけないわけでもなく、必要な時に相談を行ったりという自由があるぐらいが気楽に感じます。 仕事終わるときに抜けると切れ目にもなります。

経緯

リモートワークが始まって3か月ぐらい経ったころの2020年6月までは朝ミーティングのみオンラインでやって、以降は必要に応じてオンラインにしますが基本オフラインでいました。が、限界を感じたので、常時オンラインをやるようにしてもらいました。(フットワークの軽いチームですごくいい)

リモートワークになることの最大のつらみは、信頼を貯める方法が減る、雑談機会の減少と思っています。

オフィスでの作業が別に最高とは言わないのですが、顔を合わせる以外に人となりを知っていることによる信頼はあったようです。さりげない会話や雑談、相談時のレスポンス、応答の様子をオフラインで行うと、比較的に好意的に受ける情報が想定していたのより大きいのだなぁと思います。1

リモートワークでの作業は、チャットやコード、レビューといったテキストベースのコミュニケーションに偏重していくように思います。 これは、たとえ朝・常時オンラインで話していても、観測範囲では例外なくその傾向があります。 オフラインで得られていた相手を信頼する機会/信頼される機会、オフィスでは自然と周りから聞こえてくる雑談を得る機会は意識してても減りました。失ってみて雑談が仕事上で大きかった、と3か月の間にたびたび感じることがあり危機感を覚えていました。

当時はそういう意味で「オフィスでの信頼貯金を崩しながらリモートワークをしている」と感じており、そろそろ限界を感じで常時オンラインミーティングに参加するというスタイルに切り替えたのでした。

切り替えてしばらくはお互いに遠慮するような「ぎこちなさ」がありましたが、一年もやっていると自然になってきているようで、雑談をする機会も増え、カジュアルなやりとりから相手を信頼をする機会も増えてきているのでいい傾向だと思います。 それでもオフラインのほうが楽なのは、やはり難しい。

よく言われることですが、人間は声だけでは冷たい印象を受けるので、顔や素振りを含めたコミュニケーションが圧倒的に有利です。つまり、オンラインでのコミュニケーションで白熱するとハラハラします。

課題

オフィスでも起こるものの、オンライン雑談のみになるとより起こりやすい課題がいくつかあります。

一つ目は、声が思ったより響いて集中が切れる問題です。 オフィスでもあった? そうですね、ではオンラインミーティングではどうやりましょう問題があります。 今のところ邪魔にならない程度までボリュームを落とすことで、意識に入ってきにくいようにしていますが、気づきにくくなるのが怖いところ。(でもボリューム落とす)

二つ目は、コミュニケーションの乏しい相手ができることです。 これはチャットでも同じ課題があるのですが、やり取りをしない相手とは関わる機会が極端に減ります。2 オンライン雑談でも、何もやりとりの機会がなければずっと同じでしょう。リモートワークでは常時オンライン雑談にいても喋ること自体のハードが高く、難しいものがあります。(伝われ) 別にそれでもいいのかもしれないとも思いますが、どうなんだろう。

三つ目の課題は、雑談の総量の減少です。リモートオンラインって、頑張っても一つしか聞こえないんですよね。オフラインだと複数チャンネルきこえて、たとえ自分がかかわっていなくてもやり取りが聞こえる、というのがありましたが。

四つめの課題は、オンラインで喋った内容をチャットやドキュメントに残す癖がないと取り残される人がどうしても発生することです。これは会話する人ほど気づきにくい問題で、取り残される人は未来の自分も会話を忘れれば該当するのですが、当事者になるまで自覚できないのが厄介です。 オフィスでも起こるんですけど、ほかの人が意外と覚えてて救われた経験ありませんか? 私はあります。 リモートワークだからこそ、チャットなどに会話の内容を要約して書く癖はあるといいと思います。(やる人を尊敬しています) この問題はあるいは、自転車置き場問題とも近いものがあるので、永遠に難しいですね。

2021年になっても、こういう基本的な課題が解決があると感じます。

(集中) 一日、あるいは単位時間の目標を常に示して細かく達成していく

始業時に、今日これやります、とチャットに書いておく、その程度でも効果はあります。 自分自身の予定というメリットもありますが、リモートワークでチームみんながやることを書いているのは、チームの状態共有や相談のきっかけになったりしてて良いと感じます。

コツ

やることを一つ二つ書くよりも、意図的に内訳を細かく書いて、自分で自分の達成を意識するのが好みです。 やりすぎはよくないけど、やることが目の前にはっきりしていると集中できるタイプの人間です。 「これが終わった、次はこれ」、たぶんこれが私が集中するルーティンで一番効果があります。

NOTE

終業時にやったことを書くのは、振り返りという意味でありなきもするけど、私は朝やることをどんどん追記しているのでどっちでも。

Disclaimer

ここではあえて、アジャイルなどの開発手法とは混ぜて書きません。

(集中) Twitter を開かない

これはTwitter に限らず、自分が頻度を高めにをやっているSNSと置き換えてもいいかもしれません。

私は、PC上ではTwitterを「ブラウザで特定のプロファイルを使わないとみれない」ようにしています。 仕事用のブラウザプロファイルでは見れないようにしてあるので、Twitterを見れるプロファイルでブラウザを起動しないルールを自分に課すことで集中の分散を防いでいます。

経緯

よく見かける気がしますが3、Twitter を見るというのは時間が消えます。 自分にはない知見を得られる場なので、おもしろく当然だと思います。 ただ、面白いということは他で使っていた集中が途切れているとも思うので、私は見ないようにすることを仕事との切り替えに利用しています。

(集中/切れ目) 仕事のトリガーを作る

今から仕事、仕事おわり。を示す方法として、物理的に身に着けるものがあるのは有効だと思っています。 出社のように、顔を洗って家仕事用の服に着替えたりといった身支度はしていましたが、それは休日でもあまり変わりません。

ということで、骨伝導ヘッドセットのAfterShokz OPENCOMMを仕事の時に身に着けるようにしました。

OPENCOMMaftershokz.jp

いくつか使ってて良いことを書いておきます、やりたいことができて、細かい不安がないのがいいです。

  • Zoom / Google Meets / Teams でもマイク、スピーカーともに問題なく、ノイズキャンセリングヘッドセットなのもあり、相手からも声がきっちりとどいているといわれており安心して使えます。(私は MacBook Air M1 とつないでいます)
  • イヤホン、ヘッドホンと違って一日つけるのを続けていても痛くなったりしないのは骨伝導のメリットと当時も今も思います。
  • 骨伝導は5年前に使っていた頃は2時間あまりしか持たず微妙でしたが、これは16時間つなぎっぱなしもできるので、バッテリーで困ったことがありません。(充電がマグネットなのもよい)
  • もし充電をずっと忘れても急速充電が可能(5分充電するだけで2時間使える)なので適当になんとかなります。

ここ半年、特に集中状態にもっていくのに結構悩んでいたのが、これを付けるようにしてオフィスの感覚により近づいているので維持したいところです。

ヘッドセットを外すと仕事終わり、つけると仕事で集中、という自己暗示に便利。

経緯

オフィスにいたときから、集中するためにイヤホン、ヘッドセット、骨伝導イヤホンといろいろ使っていました。 リモートワークになってみると、オフィスと違ってマイク問題が結構課題で、ヘッドセットのマイクだとリモートミーティング時に音が切れたりしたのでつけるのをやめていました。 あと、家だからこそ、周りの音が聞こえないのは主に宅急便などで困る。

リモートワークになってから、このヘッドセットを見つけるまで試行錯誤を繰り返しました。(たびたび試した4品全部だめだった)

(集中) 集中切れた、眠くなった対策

集中が切れたり、眠くなることもあります。(寝ないでいれても、集中が底辺になるのがまずい)

  • 軽く集中が切れたときとかは、昇降デスクなので立って仕事しています。気づくと深夜までたってます。
  • 完全に眠い時は、昼ごはん後に15分寝ています。あきらめて寝ると、眠気飛んで集中がすごいので割り切っています。

幸い目覚ましを無限にかけるので昼寝で寝過ごしたことはないのですが、夜しっかり寝るのがいいでしょう。4

あ、ご飯はなるべく食べましょう。食べたら眠くなる?これはお得情報ですが、サラダ山盛り食べてからほかのものを食べ始めると、冗談抜きで食後眠くならないのでオススメです。セブンの大根サラダを食べています。

7premium.jp

経緯

オフィスにいるときだと、少し外に出てコンビニ行ったりするやつですね。 リモートワークだと本当に外でないですよね、私のリモートワーク中の徒歩は平均300歩でした。 ということで、試行錯誤してモノで解消できるならする、など打てる手は打つようにしています。

今後やるか検討していること

今はデメリットも感じるのでやっていないものの、間違いなく効果があるので検討しているものです。

(集中) スマホを見えないところに置いておく

オフィスと同様に、目に写らないように片付けようかと思っています。 集中して存在が目に入らないことも多いのですが、チャットの通知など気にしたいことがあり、悩んで一年経ちました。

ただ、通知に気づかないとそれはそれで困るので、果たしてどうするのがいいのかまだ悩んでいます。 オフィスだと、誰かに甘えてたんですね。(どうしても気づかないときは声をかけられていた)

まとめ

いろいろ書いていますが集中は今でも課題で、やっぱりリモートワーク難しいなぁと思っています。 深夜に一人で仕事して、しっかり集中もしていたので、ここまで悩むことになると思ってなかったのですが、どうやらリモートワークはそれとは別の何かが必要なようです。

リモートワークでもできる、けど、よりよい方法を見つけられていないと常に感じます。 ほかの人のやっていることも、見つけると試すのですがなかなかしっくりこない。

もっと細かく自分で分析していかないと改善するのは難しいのかもしれない。

そして、お前は本当にオフィスで日中集中できていたのか?


  1. カメラだとそこまで感じないのはなぜだろう

  2. 私が times チャンネルを嫌う理由は、この問題を加速させるためです

  3. この時点でだめ

  4. それはそう