ぽんぽんぺいんでつらたんなので、おしごとおやすみしまーす

🗣: バイクに乗ったり、ものづくりしたり、ひたすら寝たり。

お前の会話にはコミュ力が足りない

コミュ力ってなに

ここでは相手と疎通できる共通認識がある状態の事を指す。

業務上で意見聴取出来るし、困った事はない。

程度にもよるけど、よそのエンジニアと話す際に浮き彫りになった事例を下記に記す。(*お前=筆者を指す)




自分「イケてると思っていたAndroidアプリに設計のダメ出しをされた」
某氏「お前はどこがイケてると思ったん」
自分「ViewModelとかLiveDataとか使ってるし、画像のキャッシュも考慮して…」
某氏「それって当たり前やん?」
自分「!?!?」


某氏「設計はどうしたら良かったと思う?」
自分「モジュールに切り分けて…APIを分割して…」
自分「アッあのライブラリ使えばよかったな…」

某氏「なんで?」
自分「MVVMっぽくない」
某氏「MVCでよくね?」


某氏「君はなぜにMVCとMVVMという設計手法があるんだと思う?」

自分「っえーー……」(カス)
自分「MVVMはガベージコレクションを考慮されたなんたらでえ…」

某氏「Railsはファットモデルが良しとされてるよね?
これはドメインに合わせてスケールが出来るようにという意図があるみたいだけど」

自分「あーそうみたいですね。自分はあまりいいとは思えないです」

某氏「え!?!?!?」


↑↑↑
自分:基底クラスを継承しているにも関わらず、改修が冗長的になった事例を思い浮かべている(悔しい記憶)
某氏:プロダクトに必要なものを具体化出来るDDD手法について思い浮かべている



某氏「ていうか今そういう観点で話してへんやん?」

自分「…」


(この後某氏による認識合わせの時間が入る)


個人的まとめ

絶望的に会話が噛み合わない

- なぜならお前の言葉の定義が薄っぺらいから

想像力が足りない

- この後の話題の展開まで想像できていない
- 思いついた言葉を舌に乗せている
- なんか感情が先行している気がする

コミュ力を上げる為に(小2の発想)

- みんなが読んでる本を読む
- エンジニアと話す
- お利口さんぶって細かい技術の話をしない。みんなが知ってる話題(概念的なの)を取り上げる。




思いついたら追記する。コミュ力は個人的に永遠のテーマだ…。

今更Vue + github pagesに触れてみる

デプロイの度に真っさらなページが出ていたので、まずはアセットを読み込んで表示するところまでやってみた。

冬に比べてだいぶ記事が出回っているので既出感あるが…。

自分の場合、ルートパスにvue.config.jsを置いておくのを忘れていて、こちらをgithub pagesのドメインと合わせるのを忘れていました。後、ビルド後のディレクトリをdocsにしたものの、プロジェクトの設定でそれを有効にしてなかった。

githubpages-deploy-settings

デプロイ自体は5分足らずで終わった印象。

jelly

ぼよんぼよ〜ん

こうやって無駄に動きをつけるのが好きです。
display: flex大好き人間なんですが、デフォルトのタグでv-flexなどが用意してあるのが良かった(小並感)

なんかコピペでそれっぽいのを作れてしまうので恐怖感はある。
デプロイ先はこちらです。



引用元:

Deployment | Vue CLI

Kotshi+MVVMをカジュアルに採用してみた。

GWも過ぎて、ハイテンションで迎えた令和もすでに鬱々とした気分で過ごす日々です。
今回はKotlinでアウトプットする機会があったので、便利ライブラリを簡単に紹介します。



ネイティブアプリケーション開発においては、バックエンド側のWeb-APIRailsなどで用意することが多く、Kotlinで開発するクライアント側はリクエストを送信し、レスポンスに乗っているJsonを整形することで表示するデータを取得します。


しかし、null許容を搭載しているKotlinにおいてはKotlinJsonAdapterFactoryなるものを追加しない場合に空のJsonをパースする際にぬるぽが発生したり、
Moshiなるアダプターを使用するもののリフレクションを搭載している為に解釈が遅いといった問題があります。


Jsonを解析する時の問題

まだこれらの利点を払拭するような実感は得ていませんが、今回はKotshiというライブラリを使用することにしました。

よくある画像とコメントをリスト形式でレスポンスするAPIを例に、下記のようなクラスを実装しています。


Response


{
params: {
total: 100, # 総レコード数
offset: 50, # オフセット
limit: 5 # リクエスト時指定の取得数
},
album_records: [
{
"image_url": "https://album-records.herokuapp.com/images/hoge.jpg",
"comment": "Hoge",
"tag": "programming",
"recorded_at": "2019-05-10 00:04:00"
},
{
"image_url": "https://album-records.herokuapp.com/images/fuga.jpg",
"comment": "Fuga",
"tag": "programming",
"recorded_at": "2019-05-10 10:12:50"
},
...

Client


// 実際にJsonを解析するアダプタークラス
@KotshiJsonAdapterFactory
data class Album(
@field:Json(name = "params") var params: GetDataParams,
@field:Json(name = "album_records") var albumRecords: List
) {

companion object {
val INSTANCE: AlbumRecord.Companion = AlbumRecord
@ToJson fun toJson(writer: JsonWriter, value: AlbumRecord, stringAdapter: JsonAdapter) {
stringAdapter.toJson(writer, value)
}
}
}

// 取得したいインナークラス(album_recordsの中身)
data class AlbumRecord(
val image_url: String?,
val comment: String,
@Json(name = "tag") val tag: String?,
val recorded_at: String?
)

// リクエスト時のパラメータ(今回は使わない部分)
@JsonSerializable
data class GetDataParams(
val total: String,
val offet: String,
val limit: String
)

// レスポンスを格納するViewModel
class AlbumRecordViewModel: ViewModel() {
val albumRecoLiveData = MediatorLiveData>()
}




@field:Json(name = "params") のように指定することで、Jsonを解析してくれる名前を与える事が出来、後置の名前でクラスのメンバとして振る舞います。
Kotlinのdata classはtoStringなどが備わっているので、パースで入り用の際にはデータを処理するメソッドを用意する手間を無くし、憂鬱な気持ちも軽減してくれます。


今回はリスト形式のオブジェクトが含まれていた為に、クラスを切り分けつつうまく解釈してくれるような構造にしました。不必要な部分については無視してくれる便利なアノテーションも存在しますが、下記のエラーに対応していて実装はしませんでした。


Exception in thread "main" java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 16 path $.response
https://stackoverflow.com/questions/41649731/gson-expected-a-string-but-was-begin-object
つまりはStringとして期待されたメンバはオブジェクトでやってきちゃったよ!
どうしろ言うんじゃい!!!

と言うKotlin(もといJava)様の叫びです。
これは上のようにparamsとalbum_recordを切り分けずにひとつのクラスで解析しようとしていたところ頻発して、メンバ宣言の位置変えをしてみてもうまくいきませんでした。


で、実際に解析をしたいメンバを連ねるだけではダメで。
companionに書かれている専用解析変数&メソッドが鍵となります。
解析したいクラスの情報を渡して、そこではどんな感じにパースすんのと言うメソッドもimplementします。(書かなければ@FromJsonか@ToJson実装しないとこれ使えへんでと言われる)


リクエストをどうするか問題

今回リクエストに使うライブラリはOkHttp3にしてみました。触った事なかったから。
こいつはGETする時にはパラメータを変えたいなと思った時に、インスタンスがイミュータブルなもので、もうひとつ新たなものを用意しないと調整ができないと言うものでした。

Web触っていた時にはerbさんが非同期でリクエスト取ってきてくれていたものだけど、今回扱ってるものは小さなパソコン、Androidなので極力パフォーマンスも考慮して実装していきたい。

そこで画面回転があろうとインスタンスを死守してくれるViewModelさんの力を借りました。

プライベートアプリなのであらかじめ全てのデータを取得して、適当にページングして少しずつ見せる感じに。画像の表示はPicassoを使ったのでスマートにキャッシュを持ってくれて、表示もサクサクです。



諸事情でデモやコードは上げてないですが、許可が取れたら上げてみます。
今回の反省点はと言うと、なんだかんだと困ったらすぐに検索してしまい、ライブラリのソースコードをきちんと読むことを疎かにしていたって事です。ライブラリもコードなの、ああそういえば昔参加してる勉強会でひたすらコードリーディングしてる人いたけど、あれが正なのかなあ…




(イケてる開発者のトレンドはまだまだ理解できないよ…)

基本情報技術者を受けてきた

お疲れさまです。今年の本命枠とも言える資格試験を受けてきましたが、惨敗の結果に終わりました。。

理由は明白で、午後試験の対策をぬかっていたところだと思います。
基本情報技術者(以下基本情報)は午前と午後科目に分かれており、両方の試験で6割以上を期待され、それを超えることによって初めて合格となります。

本年の講評的に、万遍なく計算問題などは出題されていたものの、ハードウェアやトリッキーな問題は出ず(回路もすごく無難なものが出た)、他年度に比べて平易だったと言います。。
自己採点では午前は6割を超える事が出来ましたが、午後は50%程度しか得点できず、悔しい結果となりました。

午後試験問題の反省点

ソフトウェア設計(WebAPI)、アルゴリズムでの大コケ

一番痛かったのは、認めたくはないですがWebAPIでの大コケです。

DB, WebAPIの仕様が羅列されており、これを要約した内容に解答したり、
機能実装の例に解答するような問題です。
絵を描いて関連を把握したのは悪くなかったとは思うのですが、実際に動作するところまでを冷静に想像する必要があったと思います。ただ前提の内容を真に受けるようではダメ…

1番最初の問題はとっても基本的な問いです。
認証関連WebAPIと、登録ツールからアクセスできる。よって、申し込みDBに格納されている情報は_________である。


ここは申込者IDと解答しましたが、正解は申込者情報と検査農産物情報なのでした。(5)検査管理システムに登録された検査結果を確認して、申込者に検査結果を報告する とあるので、検査農産物テーブルは中間テーブルの役割をしていたと考えられます。

申込者←→検査農産物←→検査結果情報

こんな感じで参照することができた。


アルゴリズムについては正直テンパりながら問題を読んでいたので、お絵かきと表が全然合わなくてさらにテンパっていた

後半に進むにつれて時間が全然足りなくて、焦りが次第に諦念に変わった感じだったな…

解答の順番はこんな感じでした。
(プログラミング)Java→情報セキュリティ→DB→ネットワーク→ソフトウェア→プロジェクトマネジメント→アルゴリズム


午後問題のよかった点

データベースとマネジメントはしっかりと得点できていた

といっても上記以外の基本的な問題の得点はしっかり得られていたと思います。
業務でも触った事があったLIKEや前提に解答が書いてあるものは簡単に感じました。(ギリギリで=でワイルドカードが使えるのかを迷ってしまったのは内緒。)
主キー=UNIQUEやろ!!みたいな思い込みが失点の原因となってしまいました。

マネジメントは計算もピッタリと合っていて、利用部門から仕様変更の依頼などは業務内でもよくある光景なので
「あーうちもこんな感じでふるいがいればいいのにな…」と感想が出るくらいには問題と向き合う余裕がありました。

午前は?

午前については再帰的呼び出し、dpiの計算、ホストアドレスの個数などを落としてしまったのが悔しかった。機械学習関連の問題だったり、メル●リ的なプロダクトについて問題が出たのは今時だったな。
HEMSについてはニュースで見たから解答できた。

個人的総評・令和第1回目に向けて

時間に追われて得点を落としてしまったので、この先に必要なのは特に問題の読み込みに対する慣れと、アルゴリズム問題に対するアレルギーをなくすことだと思ってます。

午前の計算問題に対しても理解を伴って解答できればさらに得点できるかも。
とはいえ、次回の難度は上がりそうなので覚悟を決めてもう一度学習に取り掛かろうと思います。アルゴリズムは本当に対策しないと大変だぞー…


ちな勉強法

・参考書、過去問1冊
道場

Nuxtの環境構築をDockerでサクッと実現する

時間がない人の為のDockerfile

FROM node:10-alpine

RUN apk add git emacs

RUN npm install -g vue-cli
WORKDIR /app
ENV HOST 0.0.0.0
EXPOSE 3000
version: '3'
services:
  app:
    build: .
    tty: true
    volumes:
      - "./../app:/app"
    ports:
      - "3000:3000"



足りないものは自分で継ぎ足してね(・ω・`) 要らないもの然り。
brewなど入れてあるのでgitでpushやら最低限のことはできるはず
今回はベンチマーク取ってないけど、 体感的にAlphineを使ったほうが適当なイメージをpullしたり、拾ったDockerfileを使うよりもファンが昂ぶらなくて良いと思った。 OSって色々詰まってるんだね。
npm触り出すとすぐ依存性とか詰まるから、今の所は助かってる。。

docker-compose build

docker-compose up

docker ps (idチェック)

docker exec -it (container_id) sh brew入れ方はLinux Brewのページを参照する

uname -a (動いているサーバのお名前頂戴) Linux e8aa47ead274 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 Linux
appプロジェクト配下で npm i --save npm run dev




うわあああああん!!(別案件)

f:id:letterneginr:20190408100348p:plain
docker内でvueのエラーする図

ご参考 https://github.com/Linuxbrew/brew/wiki/Alpine-Linux https://techblog.zozo.com/entry/docker_image_slim_in_alpinelinux https://qiita.com/tukiyo3/items/247f853c81bf00e82c11

MotionLayoutでリッチなUXをxmlのみで表現してみました

長いこと更新をサボってました。。 最近はもっぱらKotlinでのAndroid開発に従事していますが、ビューの原則はMaterialDesignを取り入れ、バラツキのあるデバイスの端末性能を吸収する優秀なプラグインが用意してあったりと、奥深く、ネイティブは楽しい分野だと感じています!

(デザイナーさんから思いもよらぬ仕様を叩きつけられることもありますが…)

勉強がてらに新しい部品に触る事も楽しいです!

そんな感じでいただいたデザインと納期の間で不安に苛まれていたとある日、何某Kotlinイベントに参加してみました。 Droid会議直後の温まった会場でMotionLayoutについて教えていただく機会があり、実装してみたので軽くレビューしていきます🐕

1. xmlファイルでリッチな動きが実現するMotionLayout

実装例・導入方法など詳しくはこちらをご覧ください💁‍♀️

https://github.com/googlesamples/android-ConstraintLayoutExamples

Google I/O 2018で紹介されているようですね♩ youtu.be

< 実装例gif >(でかくて申し訳ない…)

gfycat.com

RecyclerViewは別途Adapterクラスなどの実装が必要なので、実装にはこちらを参照してください。

2. 導入 : build.gradle

build.gradle

dependencies {
  implementation 'com.android.support.constraint:constraint-layout:2.0.0-alpha3'
}

3. ベースのxmlを記述する

base.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".HogeActivity">

    <android.support.constraint.motion.MotionLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/design_default_color_primary"
        app:layoutDescription="@xml/motion"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">   
 
       <android.support.v7.widget.RecyclerView
            android:id="@+id/top_recycler_view"
            android:layout_width="wrap_content"
            android:layout_height="500dp"
            android:paddingTop="30dp"
            android:background="@drawable/recycler_view_bkground"
            android:scrollbars="vertical">

        </android.support.v7.widget.RecyclerView>
    </android.support.constraint.motion.MotionLayout>
</android.support.constraint.ConstraintLayout>

4. motionタグの追加

motion.xml

<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:motion="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <Transition
        motion:constraintSetStart="@id/base_state"
        motion:constraintSetEnd="@id/open_state"
        motion:duration="3000">
        <OnSwipe
            motion:dragDirection="dragUp"
            motion:touchAnchorId="@id/top_recycler_view"
            motion:touchAnchorSide="top">
        </OnSwipe>
    </Transition>

    <ConstraintSet android:id="@+id/base_state">
        <Constraint android:id="@id/top_recycler_view">
            <Layout
                motion:layout_width="400dp"
                motion:layout_height="100dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintVertical_bias="1.0">

            </Layout>
        </Constraint>
    </ConstraintSet>

    <ConstraintSet android:id="@+id/open_state">
        <Constraint android:id="@id/top_recycler_view">
            <Layout
                motion:layout_width="400dp"
                motion:layout_height="500dp"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintBottom_toBottomOf="parent">
            </Layout>
        </Constraint>
    </ConstraintSet>
</MotionScene>

非常にさっくりと説明すると、app:layoutDescription="@xml/motion_activity_first_visit"のように設定したmotion.xmlで該当の部品のアニメーションを指定します。 今回のアニメーションはベースの状態(@id/base_state)とアニメーション終了時の状態(@id/open_state)です。 motionタグで囲う範囲については、アニメーションの可動域となるので、くれぐれも他の要素が消え去らないように注意してください。(プレビューすれば一目瞭然ですが…)

今回はmotion.xmlで、部品上部において上にスワイプする操作で、ビューがプルアップ+ダウンする挙動を制御しています。 フリック(軽く指で弾くような動作、スライドショーをめくるような動き)では反応しないので、適宜使用するタグを付け替えてみてください。

公式のリポジトリの例が豊富なので非常におすすめです。

https://github.com/googlesamples/android-ConstraintLayoutExamples

報告者を指定日時で通知するスクリプト<Slackユーザー向け / コード付き>

N番煎じ?

月末に部門定例会があるので、公平にみんなの中から報告者を決めることにしました💁‍♀️



Slack当番通知
Slack当番通知


GoogleAppScript

var postUrl = 'https://hooks.slack.com/services/HOGE/HOGEHOGE/HOGEHOGEHOGE'; …①

var icon = ':hatching_chick:';
var index = 0;
var checked_engeneer = '';
var icon_url = 'https://hogehoge-team.slack.com/team/HOGEHOGE'


var engeneer_ids = ['<@hoge1_slackId>', '<@hoge2_slackId>', '<@hoge3_slackId>', '<@hoge4_slackId>', '<@hoge5_slackId>'] …②



function shuffleReporter() {

index = Math.floor(Math.random()*6)

var id = engeneer_ids[index]

var jsonData =
{
"username" : '悪意のないchick',
"channel" : "#development",
"icon_emoji" : icon,
"text" : '今月の開発部門報告者は' + id + 'さんだよー\n開発のみんなの1ヶ月のタスクと、最近自分ががんばったことを話してね!',
"icon_url" : icon_url
};

var payload = JSON.stringify(jsonData);

var options =
{
"method" : "post",
"contentType" : "application/json",
"payload" : payload,
};

UrlFetchApp.fetch(postUrl, options);
}

①… SlackのwebhookAppをオンにして、出力URLを取得しましょう。
②… メンション用の個人タグです。付けないとメンション飛びません。個人の詳細ページからmemberIdとして取得できます。



悪意のないひよこが教えてくれます。(これはKotlin因み…🐤)
Cronもあるらしいけど、今回は手動で時間設定。
時間主導型の設定フローは下記画像を参考にしてください。
時間主導型設定フロー

カレンダーのイベント抜いて設定したら、また更新します。