Firefox の JS コンテキストのロケール指定方法
背景・目的
WebDriver 経由で geckodriver + Firefox を操作して JS の自動テストを行いたい。 その時、JS にロケール依存の処理が含まれていれば、テスト実行時にも Firefox の JS コンテキストのロケール指定を行いたい。
3 行まとめ
詳しい話
ECMAScript と国際化
ECMAScript における国際化のための仕様として ECMA-402 (ECMAScript Internationalization API Specification) というものがある。
この仕様により、例えば Date.prototype.toLocaleString
メソッドなどが定義される。 このメソッドの呼び出し時にロケールを明示的に指定しなかった場合、使用されるロケールは DefaultLocale
抽象操作によって決まる。 DefaultLocale
は実装依存である。
Firefox での DefaultLocale
(JS コンテキストのデフォルトロケール)
Firefox における ECMA-402 の DefaultLocale
の実装は、Firefox のロケールを返すようになっている模様。 ちゃんとしたドキュメントは見当たらなかったが、Bugzilla で教えてもらった。
JS context locale is tied to Firefox locale, not requested locale.
1475876 - intl.locale.requested doesn't affect to JS locale unless Language Pack is installed
Firefox のロケールの決まり方
で、Firefox のロケールの決まり方であるが、RFC 5656 をベースに、available locales と requested locales から決まるらしい。
Due to the imperfections in data matching, all operations on locales should always use a language negotiation algorithm to resolve the best available set of locales, based on the list of all available locales and an ordered list of requested locales.
Such algorithms may vary in sophistication and number of strategies. Mozilla’s solution is based on modified logic from RFC 5656.
Locale management — Mozilla Source Tree Docs 63.0a1 documentation
Available locales は、Firefox のパッケージに含まれているロケール (packaged locales) と、拡張機能としてインストールされた言語パックのロケール。
In Gecko, available locales come from the Packaged Locales and the installed language packs. Language packs are a variant of web extensions providing just localized resources for one or more languages.
Locale management — Mozilla Source Tree Docs 63.0a1 documentation
デスクトップ版の Firefox では、Packaged locales は普通は 1 つのみ。 Android 版の方は 100 ぐらいのロケールを含むらしい。
When the Gecko application is being packaged it bundles a selection of locale resources to be available within it. At the moment, for example, most Firefox for Android builds come with almost 100 locales packaged into it, while Desktop Firefox comes with usually just one packaged locale.
Locale management — Mozilla Source Tree Docs 63.0a1 documentation
Requested locales は次のとおりで、intl.locale.requested
pref に保持される。
After the sanitization, the value will be stored in a pref
intl.locale.requested
. The pref usually will store a comma separated list of valid BCP47 locale codes, but it can also have two special meanings:
- If the pref is not set at all, Gecko will use the default locale as the requested one.
- If the pref is set to an empty string, Gecko will look into OS app locales as the requested.
The former is the current default setting for Firefox Desktop, and the latter is the default setting for Firefox for Android.
Locale management — Mozilla Source Tree Docs 63.0a1 documentation
なので、基本的には使いたいロケールが Firefox のパッケージに含まれるロケールか言語パックとしてインストールされたロケールであれば、intl.locale.requested
にそのロケールを指定してやれば JS コンテキストのロケールがそのロケールになる。
en-US ロケールは特殊なロケール
日本語ロケールのデスクトップ版 Firefox で intl.locale.requested=en-US
とした場合、英語の言語パックをインストールしていないと en-US ロケールにはならなさそう (available locales に含まれてないはずなので) なのだけど、実際には JS コンテキストのロケールは en-US になっているような挙動になった。
なんでだろー、と思ったのだけど、どうやら last fallback locale という特殊な扱いで en-US が使われてるらしい。
Gecko also support a notion of last fallback locale, which is currently hardcoded to “en-US”, and is the very final locale to try in case nothing else (including the default locale) works.
Locale management — Mozilla Source Tree Docs 63.0a1 documentation
悩み
というわけで、複数のロケールを切り替えて JS のテストをしたい場合は、言語パックをインストールすることになるっぽい。 もしくはロケールごとに Firefox のバイナリを用意するか。
言語パックのインストールがコマンドライン上で簡単にできればいいのだけど、ちょっと調べた感じでは大変そうで、どうしたものかなーと思っている。 簡単にできる方法があれば教えてください!
参考
- Locale management — Mozilla Source Tree Docs 63.0a1 documentation : 詳しいことは全部ここに書かれている。
- 言語パックで Firefox のインターフェイスを他の言語にする | Firefox ヘルプ
- Firefoxの言語設定 - Hideki Saito Wiki Japanese : Firefox 59 から UI のロケールの指定方法が変わったとのこと。
Acknowledgement
この記事の内容は、株式会社 OND の仕事の一環として調べたものです。
MySQL (InnoDB) とトランザクション分離レベル・ロック
(注記) 去年書いて下書き状態になってた記事をそのまま公開した。 MySQL 8.0 公開前に書いた内容なので MySQL 5.7 について言及しているが、多分 MySQL 8.0 でも基本的には変わらない気がする。
背景・目的
DB 上に指定の ID の行が存在していれば UPDATE
して、存在していなければ INSERT
したい、ということは web アプリケーションを書いているとよくあること。 SQL:2003 標準には MERGE
が導入されていて、Oracle Database なんかだと MERGE
を使用できるようだが、MySQL では使えない (バージョン 5.7 時点)。 (代わりに INSERT ... ON DUPLICATE KEY UPDATE
がある。)
また、複数のテーブルで 1 つの集約 *1 を表現していて、集約の更新時に不整合が起きないようにロックをかけたいということも多い。
といったあたりで、MySQL (InnoDB) における参照や挿入、更新とトランザクション分離レベルやロックについて調べたのでまとめておく。 (初心者が調べてみたぐらいの内容なので、指摘やコメント等頂けると嬉しいです!)
調べた結果どうしたらいいかの個人的見解
いろいろ調べた結論としては、個人的には以下のような感じがいいのかなーと思っている。
- 参照系ではトランザクション分離レベルを REPEATABLE READ にする。 → 参照だけであれば一貫性のある読み取りができる。
- 単一の集約に対する更新系 (新しい集約の新規作成や既存の集約の更新; INSERT or UPDATE) では、トランザクション分離レベルを READ COMMITTED にして *2、集約ルート (に対応するテーブルの行) の存在確認を
SELECT FOR UPDATE
で行う。- 存在すればそのままロックを保持して更新処理を行う。 → 集約ルートに対する排他ロックを獲得しているので、他のトランザクションによる更新と衝突しない。
- 存在しなければ
INSERT
する。 Duplicate error になったら (すなわち同時に実行されていた他のトランザクションによる挿入が行われた場合は) トランザクション自体を再開してやり直すか、エラーということでそのまま処理を終了する。 → こちらも挿入に成功すれば排他ロックを獲得するので、そのまま処理を進めて良い。 Duplicate error になった場合には対象行の共有ロックを獲得してしまうため、やり直す場合にはトランザクション自体をやり直さなければならない *3。 - 実装依存でも良ければ
INSERT ... ON DUPLICATE KEY UPDATE
で良い場面が多そう。 - パフォーマンスを気にしなくてもいいならトランザクション分離レベルを SERIALIZABLE にするとかも有りかもしれない。
- (だいたい songmu さんが書いてるとおりの結論ではある。)
参考ページ
- doc/innodb.md at master · ichirin2501/doc · GitHub : MySQL のロックの挙動がいろいろ書かれている。 非常に参考になる。
- 漢(オトコ)のコンピュータ道: InnoDBのREPEATABLE READにおけるLocking Readについての注意点 : REPEATABLE READ で参照系が一貫性のある読み取りになる話。 (あるいは Locking Read は一貫性のある読み取りにはならない話。)
- 世界の何処かで MySQL(InnoDB)の REPEATABLE READ に嵌る人を1人でも減らすために - KAYAC engineers' blog : こちらも REPEATABLE READ における Locking Read が一貫性のある読み取りにはならない話。
- kamipo TRADITIONALでは防げないINSERT IGNOREという名の化け物 | おそらくはそれさえも平凡な日々 :
INSERT IGNORE
は良くないという話と、INSERT or UPDATE の方法について。 ちなみに 『DELETE
してINSERT
』 は、REPEATABLE READ で対象の行が存在しない場合 (DELETE
で 1 件も削除されないとき) に、デッドロックが発生しうる *4 気がする。
MySQL (InnoDB) のロックについて
以下、自分が知らなくて調べた話をだらだら書いておく。
ロックの種類
MySQL 5.7 の英語ドキュメントにまとまっている。
インデックスに対するロック
InnoDB では、インデックスに対するロックによって行レベルロックを実現している *5。 MySQL の公式ドキュメントやかみぽさんの解説がわかりやすい。
- レコードロック (Record Locks) : インデックスレコードに対するロック。
- ギャップロック (Gap Locks) : インデックスレコード間の隙間 (gap) に対するロック。 隙間は、複数のインデックス値にかかることもあるし、単一のインデックス値や空のところにさえもかかりうる *6。 ギャップロックは、他のトランザクションが同じ隙間のギャップロックを獲得することは防がない。 対象の隙間へのレコードの挿入のみが防がれる。 (つまり、共有ギャップロック (gap S-lock) も排他ギャップロック (gap X-lock) も効果は同じ。)
- トランザクション分離レベルを
READ COMMITTED
にすると、ギャップロックは無効化される。
- トランザクション分離レベルを
- ネクストキーロック (Next-Key Locks) : レコードロックと、そのレコードの前の隙間に対するギャップロックの組み合わせ。
Insert Intention Locks
INSERT
操作時に、行の挿入前に獲得されるギャップロックの一種として、挿入インテンションロック (Insert Intention Locks) がある。
『MySQLでINSERTのデッドロックに嵌る人を1人でも減らすために - ichirin2501's diary』 におけるデッドロックは、別のトランザクションが行を挿入して獲得した排他レコードロックと、挿入しようとしている行のための挿入インテンションロックの衝突が 2 箇所で起こってしまう、ということなのかな? と思ったりしたけど、InnoDB monitor の出力を見た感じでは共有レコードロック待ちになってたので挿入インテンションロック待ちとは違ってそうだった。 挿入インテンションロックは純粋にギャップロックとのみ衝突するもので、レコードロックとは衝突しない模様。
ギャップロックとファントム行、あるいはデッドロック
ファントムリードを防ぐために
ギャップロックと挿入インテンションロックのデッドロック : mysqlのネクストキーロックと挿入インテンションギャップロックのデッドロックを確認する | ++頭道++
mysqlのネクストキーロックと挿入インテンションギャップロックのデッドロックを確認する | ++頭道++ → この人の解釈では DELETE
により指定の ID に対するロックができる (存在しないレコードに対するロックという解釈をしている) となっているが、私の手元の MySQL 5.7.20 で試した限りでは、存在しない ID を指定しての DELETE
でギャップロックが獲得されていた。
下書きはココで終わっていた
多分他にも書きたいことがありそうだったけどもはや何も覚えてないのでこのまま公開する。
*1:DDD でいうところの集約。 Aggregates。
*2:この理由は主にギャップロック無効化のため。 ギャップロック有効だとデッドロックしうる; REPEATABLE READ でもギャップロック無効化できるしそうする方がいいのかもしれない
*3:そうしなければ、複数トランザクションで同一行に対する duplicate error が起こった場合にトランザクションをやり直さないと排他ロックの獲得ができず、デッドロックになる
*4:複数のトランザクションが DELETE するとそれぞれのトランザクションがギャップロックを獲得し、その後の INSERT がそれぞれ待ち状態になってしまう。
*5:という理解であってるよね?
*6:空のインデックスでも全体に対するギャップロックがあり得る、ってことかな?
PostgreSQL と H2 Database の両方で使える SEQUENCE 値生成方法 (MySQL の AUTO_INCREMENT 的なやつ)
SQL DB に新しい行を挿入したときに自動的に ID 値を生成して欲しいことはままある。 このような処理をしてくれるテーブル定義についての話。
MySQL だと AUTO_INCREMENT を使いがち
MySQL を使ってる場合は AUTO_INCREMENT
で済ませちゃうことが多い (H2 Database でも使用可)。
CREATE TABLE "foo" ( "id" BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY );
PostgreSQL のための AUTO_INCREMENT 以外の方法
ただ、PostgreSQL では AUTO_INCREMENT
が使えない。 代わりに使える方法を 2 つ書いておく。
BIGSERIAL 型を使う
PostgreSQL で、テーブル定義時に型として BIGSERIAL
型を使用すると内部的に SEQUENCE を利用するようになる。
The data types smallserial, serial and bigserial are not true types, but merely a notational convenience for creating unique identifier columns (similar to the
AUTO_INCREMENT
property supported by some other databases). In the current implementation, specifying:CREATE TABLE tablename ( colname SERIAL );is equivalent to specifying:
CREATE SEQUENCE tablename_colname_seq; CREATE TABLE tablename ( colname integer NOT NULL DEFAULT nextval('tablename_colname_seq') ); ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;PostgreSQL: Documentation: 10: 8.1. Numeric Types
上の例では SERIAL
型が使われているが、これは INTEGER
相当なので、BIGINT
相当のサイズにしたければ BIGSERIAL
を使用すること。
ちなみに BIGSERIAL
は H2 Database でも使用できる (ちゃんとしたドキュメントは見当たらなかった)。 MySQL でも SERIAL
は使用できる (MySQL の場合は SERIAL
で BIGINT
になる) が、BIGSERIAL
は使えない (MySQL 8.0 で検証)。
外部 SEQUENCE 生成子を使う
標準 SQL に従った方法はこれっぽい。 上の SERIAL
型を使った場合と等価な例に載っているような形になる。 ただ、H2 Database は SEQUENCE の所有カラムを明示できないようなので、そこは指定しないでおく。 (H2 Database でも使いたいので。)
CREATE SEQUENCE "foo_id_seq"; CREATE TABLE "foo" ( "id" bigint NOT NULL DEFAULT nextval('foo_id_seq') );
- PostgreSQL : PostgreSQL: Documentation: 10: CREATE SEQUENCE
- H2 Database : SQL Grammar
参考
- i am BEST : MySQL 固有の SERIAL データ型を標準SQL で書き換える(内部シーケンス生成子:IDENTITY) : 本記事では触れていない内部シーケンス生成子の話なども。
- 旧・そーだいなるらくがき帳: MySQL使いの人がPostgreSQLを始めるときの罠をまとめてみた
WebdriverIO を使い始めるときのハマりどころ (geckodriver を添えて)
WebDriver で Firefox を操作するために Node.js 用の WebDriver バインディングである WebdriverIO を使ってみました。
使ってみると意外とハマりどころがあってちゃんと使い始めるまでに時間がかかったので、自分がはまったところを書き残しておきます。
自分の環境
- OS : Windows 10 Pro 1803 (Spring Creators Update)
- WebDriver リモートエンド
- geckodriver 0.20.1 (Firefox の Marionette に対するプロキシとして WebDriver の API を提供するやつ)
- 操作対象のユーザーエージェント (ブラウザ) : Firefox 60.0.1 (64 ビット)
- 注意点) Selenium Server を経由せず、geckodriver が提供する WebDriver の API を直接使用する。
- クライアント側
- Node.js 8.6.0
- npm 5.3.0
- TypeScript 2.8.3
- WebdriverIO 4.12.0
- @types/webdriverio 4.10.1
私は TypeScript で書いてるので、もともと JS で書かれてたサンプルコード以外は全て TypeScript のコードである。
ハマったところ
クライアントの生成 (接続先の指定)
例などを見ると、クライアントの生成は以下のように書かれているが、詳細なドキュメントが見当たらない。 (どこかにあるかもしれないが見つけられなかった。)
var webdriverio = require('webdriverio'); var options = { desiredCapabilities: { browserName: 'chrome' } }; var client = webdriverio.remote(options);
geckodriver を使う場合に、WebDriver のリモートエンドの URL を指定する方法がわからなかった。 TypeScript の型定義を見ると、オプションに baseUrl
があったので以下のような指定をしてみたが、
import * as wd from "webdriverio"; let wdClient = wd.remote({ baseUrl: "http://localhost:4444" });
残念ながら以下のようなエラーが返ってきた。
Error: POST /wd/hub/session did not match a known command
このエラー内容から察するに、どうやら Selenium Server への接続を想定しているようである。 そしてよくよく調査すると、baseUrl
に何を指定してもホスト 127.0.0.1 の 4444 ポートに対してリクエストを試みているようであった。 (baseUrl
の指定が効いていない。) 他のオプションも試してみて、結論としては host
、port
、path
といったオプションで、接続先を指定できた。
import * as wd from "webdriverio"; let wdClient = wd.remote({ host: "localhost", port: 4444, path: "/" });
非同期処理とエラー処理
サンプルコードを見ると、メソッドチェインで処理を繋げられるようである。
client .init() .url('https://duckduckgo.com/') .setValue('#search_form_input_homepage', 'WebdriverIO') .click('#search_button_homepage') .getTitle().then(function(title) { console.log('Title is: ' + title); // outputs: // "Title is: WebdriverIO (Software) at DuckDuckGo" }) .end();
この例を見てもどういう順序で実行されるのかわからないだろう。
普通に実行するとすべてのメソッドは非同期処理になる。 しかし、WDIO というテストランナー上では同期的に実行される。
Each command documentation usually comes with an example that demonstrates the usage of it using WebdriverIO’s testrunner running its commands synchronously. If you run WebdriverIO in standalone mode you still can use all commands but need to make sure that the execution order is handled properly by chaining the commands and resolving the promise chain.
WebdriverIO - API Docs
初見殺しもいいところである。 ちなみに @types/webdriverio の型定義としては、同じメソッドで非同期的なときの返り値の型と同期的なときの返り値の型の intersection type で定義されてたりする。 難しすぎる。
上のサンプルコード (+ インポート処理やクライアント準備) を、TypeScript の async/await を使ってエラー処理も含めていい感じに書き直すと以下のような感じになる。
import * as wd from "webdriverio"; (async () => { let client = wd.remote({ baseUrl: "http://localhost:4444", path: "/" }); let session = client.init(); try { await session.url('https://duckduckgo.com/'); await session.setValue('#search_form_input_homepage', 'WebdriverIO'); await session.click('#search_button_homepage'); let title = await session.getTitle(); console.log('Title is: ' + title); // outputs: // "Title is: WebdriverIO (Software) at DuckDuckGo" } finally { await session.end(); } })().catch(e => console.error(e));
一度理解してしまえばメソッドチェインで書けるのは便利ではあるが、最初の理解が難しかった。
余談だが、バージョン 3 でコア部分が Ajax/Promise ベースの Monad に書き換えられて、コマンドチェインや Promise の扱いがやりやすくなって今の形の API になったらしい。
Some big changes came along with v3. We’ve rewritten the whole core to an ajax/promise based monad. Instead of implementing a complex command scheduler or request queues we built the whole library on top of a monad construct. This allows us to chain commands as we are used to and keep stacktraces sane. In addition to that we wanted to have 1st level promise support. Therefore we used the Q library (there are already plans to move to native Promises) to integrate promises into the monad system. This works astoundingly well. Each command execution represents a promise. If you chain commands, the command waits until the previous command is resolved. On top of that, the optional modifier that you can pass to a monad makes the library incredibly flexible and extensible.
WebdriverIO - What's new in WebdriverIO?
セレクタについて
WebDriver では、要素の選択に使用できるセレクタに種類がある。
WebDriver12.1 Locator Strategies
An element location strategy is an enumerated attribute deciding what technique should be used to search for elements in the current browsing context. The following table of location strategies lists the keywords and states defined for this attribute:
State Keyword CSS selector "css selector" Link text selector "link text" Partial link text selector "partial link text" Tag name "tag name" XPath selector "xpath"
しかし、WebdriverIO ではその指定ができないようである。 どうやら Sizzle みたいな既存の一般的なセレクタライブラリに近くなるように内部的に使い分けしてくれてるっぽい。
The JsonWireProtocol provides several strategies to query an element. WebdriverIO simplifies these to make it more familiar with the common existing selector libraries like Sizzle.
WebdriverIO - Selectors
具体的にどういうセレクタを書けるのかは WebdriverIO の Selectors のドキュメントに書かれている。
id セレクタを使用しようとする問題
セレクタの話でいうと、geckodriver に対して await session.setValue('#search_form_input_homepage', 'WebdriverIO')
を実行すると以下のようなエラーが返ってくる。
Error: Unknown locator strategy id
WebDriver には id lacator strategy というものはなく、geckodriver には実装されていないのだが、WebdriverIO は id locator strategy を使おうとしてこのエラーが出るようになっているらしい。 回避方法としては 「*#foo」 みたいな感じで ID 以外の条件も含めると良い模様。
WebdriverIO の Issue にもなっているが、「We can't remove the id selector just yet as it is still supported my many other drivers (also on mobile)」 って言って閉じられてる。 CSS セレクタがサポートされてる環境なのなら普通に移行できると思うのだけど、CSS セレクタがサポートされてない環境があるってことなのだろうか……。 (わからん。)
おわり
というわけで私がハマった WebdriverIO の罠でした。 多分ここら辺にハマっておけば後はいい感じに使えるはず。
それでは、よき自動化人生を!
読んだ : 最高のリーダー、マネジャーがいつも考えているたったひとつのこと
ラインマネージャに任用されたのでマネジメント系の本を読んだりしてる。 これは社長おすすめの一冊。
最高のリーダー、マネジャーがいつも考えているたったひとつのこと
- 作者: マーカスバッキンガム,Marcus Buckingham,加賀山卓朗
- 出版社/メーカー: 日本経済新聞社
- 発売日: 2006/01/01
- メディア: 単行本
- 購入: 34人 クリック: 421回
- この商品を含むブログ (190件) を見る
本書では、「マネジメント」、「リーダーシップ」、「個人の継続的な成功」 の 3 つの主題について、それぞれ最も重要なことは何かということが述べられる。 実際にマネージャとして仕事をしていくうえでは学ぶべきこと、知っておくべきことはいろいろあるけれど、根幹となる考え方として本書の内容は非常に明確でわかりやすく、実際に有用であると感じた。
読書メモ
組織の成功について
本書の第 1 部では、組織の継続的な成功について、マネージャとリーダーの違いと、それぞれで大切なたったひとつのことが述べられる。
マネージャについては以下のようなことである。
- 部下の才能を業績に結びつけるいちばんの方法を見つけ出すことが、優れたマネージャの仕事。
- ひとりひとりの強みや弱み、特色を見いだし、有効に活用すること。 ときには仕事の方をメンバーに合わせて変更する。
- 部下のために働く。 部下にとっての目標を出発点にして、そこから企業の目標に結びつけることを考える。
- 成長を手助けすること。 自社でのキャリアだけでなく、本人にとって最も良い道を探す手助けをする。
- ひとりひとりの特色を見いだす。 そのための質問例。
- 強みや弱み : 最近仕事が楽しかったのや辛かったのはいつか。 何をしていたときで、それは何故か。
- 引き金 (動機づけ?) について : これまで一番うまくいったマネージャとの関係は? なぜ? いままでに承認を得た中で一番心に残っているのは? それはなぜ?
- 独自の学習スタイル : これまでの仕事で一番多くを学んでいると思ったのはいつか? なぜ? 一番の学習スタイルはどういうもの?
ひとりひとりの 「人」 を見る、ということをすごく重要視している。 個人的にはあまり得意ではない部分なので、意識してやっていきたい。
会社のミッションと個人のミッションをすり合わせるという話については 『ALLIANCE』 が非常に参考になる。
ALLIANCE アライアンス―――人と企業が信頼で結ばれる新しい雇用
- 作者: リード・ホフマン;ベン・カスノーカ;クリス・イェ,篠田真貴子;倉田幸信
- 出版社/メーカー: ダイヤモンド社
- 発売日: 2015/07/10
- メディア: 単行本
- この商品を含むブログ (2件) を見る
リーダーについては以下。
- すぐれたリーダーは、よりよい未来に向けて人々を一致団結させる。
- そのためにたった一つの大事なことは、普遍的なことを発見して、それを活用すること。
- 未来を明確に示し、不安を取り除く。
- リーダーシップの 3 つの規律。
- 考える時間を作る : 未来を明確に示すためには熟考して結論を出す必要がある。 多忙な中でも時間を割いて熟考する。
- ヒーローを慎重に選ぶ : 未来に向けてとるべき行動を示すために、ヒーローを選ぶ。 (この人のこういう行動が未来に向けて良い、ということを示す。)
- 練習する : 伝えるための言葉やイメージ、ストーリーを練習する。 同じ言葉を何度繰り返しても繰り返しすぎだと思わないこと。 自分が繰り返しに飽き始めるころにやっと相手の心に届く。
目指す先を明確にするというのは非常に大事だと思う。 事業のビジョンを明確に打ち出すというのも、そのひとつなのだと思う。
意識はしていてもなかなか難しいことではあるが、マネージャとしては最初にこの 2 つの 「たったひとつのこと」 を大事にしていくと良さそう。
個人の成功について
第 2 部では、個人の継続的な成功について語られる。 本書では、個人の継続的な成功を 「可能な限り大きな影響を最も長い期間与えること」 とおいている。
- 個人が継続的に成功するために大切なたったひとつのことは、自分がしたくないことを見つけ出し、それをやめること。
- 正しい戦術を見つけ、それを活用するだけではありきたりな存在になる。 自分の個性をいかすこと。
- 弱みを克服することは重要ではない。 人が最も多くを学び、やりがいを感じるのは強みの分野。
- 強みを見つけ、それを伸ばすことは、必要ではあるがそれが最も重要なことではない。 強みを活かしつつも他のやりたくない仕事が多量にあると継続的な成功は難しい。
- 自分がしたくないことをやめるための戦術 : 役割をやめる、役割を微調整する、正しいパートナーを探す、役割の中で自身の力を引き出す側面を見いだす
- チームに対して、そして未来に対して最高の貢献ができるように軌道修正を行うのは、常に自身の責任である。
感想
組織で仕事をしていくうえで、本書に書かれている内容はいずれも重要であると感じた。 マネジメント研修でも、「仕事の側面に注目しがちだけど、人の側面も大事」 ということや 「仕事のサイクルの中で一番大事なのは計画で、目的を明確にしてそれを伝える必要がある」 というようなことを言われたのだけど、本書に書かれてる内容を踏まえてそういう話を聞くと納得感も高かった。
個人の成功についての話も大事な話で、「強みを伸ばす」 というのも一つの大事なことではあるけれど、強みとやりたいことが違う場合もあるし、強みを伸ばしながらも他の作業に忙殺される状況もあるし、そういったもろもろを避けるために 「やらないことを決めて、それをしないようにする」 というのをやっていこう。