言いたいことはそれだけか

KotlinとかAndroidとかが好きです。調べたことをメモします。٩( 'ω' )و

最近読んだジェンダー関連の本まとめ

はじめに

最近読んだジェンダー関連の本のメモ。

一般的なトピック

これは教科書とか研究をまとめたものではなくて、大学生がゼミで調べたことや話し合ったことをまとめたもの。ざっとジェンダー周りのトピックに目を通すのにいいと思う。一橋大学のゼミらしいが本の中で一橋大学アウティング事件にもふれられていた。

本書はジェンダーに限定した本ではなく、ステレオタイプ全般にまつわる脅威を対象としているがとても面白かったので紹介する。私たちはステレオタイプとして見ることも見られることからも逃れられない。しかしどういった影響があるかを学ぶことが対応への第1歩となると思う。

感想は以下のスレッドを参照。

女性を中心としたトピック

邦題がちょっと恥ずかしい感じなので本屋でレジに持っていくのが躊躇われるかもしれないが、内容はとてもよかった。

感想は以下のスレッドを参照。(めちゃめちゃ長いです)

この本についてはゲストとして呼んでもらったPodcastでも少し話した。

anchor.fm

プログラミングで世界を変えたアメリカの女の子二人の実話。プログラミングを学んできた元女の子としては共感する部分も多かった。

ジェンダー関連の実験を紹介しつつ、どうやって格差を克服していくかについての本。中でも興味深かったのはインドで実際に行われた社会実験。憲法で農村の議員の1/3を女性枠とし、さらに選挙毎に全国すべての村の3分の1を無作為抽出し議長になれるのを女性に限定した。日本だったら絶対にできないような実験なんだけど、結果も興味深いのでぜひ読んでみてほしい。

感想は以下のスレッドを参照。(めちゃめちゃ長いです)

男性を中心としたトピック

育児という場においては母親である自分はマジョリティに属しているのだが、マイノリティである父親の立場や考え方、バックグラウンドについて知りたかったので読んだ。もちろん人それぞれ考え方や事情は違うとは思うが、社会的な事情や男性の考え方の傾向など大変参考になった。

以下感想文スレ

おまけ:これから読もうと思っている本

Pending Intentのrequest codeは注意が必要(PendingIntentの仕組み)

Notificationに設定するaction buttonで使うPending Intentについて、よくわかってなかった部分があったのでメモ。

現象

Notificationにactionを設定する際、Pending Intentを渡す必要があるが、複数のPending Intentで同じrequest codeを使いまわしていたらintentが上書きされるという現象がおきた。上書きされたintentは起動先activityは同じクラスだが、extraに異なるものを設定していた。

例えば、下記のようなpending intentをそれぞれactionに登録したとして、

val requestCode = 0

// 同じrequest code
val intentFoo = getIntentFoo()
val pendingIntentFoo = PendingIntent.getActivity(this, requestCode, intentFoo, PendingIntent.FLAG_UPDATE_CURRENT)

val intentBar = getIntentBar()
val pendingIntentBar = PendingIntent.getActivity(this, requestCode, intentBar, PendingIntent.FLAG_UPDATE_CURRENT)

val notification = Notification.Builder(this, channelId)
            // いろいろ省略
            .addAction(Notification.Action.Builder(icon, getString(R.string.foo), pendingIntentFoo).build())
            .addAction(Notification.Action.Builder(icon, getString(R.string.bar), pendingIntentBar).build())
            .build()

これでfooの方のbuttonを押下した場合でも、起動先のactivityで取得されるのはintentBarだった。

公式のdocによると、

If you truly need multiple distinct PendingIntent objects active at the same time (such as to use as two notifications that are both shown at the same time), then you will need to ensure there is something that is different about them to associate them with different PendingIntents. This may be any of the Intent attributes considered by Intent.filterEquals, or different request code integers supplied to getActivity(Context, int, Intent, int), getActivities(Context, int, Intent[], int), getBroadcast(Context, int, Intent, int), or getService(Context, int, Intent, int).

とのことだったので、複数の異なるpending intentを同時に使いたい時はrequest codeを分ける必要があった。

Frameworkのコードを読む

上記のコードはPendingIntentを生成するときにPendingIntent#getActivity()を利用している。この getActivity()は内部でActivityManager#getIntentSender()をコールしている。

    public static PendingIntent getActivity(Context context, int requestCode,
            @NonNull Intent intent, @Flags int flags, @Nullable Bundle options) {
        String packageName = context.getPackageName();
        String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                context.getContentResolver()) : null;
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(context);
            IIntentSender target =
                ActivityManager.getService().getIntentSender(
                    ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
                    null, null, requestCode, new Intent[] { intent },
                    resolvedType != null ? new String[] { resolvedType } : null,
                    flags, options, context.getUserId());
            return target != null ? new PendingIntent(target) : null;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

ここからActivityManagerService経由でPendingIntentController#getIntentSender()が呼ばれる。

    public PendingIntentRecord getIntentSender(int type, String packageName,
            @Nullable String featureId, int callingUid, int userId, IBinder token, String resultWho,
            int requestCode, Intent[] intents, String[] resolvedTypes, int flags, Bundle bOptions) {
        synchronized (mLock) {

// いろいろ省略

            PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, featureId,
                    token, resultWho, requestCode, intents, resolvedTypes, flags,
                    SafeActivityOptions.fromBundle(bOptions), userId);
            WeakReference<PendingIntentRecord> ref;
            ref = mIntentSenderRecords.get(key);

ポイントはPendingIntentRecord.Keyを使ってIntentSenderRecordを取得していること。Key#equals()を見るとここでrequest codeが使われている。

        @Override
        public boolean equals(Object otherObj) {
            if (otherObj == null) {
                return false;
            }
            try {
                Key other = (Key)otherObj;
                if (type != other.type) {
                    return false;
                }
                if (userId != other.userId){
                    return false;
                }
                if (!Objects.equals(packageName, other.packageName)) {
                    return false;
                }
                if (!Objects.equals(featureId, other.featureId)) {
                    return false;
                }
                if (activity != other.activity) {
                    return false;
                }
                if (!Objects.equals(who, other.who)) {
                    return false;
                }
                if (requestCode != other.requestCode) {
                    return false;
                }
                if (requestIntent != other.requestIntent) {
                    if (requestIntent != null) {
                        if (!requestIntent.filterEquals(other.requestIntent)) {
                            return false;
                        }
                    } else if (other.requestIntent != null) {
                        return false;
                    }
                }
                if (!Objects.equals(requestResolvedType, other.requestResolvedType)) {
                    return false;
                }
                if (flags != other.flags) {
                    return false;
                }
                return true;
            } catch (ClassCastException e) {
            }
            return false;
        }

Package nameが同じ場合、起動先のintentのfilterEquals()が一致してrequest codeも同じだった場合は同様のものとみなされる。(公式docでfilterEquals()でもできるよって書いてあるのは、ここの条件のことっぽい。)

    public boolean filterEquals(Intent other) {
        if (other == null) {
            return false;
        }
        if (!Objects.equals(this.mAction, other.mAction)) return false;
        if (!Objects.equals(this.mData, other.mData)) return false;
        if (!Objects.equals(this.mType, other.mType)) return false;
        if (!Objects.equals(this.mIdentifier, other.mIdentifier)) return false;
        if (!(this.hasPackageEquivalentComponent() && other.hasPackageEquivalentComponent())
                && !Objects.equals(this.mPackage, other.mPackage)) {
            return false;
        }
        if (!Objects.equals(this.mComponent, other.mComponent)) return false;
        if (!Objects.equals(this.mCategories, other.mCategories)) return false;

        return true;
    }

そしてfilterEquals()はextraを見ていない。

さらに同じkeyだとみなされた場合はextraを上書きしている。

    public PendingIntentRecord getIntentSender(int type, String packageName,
            @Nullable String featureId, int callingUid, int userId, IBinder token, String resultWho,
            int requestCode, Intent[] intents, String[] resolvedTypes, int flags, Bundle bOptions) {
        synchronized (mLock) {

// いろいろ省略

            PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, featureId,
                    token, resultWho, requestCode, intents, resolvedTypes, flags,
                    SafeActivityOptions.fromBundle(bOptions), userId);
            WeakReference<PendingIntentRecord> ref;
            ref = mIntentSenderRecords.get(key);
            PendingIntentRecord rec = ref != null ? ref.get() : null;
            if (rec != null) {
                if (!cancelCurrent) {
                    if (updateCurrent) {
                        if (rec.key.requestIntent != null) {
                            rec.key.requestIntent.replaceExtras(intents != null ?
                                    intents[intents.length - 1] : null);
                        }

Intent#replaceExtras()の中身はこんな感じ。コメントにある通り、本当にまるっと入れ替えている。

    /**
     * Completely replace the extras in the Intent with the extras in the
     * given Intent.
     *
     * @param src The exact extras contained in this Intent are copied
     * into the target intent, replacing any that were previously there.
     */
    public @NonNull Intent replaceExtras(@NonNull Intent src) {
        mExtras = src.mExtras != null ? new Bundle(src.mExtras) : null;
        return this;
    }

というわけで、extraだけ異なるintentでrequest codeを使いまわした場合は上書きされる。

おまけ:Notificationのactionがタップされた時のコード

addaAction() されたボタンの実態はRemoteViewである。こいつがNotificationに表示されるときにclick handlerが設定される。

RemoveView ※懐かしのAsyncTask

       @Override
        protected void onPostExecute(ViewTree viewTree) {

// 前後は省略
                try {
                    if (mActions != null) {
                        OnClickHandler handler = mHandler == null
                                ? DEFAULT_ON_CLICK_HANDLER : mHandler;
                        for (Action a : mActions) {
                            a.apply(viewTree.mRoot, mParent, handler);
                        }
                    }
                } catch (Exception e) {
                    mError = e;
                }
            }

実際にユーザがactionをclickした際にはRemoteView#handleViewClick()が呼ばれる。ここからいろいろ経由してNotificationRemoteInputManagerが持っているmOnClickHandlerでpending intentが使われる。

    private final RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {

        @Override
        public boolean onClickHandler(
                View view, PendingIntent pendingIntent, RemoteViews.RemoteResponse response) {
            mShadeController.get().wakeUpIfDozing(SystemClock.uptimeMillis(), view,
                    "NOTIFICATION_CLICK");

            if (handleRemoteInput(view, pendingIntent)) {
                return true;
            }

            if (DEBUG) {
                Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent);
            }
            logActionClick(view, pendingIntent);
            // The intent we are sending is for the application, which
            // won't have permission to immediately start an activity after
            // the user switches to home.  We know it is safe to do at this
            // point, so make sure new activity switches are now allowed.
            try {
                ActivityManager.getService().resumeAppSwitches();
            } catch (RemoteException e) {
            }
            return mCallback.handleRemoteViewClick(view, pendingIntent, () -> {
                Pair<Intent, ActivityOptions> options = response.getLaunchOptions(view);
                options.second.setLaunchWindowingMode(
                        WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
                return RemoteViews.startPendingIntent(view, pendingIntent, options);
            });
        }

またRemoteViewに帰ってくる

    /** @hide */
    public static boolean startPendingIntent(View view, PendingIntent pendingIntent,
            Pair<Intent, ActivityOptions> options) {
        try {
            // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
            Context context = view.getContext();
            // The NEW_TASK flags are applied through the activity options and not as a part of
            // the call to startIntentSender() to ensure that they are consistently applied to
            // both mutable and immutable PendingIntents.
            context.startIntentSender(
                    pendingIntent.getIntentSender(), options.first,
                    0, 0, 0, options.second.toBundle());
        } catch (IntentSender.SendIntentException e) {
            Log.e(LOG_TAG, "Cannot send pending intent: ", e);
            return false;
        } catch (Exception e) {
            Log.e(LOG_TAG, "Cannot send pending intent due to unknown exception: ", e);
            return false;
        }
        return true;
    }

ここで、上で見てきたIntentSenderを取得してstartするコードになっていた。

言いたいことは以上です。

WorkManager.getInstance()に渡すContext

ちょっと気になったので調べたメモ。
Titleの通りWorkManager#getInstance()の引数のcontext1は何を渡すべきなのか、また何に使われるのか気になった。

developer.android.com

上記のAPI documentには

Context: A Context for on-demand initialization.

としか書いていない。よくわからない。これはapplication contextを渡すべき?それともactitivity? 複数の箇所でWorkManagerのinstanceを取得する場合、渡すcontextによって動作に差が出るか?など気になるポイントがいくつかある。

で、いつものようにコードを読む。まずWorkManager#getInstance()を読むと、Impl classを呼び出しているだけだとわかる。

   public static @NonNull WorkManager getInstance(@NonNull Context context) {
        return WorkManagerImpl.getInstance(context);
    }

Impl classを見にいく。

    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static @NonNull WorkManagerImpl getInstance(@NonNull Context context) {
        synchronized (sLock) {
            WorkManagerImpl instance = getInstance();
            if (instance == null) {
                Context appContext = context.getApplicationContext();
                if (appContext instanceof Configuration.Provider) {
                    initialize(
                            appContext,
                            ((Configuration.Provider) appContext).getWorkManagerConfiguration());
                    instance = getInstance(appContext);
                } else {
                    throw new IllegalStateException("WorkManager is not initialized properly.  You "
                            + "have explicitly disabled WorkManagerInitializer in your manifest, "
                            + "have not manually called WorkManager#initialize at this point, and "
                            + "your Application does not implement Configuration.Provider.");
                }
            }

            return instance;
        }
    }

こんな感じで実際は引数として渡されたcontextから getApplicationContext() を呼んでそちらを使っているので、特に渡すcontextは気にしなくて良いことがわかる。


  1. 引数なしの同名methodも存在するがdeprecatedである。

「チームで育てるAndroidアプリ設計」を読んだ

[PR] 献本いただいた1「チームで育てるAndroidアプリ設計」を読んだので感想文です。

peaks.cc

全体を通して

本書は大まかに前後半に分かれていて、前半は新規開発について、後半は大規模チーム開発について、それぞれAndroidアプリ設計の勘所について述べている。よって、すでにAndroidエンジニアとして働いている人であれば大体どちらかは経験があるだろうし2、これからAndroidエンジニアとして働く人にとっては事前に勘所が予習できるので大きな価値があると思う。つまり対象読者がとても広い。Android開発に興味がある人だったら何かしらの共感もしくは知見が得られると思う。

以下、面白かった部分について書いていくが、普通に全部読んで欲しいのでほんの一部だけ紹介する。

前半パート:新規開発について

MVVMとだけ決めたチームの例 (p.4)

本パートでは実際に開発を始める前に設計することの重要性を繰り返し述べている。一例として「全くアーキテクチャを決めずに開発に走り出してしまったケース」と「MVVMとだけ決めたケース」を比較しているが、実は後者もなかなかヤバくて、徐々におかしなことになっていく様子がめちゃめちゃリアルで読んでいてニヤニヤが止まらない。これは「3.3.2 統一性が崩れる時」(p.57) とも関連していて、「何世代も書き方が存在する時、どれが最新なのかわからない問題」はある程度の開発期間を重ねたrepositoryあるあるではないだろうか。

アーキテクチャの選定と背景 (p.13)

実際にどういったアーキテクチャを選定するかの実例とその理由が豊富で読んでいて楽しい。特に多層アーキテクチャでどう言ったアプリは何層にするのがおすすめか指針が書いてあるので、分け方に迷っている人はとりあえず読んで試してみるのが良いと思う。

より多くのチームへ (p.61)

第4章では自分たちのチームでうまくいった知見を、全社に展開することの重要性といいやり方について説明している。話が少しずれるが、最近ジェンダー研究の本をよく読んでいて、こう言った自チームを超える動きは女性が比較的苦手な傾向があるらしい。3

自分もやれと言われない限り積極的にこういうムーブできてないなと反省した。やっていきます。はい。

後半パート:大規模チーム開発について

合意をとってやっていくことの重要さと難しさ

後半パートでは大規模チーム開発について語られるが、「大規模開発でも新規開発と同じくチーム内でアーキテクチャ命名規則などの合意をとってから前進していく」(p.87)とあるように、できれば前半を読んでから後半を読んだ方が理解が深まって楽しいと思う。合意をとってやっていくのは新規開発と同じだが、大規模チーム開発では合意をとるべき人数が多く、全員の目線を合わせるだけでも本当に大変。一つのプロダクトでAndroidエンジニアだけで数十人超えるような大規模チームだとどうやってるんだろうと思わずにいられない。やっていきましょう。

大規模チームのアーキテクチャ: モジュラーモノリスの例(p.99)

著者の経験を踏まえ、どう言った状況でどのようなアーキテクチャを採用したのかステップバイステップで説明されているのでわかりやすい。ただ、この例では割とメインストリームから外れた技術が採用されていて(それについては別の章でもふれられている)そのまま真似をすれば良いというわけではなく、あくまで考え方の参考に留めるべきだが参考になる。
突然GoF本のFacadeパターンが出てきて思ったが、やはり大規模なアプリの設計を考える人は引き出しをちゃんと持ってるんだなー。GoF本は前職でみんなで読書会(みんなで本を読んで1パターンずつ担当を決めてそのパターンで小さいプログラムを実装する)をやったのだが楽しかったので一人で挫折しちゃった人にはこの方法がおすすめ。

オンボーディングの知見(p.91)

人数が多くなるとそれだけ人の入れ替わりが頻繁に発生する。在籍年数を2年と仮定して、24人チームメンバーがいた場合は毎月誰かがやめていくという計算は思わず笑ってしまった。実際は人が辞めやすい時期が偏っている気がするが、人が頻繁に入れ替わっていくというのはまさにそうなのでオンボーディングを整備していこう。この箇所は組織が急拡大するフェーズのベンチャーで頑張っている人にも参考になると思う。オンボーディング具体的に何すればいいかの知見ってそういえばあまり明文化されていない気がするので貴重かもしれない。

最後に

著者の釘宮さん、横幕くん、編集のひつじさん、お疲れ様でした!


  1. 献本いただいたが、実は元々peaksでポチっていたので普通にお金は払っていますw

  2. 読んでて「わかる〜〜〜」「それな〜〜〜〜〜〜」ってめちゃめちゃ心の中で言ってた

  3. 邦題はアレですが、中身は面白いのでおすすめです https://www.amazon.co.jp/dp/B07N65TC1S/

Kotlin 1.4からFlowのcombine()がより綺麗に書けるようになった(suspend conversion on callable references)

今回は小ネタ。Kotlinがますます可愛いという話をします。

Kotlin 1.4からsuspend conversion on callable referencesがsupportされました。

(^ もう数ヶ月も前のtweet...)

リリースノートではさらっと

In addition to suspend conversion on lambdas, Kotlin now supports suspend conversion on callable references starting from version 1.4.0.

としか書かれていないのであまり気に留めた人もいないんじゃないかなと思いますが、これによってKotlin coroutineの Flow#combine() がより綺麗に書けるケースがあります。

例えば、二つのflowをcombineして、それをそのまま collect に渡したい場合、1.4より前ではこのような書き方ができませんでした。

suspend fun foo() {
    combine(
        flowA, flowB, ::Pair
    ).collect { (a: Int, b: Int) ->
        println("$a and $b")
    }
}

val flowA = flowOf(1, 2)
val flowB = flowOf(3, 4)

1.4より前だと上記のコードはコンパイルエラーになります。combine()の第3引数はsuspend function lamdbaなので、suspendじゃないPiarクラスのコンストラクタは受け付けてもらえません。1.4からはsuspendに自動で変換してくれるようになったので、上記のコードは問題なく動きます。

ちなみに、collect()の引数のlambdaの引数(a: Int, b: Int)destructuring declarationsを使っていて、いちいちPairのfirst/secondに名前を付け直したりしなくてもここでabといった名前をつけられます。可愛い。

a, bの後ろの型の明示は省略可能ですが、destructuring declarationsを使っているので()はないと動きません。

    combine(
        flowA, flowB, ::Pair
    ).collect { (a, b) -> // OK
        println("$a and $b")
    }
    combine(
        flowA, flowB, ::Pair
    ).collect { a: Int, b: Int -> // NG (コンパイルエラー)
        println("$a and $b")
    }

1.4より前はどういうコードを書いていたか参考までに残しておきます。やはり少し冗長に見えます。

suspend fun fooBefore4_1() {
    combine(
        flowA, flowB
    ) { a, b ->
        a to b
    }.collect {
        val a = it.first
        val b = it.second
        println("$a and $b")
    }
}

val flowA = flowOf(1, 2)
val flowB = flowOf(3, 4)

言いたいことは以上です。

私が出会った最高のEMたち

[2020.12.8 追記]
ブコメでEMが何かわからないと書かれていたので補足。EM = Engineering Managerです。EM菌ではありません!!!
[追記ここまで]

今の会社でお世話になったEMの人たちのマネジメントがとてもよかったので育休で全てを忘れる前にメモを残す。EMの話題はよく見かけるけれど、マネジメントされる側の視点で語られることがあまりなかった気がするのでいい記録になるかもしれない。

前提

  • 自分: メンバー(マネジメントされる側)。Androidエンジニア。ある程度放置されても自走できる。
  • EM: 一人ではなく複数。(歴代という意味。同時に複数人のEMにマネジメントされたという意味ではない。)彼らはみなAndroidエンジニアではないがモバイルもしくはフロントエンドのエンジニア。なので技術の相談はしないが、開発業務そのものについてはとても詳しい。
  • 組織: エンジニアリング組織がある程度きっちり作られているので、レポートラインも明確だし評価の基準も明確。OKRで目標を管理する。

ここがよかった!マネジメントポイント

認識を最初に合わせる

マネジメントで個人的に一番重要だと思っているのは、(1)期待値を共有して (2)目標を合意し (3)目標が達成できたか一緒に振り返る(=評価) のサイクルがちゃんと回っていることだと思う。1
(1)の期待値を共有する前に、まずマネジメントされる側(私)がどういうタイプで何を重視しているか聞いてもらえたのが面白いなと思った。確かに、「会社ではそこそこのお給料もらって残業せずに趣味のOSS活動に時間と脳のリソースを割きたい」というタイプの人に「こうすれば昇進できるからもっと頑張ろう!こういう目標どう!?!?」みたいな話しても全く響かないと思う。ちなみに自分は普通に昇進してお給料上げたいタイプ。今の自分がこういうタイプです、という前提を共有して(1)、じゃあ今後どういうキャリアに進みたいか?そのために今期はこういう目標にしましょうという合意をする(2)。(2)で決めた目標は定期的な1on1で二人でチェック。ヤバそうだったら相談し、期末の評価時に決定的な手遅れな状態になるのを防ぐ。2 この1on1も、何のためにやるのか(目標の進捗チェック?それともただの雑談?)を最初に共有するのが大事。ある程度放っておかれてもそれなりに仕事をこなせる人にもちゃんと定期的に時間をかけてくれるのはありがたかった。3
また、1on1ではマネジメントされる側の話を一方的にするのではなく、マネジメントするがわが今どういう状況なのかシェアしてくれるのもよかった。

相談した時のアクションがめちゃ早い

1on1で「これもしかしたら後々問題になるかも」とぽろっと言ったことに対し、数時間後には関係者に連絡がとられ会議が設定され、そのままいい感じに解決されたことがあって本当にすごいと思った。相談した時のアクションが素早いと信頼貯金が爆上がりするし次も相談しようという気になる。次も相談したくなるというのは大事なポイントだと思っていて、「この人に何言ってもしょうがないな…」と思われたらマネジメント関係が成り立たなくなり相互に不幸である。

叱る時のポイント

マネージャーは何かをやらかしたメンバーを叱る必要がある。よく言われる事だが、みんなの前ではなく会議室に呼び出されて注意されたのは注意される側としてよかった。叱るときも「今回は初めてだからいいよ。誰でも失敗するから。でも次からはダメだよ」と仏のような注意だった😇

キャリアアップを手伝ってくれる

「一つ上のレベルに昇進させたいんだけど、ボードメンバーを説得するにはhogehogeの経験がないと厳しい…そういうわけでこのプロジェクトやってみない?」その後本当にレベルが上がって最高オブ最高でした。ありがとうございました。

信頼貯金を失うことをしない

私は初対面の人のことを基本的にいい人だと思っているので、その人が(私にとって)残念なことをしない限りは信頼貯金が失われることはない。信頼貯金を失うような行動というのは人によると思うが、一般的に「約束をちゃんと守る」「人を傷つけるような行動はしない」「自分の職務は責任を持って行う」など人として当たり前のことを守っていれば大丈夫じゃないかなと思っている。当たり前と書いたが、この当たり前を当たり前に実行できる人は意外と少ないのではないかなと思う。

マネジメントされる側としてやるといいこと

ドキュメントを用意する

話したいトピックを1on1までに事前にドキュメントに書いておく。箇条書きレベルで良い。1on1ではそのドキュメントをお互い見ながら話をする。Google docsなどリアルタイムで共同編集できる物があると良い。話しながらアドバイスやNext action、追加で話した話題などを書き込んでいくとそのまま議事録になるし、書かれたことが意図と違うとそこで気がつけるのであとで困ったことにならないで済む。この議事録は期末の自己評価の際にも使えるので便利。

自分からアラートがあげられる

当たり前だけど、困ったことが起きたときは自分からちゃんとアラートをあげられることが大事。定期的な1on1の予定がずっと先で、このままでは手遅れになりそうだったらちゃんとEMを捕まえて報告・相談する。上記の「認識を最初に合わせる」でも書いたが、ここで「EMがどれくらい忙しそうか?」「今EMがやっている仕事内容よりも優先的に聞いてもらうべき内容か?」を判断するために日頃からEMが今何をやっていてどれくらい忙しいかを把握しておいた方がいい。

おまけ:1on1のときにいつも聞いていたこと

  • 「私が知っておくべきことは何かありますか?」
    • 自分が関わる他チームの動向なんかを教えてもらえることがある
  • 「今何に忙しいですか?」
    • 上で書いた通り

言いたいことは以上です。


  1. あくまでマネジメントするのであればという前提の話。初期フェーズのベンチャーでは期毎の目標とか決めてもすぐに状況が変わったりするので、とにかく前に進めることが最重要でマネジメントとかしないんじゃないかなと妄想しています。初期のベンチャーで働いたことないので妄想です。

  2. 個人的に期末で「あの時のあれがアレだったので評価据え置き」「本当はあの時ああして欲しかったんだよね」みたいな事言われるの、結構モチベーション削られる。

  3. 手をかけないといけない人に手をかけるのは必要だが、実は手をかけなくても大丈夫な人にこそもっと伸びてもらうために手をかけるべきという説がこの本で紹介されていて面白かった。

産休・育休中に読んで良かった本のまとめ

はじめに

産休・育休中に読んで良かった本を周囲の方々に教えてもらったので読んで良かったもののメモ。オススメしてもらった量がすごいので、特に自分の興味にあっているものや実際の育児に役立った(子どもの個性に合ったor親のライフスタイルに合った)物を選んで書いていく。

実用的なやつ

ネントレ本

賛否両論ある(?)ジーナ本、うちの子には合っているようでやって良かった。生活リズムが早いうちから整ったことで家族全員が楽になった。あと1日のスケジュールが細かく決まっているのが逆に助かった。子育て中は意思決定に脳のリソースがかなり持っていかれる実感があるので、「あと1時間でミルク」「これが終わったらお風呂」などタスクを誰かに決めてもらうのが精神的に楽だった。

発達全般

細かい月齢ごとに何ができるようになる・どんなことに気をつけるかが書いてあるので非常に参考になった。月齢が上がるたびに見返している。

離乳食

これを読んで主食はライスシリアルにしたけど、その他は今のところ手作りしている。うちの子はブレンダーの音が怖いらしくマジ泣きするのでBaby Brezzaを買ってかなり助かった。

産後すれ違い対策

もしこれを読んでいるあなたが「今妊娠中で最高に幸せでハッピーな子育てライフが待っているはず!」という人であればここから先は読まない方がいいかもしれない。(私はビビリなので妊娠中にこの手の本をたくさん読んだが、今のところ夫との関係は変わらず良好である。)

産後クライシス

(009)産後クライシス (ポプラ新書)

(009)産後クライシス (ポプラ新書)

第1章から衝撃的なデータに横っ面を殴られる。そのデータとは、「配偶者といると本当に愛していると実感する」と答えた人の割合が男女でかなり差が出る。2歳時期になると夫が51.7%に対して妻が34.0%...ちなみに妊娠期は夫も妻も同じ74.3%なので2年間に何が起こったのか想像すると恐ろしくなる。こうした事態を避けるために妻向け・夫向けにそれぞれアドバイスが書かれていた。これだけ見ると夫を責める方向に向かうように見えるかもしれないが、実際は今の日本の社会システムのせいでで夫が育児参加したくてもできないなどの問題点が指摘されていて妻側の啓蒙にも良いと思う。

ふたりは同時に親になる

先ほどの「産後クライシス」よりも若干マイルドな気がする。一番記憶に残ったのは挿絵で、妻が赤ちゃんを背負って崖にぶら下がっているところを「(仕事で)俺無理だから家事代行頼めば?」と言って立ち去り家事代行の人と母が妻を引っ張り上げている絵(NGケース)と、「みんなを連れて助けに来たぞ!」と言って家事代行の人と母と一緒に妻を引っ張り上げる男性の絵(OKケース)。文字で説明するのが難しいので何言ってんだって感じだと思うけど、この絵を見たときにとても腹落ちした。

その他の感想はtweetのツリーをどうぞ

科学的な読み物

ここからは完全に趣味の話です。

ヒトの発達の謎を解く

赤ちゃんが大きくなる時に脳の中で何が起こっているのか?読んでいると「人間、よくこんなので社会を維持してるな…」って思える。内容が気になる方はこちらのツリーをどうぞ。

「家族の幸せ」の経済学

これは紹介してもらったのではなく、Kindleセールで見つけて面白そうだったのでポチったやつ。かなり良かった。社会学というか面白い統計データの紹介で、日本だとデータが少ないのか外国の事例が多かった。そのためどこまで日本社会に適用できるかわからないが普通に読んでて楽しかったのでおすすめ。 面白ポイントはこちらのツリーをどうぞ。

子どもは40000回質問する

これもKindleセールで買ったやつ。邦題が割とアレで、実際は子供にフォーカスした本ではなく、原題(Curious)の通り好奇心全般について書かれた本。なので育児本だと思って読み始めると肩透かしな可能性が高い。個人的には面白かったので興味がある人はこちらのツリーをどうぞ。

言いたいことは以上です。