どらめも

なんでもないことをかきます

4月振り返り

よかったこと

新生活に適応してきた

ちゃんと対策をしつつ大学に行って進捗を生むムーブをそこそこ確立できてきているので続けていきたい、時間が足りねえ。

本を読むのを徐々に再開

電車の中で読むことにしていてまあまあできているので良し。いわゆる超速本を読みました。DMMブックスで積読を大量入荷したのであとはしっかり消化していきたい。

ボルテvf19

念願(わかる人だけでいいです)。

gatsbyですこしわいわいした

コピペは良くないね(リンク)。

よくなかったこと

書類作業の増大

学期はじめのいろいろとかイとかでなんか仕方ないとはいえ多くの時間を取られた印象、効率良くさばけるようになりたい。

運動できてない

運動をして健康になるべき。

生活習慣が微妙

夜2時に寝てちゃんとおきるのが10時11時な気がするのでもう少し前倒ししたい。

その他

タスクの見積もりが適当

なんか目の前にあることやりたいことをいい意味でも悪い意味でもこなしている感じなのでもう少し制御を加えていきたい。

例の2021年のやつとの対応(関係箇所のみ)

○1ヶ月ごとに振り返りをしていく
△typescriptをちゃんとかけるようになる
twitterべったりをやめる

Gatsby.js入門がてらポートフォリオのベースを作った話

こんにちは最近アニメ見る時間がなくてどうしようと頭を抱えているドラです。

まえがき

結構前につくったポートフォリオサイトが正直あまり好きではなく普通に見づらかったのでとりあえず見やすいサイトを別途作ることにしました。 最近よく書いてるNext.jsでも良いかなと思ったのですがポートフォリオなので静的で何も問題ない&なんか使ってみたかったのでGatsby.jsを使うことにしました。
みやすさ重視なのでデザイン的なことは何もしてない単一ページです。

やったこと(つまったこと)

typescript対応

そんなに型を振り回すサイトじゃないので完全に自己満ですがやりました。具体的にはこのサイトを参考にやっていきました。gatsby-plugin-typegenを使うとgraphqlから型定義を自動生成してくれるらしく感動してました。ところが問題発生その型定義、どうやって使うんだ。写真の様にそんなもんはないと言われ途方に暮れていました。

f:id:doradorasuki:20210425175755p:plain
型エラー

そのため、依存関係に問題があるのかな?と思い当初は

/// <reference path="../__generated__/gatsby-types.ts" />

をコードの最初に書くことで解決していました。詳しくは公式を読んでいただきたいのですがこれを使うとその対象ファイルをコンパイル時に追加してくれるそうです。多分間違った使い方です。その後1週間くらい経って良いやり方ないかなあとtsconfigのドキュメントを読みつつゴニョゴニョしていたらtsconfigに

"include": ["./sec/**/*"],

Typoしていたことが判明し、原因が判明しましためでたしめでたし。
ところでいざこのTypoを直すと次はこんな感じのエラーが出ました。

f:id:doradorasuki:20210425181415p:plain
型エラーその2

自動生成される型定義は基本的に

type Maybe<T> = T | undefined;

が使われているので当然と言えば当然でオプショナルチェイニングを用いて解決してやれば良いのですが逆にいままで何で出なかったのかわかっていません(vscode型推論自体はreference pathの時も効いていました)。分かり次第追記します。

tailwindcssのpurgeについて

どこかから拾ってきたらしい?tailwind.config.jsに記入するpurgeのパスがぶっ壊れていてtsxに用いるtailwindがnetlifyにデプロイするとひとつも反映されない問題が生じていました。configは理解して自分でかこうねの気持ちになりました(それはそう)。ところで発見が遅れた理由として開発時に

gatsby develop

を使うと思うのですが、これを用いることでcssファイル自体は生成され、その後buildをするとそのcssは上書きされずしかも同じものが使われる?ようでローカル環境だとindex.htmlをひらくと正常にレンダリングされるんですね(もちろんgatsby cleanなどを行った上でbuildすると正常にレンダリングされません)。ローカルでの環境再現の時には注意したいポイントですね。buildまわりのことが無知なのがよく分かったので精進したいと思います。

Renovateを使い始めた

ライブラリのアップデート周りを自動でpull request出してくれる便利サービスです。知らない方は是非。

このあとやりたいこと

  • レスポンシブデザイン
    現状pcフルサイズ以外だとレイアウトが崩れるので一番やりたいですね
  • ブログの取得
    前のポートフォリオだとやっていたのですがheroku上のバックエンドの取得がかなり遅い(スリープ的なものに入る影響)のもあってとりあえず今回は見送ったのでそこら辺の改修も含めてやりたいですね
  • デザインとか凝る?
    みやすい中で動きがあると、うれしい!

さいごに

すぐできると思ってたんですけど結構色々ハマったので備忘録がわりにブログを書きました。完全にプログラムに使われている感じがするので改善していきたいです。
ここまで読んでいただきありがとうございました。
↓がリポジトリです。

github.com

redux-toolkit素振り

これはなに

redux-toolkitというreduxのラッパーライブラリ(公式推奨)の素振りをしてみた記事です。
前々から状態管理をちゃんとできるようになりたかったので今回備忘録がてら書いています。
サンプルとしてはtwitteridを取得してきて画面に表示します。

本編

まずはじめにフォルダの構成はこんな感じです。

f:id:doradorasuki:20210416231042p:plain
フォルダ構成

create-react-app フォルダ名 --template typescript

で作ったので今回使わないものも混じっています。

yarn add react-redux @reduxjs/toolkit firebase

次にコレを実行します。
ちなみにfirebase.tsにfirebaseのinitialize用のやつが入っています。

import firebase from 'firebase'

if(!firebase.apps.length){
    let firebaseConfig = {
        apiKey: process.env.REACT_APP_FIREBASE_APIKEY,
        authDomain: process.env.REACT_APP_FIREBASE_AUTHDOMEIN,
        projectId: process.env.REACT_APP_FIREBASE_PROJECTID,
        storageBucket: process.env.REACT_APP_FIREBASE_STORAGEBUCKET,
        messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGINGSENDERID,
        appId: process.env.REACT_APP_FIREBASE_APPID,
        measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENTID
    };
    firebase.initializeApp(firebaseConfig)

}
export default firebase

一応こんな感じです。
ファイルごとのイメージとしてはstores/twitter.tsにてreduxの関数とか状態回りの記述を行った上でstore.tsにてstoresのredux情報をまとめ上げてcomponents/Twitter.tsxから呼び出すという感じですね。
ここでreduxのデータフローのお話を少ししておきます。
https://redux.js.org/assets/images/ReduxDataFlowDiagram-49fa8c3968371d9ef6f2a1486bd40a26.gif
このgifがreduxの基本的な流れです。 uiのクリックによってactionが発行され、それがstoreにdispatchされることで現在のstateと組み合わせて新たなstateとして発行されます。
コード的な話をするとactionを書いて、storeを操作するreducerを書いて、あとはそれらをいろいろ結合して、みたいに様々なコードが必要になってきます(わからん人は調べてください、公式tutorialが良いです)。
その面倒くささを緩和してくれるのがredux-toolkitです。なんとactionをreducerを一箇所に書くことが可能です。それではコードを見ていきましょう。

import {createSlice, PayloadAction} from '@reduxjs/toolkit'

export type TwitterState = {
    id: string;
}
const initialState: TwitterState = { id: "" }

export const twitterSlice = createSlice({
    name: 'twitter',
    initialState: initialState,
    reducers: {
        updateId: (state, action: PayloadAction<string>) => {
            return {
                ...state,
                id:action.payload
            }
        }
    }
})

まずはstores/twitter.tsです。redux-toolkitではSliceインスタンスがreducerやactionの生成をしてくれます。
nameによってactionの名前空間を管理してるみたいです。これだけでreduxで状態管理できるなら使ってみようってなりませんか??(僕はなりました)また、TwitterStateをexportしていることからもわかるとおり型定義をふんだんに使って書けます。

import { combineReducers } from 'redux'
import { configureStore } from '@reduxjs/toolkit'

import { twitterSlice, TwitterState } from './stores/twitter'

export type AppState = {
    twitter: TwitterState;
}
const rootReducer = combineReducers<AppState>({
    twitter:twitterSlice.reducer
})

const store = configureStore({reducer:rootReducer})

export default store;

次にstore.tsです。結合処理です。今回は一つしかないですがstores/が増えるとAppStateやrootReducerの中身が増えます。

import React, { FC, useEffect } from "react";
import firebase from "../plugins/firebase";
import { useDispatch, useSelector } from "react-redux";
import { twitterSlice } from "../stores/twitter";
import { AppState } from "../store";
const TwitterLogin: FC = () => {
    const { twitterId } = useSelector<AppState, { twitterId: string }>((state) => {
        return {
            twitterId: state.twitter.id,
        };
    });
    const dispatch = useDispatch();
    const { updateId } = twitterSlice.actions;
    useEffect(() => {
        (async () => {
            firebase
                .auth()
                .getRedirectResult()
                .then((result) => {
                    console.log(result.additionalUserInfo);
                    dispatch(updateId(result.additionalUserInfo?.username?result.additionalUserInfo?.username:""))

                });
        })();
    }, [updateId, dispatch]);

    const LoginHandler = async () => {
        const provider = new firebase.auth.TwitterAuthProvider();
        firebase
            .auth()
            .signInWithRedirect(provider)
            .then((result) => {
                console.log("ok");
            });
    };

    return (
        <div>
            <button onClick={LoginHandler}>PUSH</button>
            {twitterId.length > 0 ? twitterId : "LOADING"}
        </div>
    );
};
export default TwitterLogin;

そしてcomponents/Twitter.tsxです。useSelector<A,B>のAにはstateの型情報、Bには実際にその関数で使いたい情報を指定してやるといいです。
あとはtwitterSlice.actionsをuseDispatchにて生成した関数を用いで読んでやればreduxを扱うことができます。
おまけとしてtwitter idを取得してstoreに突っ込むコードが書いてあります(余談ですがidの取得はloginした上でgetRedirectResultを呼ばないと取得できないみたいですなんで....)。 redirect処理を挟むのでuseEffectでtwitter idを取得してやる処理が妥当だと思います(他にいいやり方あったら教えてください)。

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { Provider } from "react-redux";
import store from "./store";

ReactDOM.render(
    <React.StrictMode>
        <Provider store={store}>
            <App />
        </Provider>
    </React.StrictMode>,
    document.getElementById("root")
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

最後にindex.tsxでAppの親としてProviderで囲ってやれば完成です。

あとがき

reduxなんとなく敬遠してたんですけどめちゃめちゃ使いやすくなっていていいですね。
あとreduxの流れを掴むためにいろいろ読みましたが公式tutorialが一番わかりやすかったのでおすすめです。

リンクとか

実装↓ github.com

TypeScriptでのasでハマった話

こんにちは、今期のアニメが忙しくてどう追おうか悩んでいるドラです。春休みにTypeScriptを書いていて引っかかったお話を書きます。

asとは何か

アサーションです。キャストではありません!!型アサーションです(2回目)。何もわかってなかった僕はキャストのつもりで使ってました(照)。型アサーションって何なのかという話ですが一言で言うとコンパイラを黙らせる機能です。 handbookには

Sometimes you will have information about the type of a value that TypeScript can’t know about.

と書いてあり自分がTypeScriptより優秀な時は使ってねのニュアンスです。
また、注意点として

Like a type annotation, type assertions are removed by the compiler and won’t affect the runtime behavior of your code.

とかいてあり、あくまでコンパイラのための機能であることがわかります。

何が起こったか

next.jsにてSSRする際に用いるGetServerSidePropsにてdynamic routingにて用いる値を取得しようとして[id].tsx内で

export const getServerSideProps: GetServerSideProps = async (context) => {
    const id = context.params?.id;
    ...
};

みたいなことをすると思うんですが、この場合idはany型になるので事件は起きたと言う感じです。
コードに状況を起こすと元はurlパラメータなのでこういう状況です。

const id = '1' as any;

そのうえで僕のした操作としては、asをキャストだと思っていたのでこうしました。

const b = a as number;
const c = b + 3;

するとconsoleにcをはくとなんと13が帰ってきます。3が文字列に自動的にキャストされてこれが行われているわけです。

'1'+'3'

それではどうするのが正解だったのでしょうか、正解としては以下の様なコードになります。

const b = Number(a)
const c = b + 3;

JavaScriptの関数で変換しています(リンク)。TypeScriptはあくまでJavaScriptのラッパーであることは理解しておくべきですね。

あとがき

any取扱注意を体感しました。

CA Tech Challenge 2daysに参加してきました。

それは何

2日間(実質1日)でECサイトを作ろうというものでした。軽いレギュレーションはあるものの 基本的にはapiを用いて自由に開発しその完成度等を競うものでした。 3人ほどのグループに一人メンターの方がついてくれる形で常時zoomをつないで開発する形式をとっていました。

目標

  • しっかり作り切る(2日しかないので)
  • なにか新しい技術を使う

一日目

まずはどんなものを作ろうか考えました。いろいろ考えた結果ウィンドウショッピング専用サイトを作れるとおもしろいんじゃないかということで 作りました(単純)。そこで欲しい機能を考えたところ、

  • お気に入り機能をログインせずに使いたい
  • ウィンドウショッピングを快適にしたい!!

だったのでまずはレギュレーションを満たした上でこれらの機能を実装することにしました。
技術としてはNext.js(Typescript)を直近のcookpadのやつで多用していたのもあり使いました。 レギュレーションはとりあえず結構すぐに満たせたのでお気に入り機能をつけ始めました。 ログイン機能を使わずに作ることが目標だったのでいろいろググったところlocalstorageが良さそうだったので使うことにしました。 ざっと読んだ感じすぐにできそうな気配がしていたのですが割と時間がかかってしまいこの日は終了でした。
ちなみに引っかかったところとしてはlocalstorageはすべて文字列管理になるのをイマイチ理解していなかったところでした。

二日目

まずはお気に入り機能を表に出してくる実装をした後少しだけ時間があったので(ほんまか)SSRとOGP対応をサクッとしました。 あとお気に入りを共有できるようにしようとurlにクエリを埋め込む実装を追加したのですが、twitterにリンクを投げてツイートできるようにする際に encodeをしていなくてうまく行かないことが発生し少し時間を溶かしました(汗)。
最後にデザイン回りを整えてfinishという感じですね。
ちなみに途中でログインapiやカートapiが生えましたがreduxとかrecoilとかをやったことなくてやりたい実装が他にあったので泣く泣くスルーしました(つらい)。

発表会

他の人の作品を見ているとfirebaseつかって自前データベースを持つようにしたり外部apiを用いて決済機能をつけた人、めちゃめちゃオシャレなUIにした人など様々で 自分の視野の狭さと手の遅さをまじまじと感じました。ずっとすげ〜って言っていたような気がします。精進したいですね。

感想

  • 当初立てた目標は一応達成できたので良かったです(新規性はlocalstorage)
  • メンターの方に抽象的な質問を投げても的確な答えが帰ってきてすごってなってました
  • 上だとさらっと書いてますけどcssまわりが下手で遅いなあというお気持ちになりました
  • 自分の手札が少なくて切ってしまった実装があったのでそこらへんの課題をこれから解決していきたいですね
  • コードがクソになりまくったので設計とか意識できるようになりたい。。。
  • cookpad(5day)+CA(2day)で7日間ハッカソンしていて本当に疲れました
  • メンターの方がアニメ好きで話が盛り上がってよかった

Cookpad Online Spring Internship参加記

研究にwebに忙しいドラです。春休みにcookpadのspring internship(学習型ハッカソン)に参加してきたので、 そのことについて書いていきます。

それは何?

インターン用のapiを用いてスマートフォン向けのレシピサイトを作るというものでした。 仕様書と使う技術(next.js, Typescript)は決まっていて基本的にはそのレギュレーションをまもりつつ まずは必須課題をこなしてその後自由課題や自分で考えた改善にとりくむという 感じでした。詳細は公式さんのリンク を載せておくのでそれを読んでもらえると幸いです。
f:id:doradorasuki:20200108113700p:plain 以下はドラの参加記です。

実際の開発

基本課題

開発初期はReactは軽く触ったことはあったもののNext.jsやapi通信に対ししっかりと型を使う経験などはないみたいなスペックでした。
そこでとりあえず用意していただいた講義動画を順に見ていきました。リンクの方から飛べると思うので良かったら見てみてください。 jsの入門から始まり最終的にはいろいろなレンダリングを用いた実装まで網羅していてとても完成度が高かったです。 見た後はまずは基本課題の実装をしていきました。基本課題に関してはあまり滞りなく進むはずだったのですが途中で apiキーをgithubにあげる基本的ミスをして青ざめたりしていました(言い訳をしておくとenvファイルまで作った上で使っていなかったので 自分でも意味不明でした)。開発は都度冷静になることが大事ですね。

発展課題

発展課題に関しては以下のものに取り組みました。

  • OGP対応
  • CSS in JS
  • 無限スクロール
  • パフォーマンス最適化(チョット)
  • UIをスマホから触りやすくする

OGP(SSR)に関しては前からやってみたいな〜って思ってたのでslackで画像がちゃんと表示されたときはヤッターって言ってました。CSSに関しては前々からtailwindCSS使ってみたかったので 開発初期から使っていました。めちゃめちゃ体験が良かったのでおすすめです。無限スクロールに関してはlodashをググって出てきたので使いましたが他の方の発表聞いてみた感じ いろいろとアらしいですね。ムズカシイ パフォーマンス最適化に関しては(スコア的な話だけにとどめますが)SSRしてnext/image適用で点数ガンガンあがりました。Next.jsスゴイ 余談ですが最適化面白そうだな〜って思って今超速本を読んでみたりしています。 UIは指で使いやすいといいよな〜ってしたら某フリマサイトみたいになりました。

f:id:doradorasuki:20210412223018p:plain
つくったもの

他の人の発表を見て

終始すげ〜〜っていいながら聞いてました。同じものを作る上でもここまで人に寄ってコンセプトが変わってくるのかって参考になりました。中には しっかりと使ってもらう対象を絞って開発している人やposter viewを他のサイトのcssとにらめっこして作った人とかもいてとても面白かったです。

感想

  • Next.js初めて使ったんですけどいろいろと整いすぎていてすげ〜って感じました。あとtypescriptはもっとゴリゴリかけるようになりたい。
  • slackでとても質問しやすい雰囲気になっていたのは参考にしたいなと思いました(レススピードやスタンプとかかな多分)。
  • メンターの方々がツヨツヨ&秒で質問に答えてくれてとても開発しやすかったです。ありがとうございました。
  • フロントエンドの視野が広まってあと自分の中の課題感がまとまった感じがしていて参加してよかったです。

その他

github.com

Open Hack U vol.4参加記

春休みが終わりそうで泣いていますドラです。ヤフーのハッカソンOpen Hack U 2020 Online Vol.4に JPHACKSの時と同じチーム(学科同期3人)で334jstとして出場しました。ありがたいことに発表会では最優秀賞をいただきました。やったね!
今回はその時やったことについて書いていきます。

何を作ったの??

プレゼンペースメーカーというプレゼンするときに話す速度を可視化してくれたりプレゼン練習するときにその速さを示してくれるツールを作成しました。
要素技術はPyQt5、PyAudioMeCabです。
音声認識の動画

↓テキストのスピード支援の動画

プレゼンペースメーカーを支える技術

音声認識について

神記事を読んでもらうのが一番早い気もしますが、
音声からMFCC(メル周波数ケプストラム)という特徴量を計算してその変化率を用いて母音の検出を行い、単位時間ごとの母音数をカウントしてそれを話す速度 と定義することでその値をグラフに描画しています。

ペースの提示について

入力された原稿に対しMeCabを用いて形態素解析を行い、形態素ごとに時間を割り当てた上で時間に対応した空白を設定し描画しています。
また、三角点はその時間に対応して動きます(たくさんの表示バグをかかえていますすみません)。

技術選定パート

まず何で作ろう、という話になり当初は話す速度の可視化にgoogle音声認識に投げ込んで帰ってきたテキストの文字数を数えるとかを考えていたので とりあえずwebで作るかみたいな話になりました。しかしながらそれだとapiにお金がかかること(web speech apiならお金かからないっぽい)、そして詳しい文字情報は話す速度認識には実は必要なく(話しているかどうかがわかればいい)自前で音声いじったほうが その後の拡張性につながる ことから自前で実装することになりました。
やり方のサーベイをする中で神記事をチームメンバーが見つけてくれて音声可視化パートの実装が 決まっていきました。またその中でプレゼンをする環境について考えてみたところwebアプリケーションである必要はない(プレゼンをするときはpcがあるので)ことに気づき、 その上で音声をいじるうえではライブラリの充実しているpythonが良いと考えたのでpythonを用いてデスクトップアプリケーションとして製作することにしました(ちなみにguiアプリケーション開発経験者は無でしたおい)。
使用環境等をしっかり考えたうえで最適な実装を選択することはとても大切だなと感じました。

実際の開発

前回同様基本的にdiscordで会話しつつ開発を進めていきました。
webアプリケーションのようにフロントエンドバックエンドが別れているわけでもないので開発を分業するのが結構大変でした。
結果的には僕は全体のコンポーネントの管理(親クラスの設計)とグラフの可視化、テキスト表示機能なんかを担当した気がします。
できるだけインスタンスの親子関係を大切にするようにコードを書いていったつもりですが、開発言語pythonの関係上子の間で変数共有したいときに一回 親インスタンス経由で渡したりするはめになりどうすればよかったんだろうと思っています。(webフロントだとvuexとかreduxのような状態管理の仕組みが整っていると思いますがpythonだと ない気がしました、知ってる方いたら教えてください!)

苦労した点

開発環境による差異

GUIアプリケーションを作成したのは初めてだったんですがOSによって適用されるデフォルトフォントが違ったりだとか各個人のディスプレイの解像度が異なるせいで見え方が異なるとかで 再現性の確保が大変でした(結局OS間の差異は埋められず現状Ubuntu番だけ公開しています...)。webだと結構そこらへんがやりやすかったりするのでこういう問題に初めて直面してなるほどなあって言ってました。

メンバーの生活習慣がバラバラ

多分前回よりも直接同時作業している時間がかなり少なかった気がします。非同期的に進捗を上げていく上で現在の進捗確認や詰まっているところをわかりやすく伝えることなどは とても大切だと感じ、意識していました。

QThread乱立させたら重くなった

PyQt5にはスレッドを分けるQThreadというものがあるのですが、それの数を増やしたら割と簡単に重くなりました(あたりまえ)。
同等の処理をQTimerという時間管理をする仕組みを用いることで解決しました。同じことをする上でも実装方法を調べ、考え相談するのはとても大切ですね(このときQTimerなるものの存在を知らなかった)。

今後の課題

ペースの提示回りのバグ

バグの原因が特定できていないのですががんばります。

OS間など環境間の差異をなくす

フォント埋め込んだりできるんですかね...?

感想

  • 自分一人じゃできないことができるという意味でチームハッカソンはやっぱ楽しいなと思いました。また、例の記事を読み解く上でチーム内でワイワイしつつ理解していったのですがとても楽しかったです。リンク
  • サーベイしてる段階で話題に上がったのですがNHK技研R&Dの資料が普通に面白いのでおすすめです。
  • クソ実装をしようとしてるときは一度誰かに相談するのは大事だと思いました(チームメイトが良い改善をしてくれた)。
  • マルチOSアプリケーション開発普通に難しいですね。

その他

github.com