☀️

Tech Friday

概要

  • 週1開催 金曜19時-20時 Slack callで開催 もしくはZoomかも
  • 内容
    • 学んだこと、改善したことを共有
    • テーマは自由、ゆるく継続する、準備に時間をかけない
  • 目的
    • 社内で学びを共有することで技術を個人に固定化することを回避する
    • コードベースを継続して改善するためにインプットを行うことと言語化の習慣付け
  • 参加者
    • 基本はAppify社員が話しますがスピーカーとしてのゲスト参加も歓迎
    • たまに公開イベントやるかも
  • 会のかっこいい名前募集中

ストック

Webのコンポーネントn階層ループを回避する方法を考える yamashou   (ぽこさんがいたら)

AとBコンポーネントからつかわれる単純なコンポーネントが増えてきたので階層を増やそうとすると、webの場合その階層が無限に増える可能性がある

だが、そうしていくとどこかでそれを妥協して同じ階層レベルで呼び合うことを妥協した層が必要になる。これを解決するにはどうしたらいいんだろう?

FlutterにHooksは必要か? sonatard
元?Uberのエンンジニアがアプリのスケールノウハウをまとめた書籍 sonatard

5/28

4/2 17-18時予定

  • 学び

3/26 16-17時

3/12 15-16時

  • 学び
  • SwiftUI yuzushioh
    • コンポーネントの基本
    • 状態管理
    Apollo InMemory Cache yamashou  

    ページネーションの時にTypeポリシーを使ってその状態を弾けるようにする

    • ページが側にその状態が現れないので、若干わかりずらい部分もあるが、ページネーションのロジックはコンポーネント側からへる
    • もしページ側でやるなら、自前でreadとwriteを駆使してページネーションを管理するものを用意する必要があるが、その場合は、ページネーションをしているページ全てで必要
    • うちの方針としてはページネーションをしているものは全て、InMemoryCache側にその処理が入るという方針でやっていくのが良さそう

3/5 3回目 16-17時

  • 今週のトピック
    • Flutter 2がきた(うちでは使ってないけど気になる)
  • 改善
  • 学び
  • 構造化プログラミング、オブジェクト指向の表や図 sonatard
    • 目的によって図を使い分ける
    • 構造化プログラミング
      • フローチャート → 処理の流れ
      • 状態遷移表、状態遷移図 → 状態の変化
      • データフロー図(DFD) → データの流れ
      オブジェクト指向(UML)
      • ユースケース図 → 要件の整理
      • クラス図、コンポーネント図、パッケージ図 → ソースコードの構造
      • シーケンス図、コラボレーション図 → ソースコードの流れ
      • ステートチャート(状態遷移図) → 状態の変化
      • アクティビティ図 → 全部入り
      • 参考
    • 仕様や実装を整理するのに役立つ
      • 表や図にすることでより俯瞰した視点で捉えることができる
    • 1つの図に情報を詰め込みすぎない
      • 図に書いている矢印は関数呼び出し?パッケージの依存関係?データフロー?
    CSSフレームワークの変遷 sonatard
    参考
    https://yuheiy.hatenablog.com/entry/2020/05/25/021342
    https://tailwindcss.com/docs/utility-first
    https://adamwathan.me/css-utility-classes-and-separation-of-concerns/
    https://frontstuff.io/in-defense-of-utility-first-css
    http://nicolasgallagher.com/about-html-semantics-front-end-architecture/
    https://vimeo.com/294976504
    https://m.youtube.com/watch?v=R50q4NES6Iw
    https://mxstbr.com/thoughts/tailwind/
    https://twitter.com/siddharthkp/status/1351889550159851521
    TailwindやCSS Propsは名前付けしなくていいのが便利
    Utility First
    
    https://dev.to/swyx/why-tailwind-css-2o8f
    Tailwind賛成派の意見
    
    https://programmingisterrible.com/post/139222674273/how-to-write-disposable-code-in-large-systems
    https://www.infoq.com/presentations/Simple-Made-Easy/
    Tailwind賛成派が紹介したコードの再利用についての説明
    
    https://www.joshwcomeau.com/images/snippets/separation-of-concerns.jpg
    関心の分離 HTML CSS JSではなく、機能ごとに分離する
    
    https://engineering.fb.com/2020/05/08/web/facebook-redesign/
    Facebookの新しい技術スタック
    stylexについてAtomic CSS
    
    https://m.youtube.com/watch?v=J_7_mnFSLDg
    Tailwindベストプラクティス
    
    https://dev.to/jaredcwhite/why-tailwind-isn-t-for-me-5c90
    Tailwindに否定的な意見
    
    https://mxstbr.com/thoughts/css-in-js/
    何故CSS in JSを使うのか
    影響範囲を限定できる
    自分の意見としては、カスケードを使うと影響範囲が難しい
    
    http://nicolasgallagher.com/about-html-semantics-front-end-architecture/
    BEM

2/26 17-18時

  • 今週のトピック
  • Jetpack Compose Betaリリース 🎉
  • 改善
  • E2Eテストの改善 sonatard
    • GraphQLクエリーからGoクライアントを生成してE2Eテストを書いている
    • すべてのE2Eテストをシーケンシャルに実行していたので待機時間が長かった
    • 動作確認のサイクルを短縮(BASEなら23s、Shopifyは110s)
      • Shopifyが長いのでデザインブロックとかは分けてもいいのかも
    • 思ったよりAPIが疎結合だった
      • Adminのリリース処理しなくても サービスのAPIはしっかりと動く
      • サービスごとに並列処理でテストしても問題なし
    • 厳密には単一アプリケーションにおける申請とサービスAPIの一連のテストをさぼっているのでよくない点もある
      • 両方行ったら発生する問題に気が付けないかもしれない
    • CIのジョブをdeploy+テスト(admin, announce)とサービス固有のテスト(base, shopify, campfire)の2つに分けた
      • Shopifyが不安定でテストが落ちることがたまにあるため、そこだけリトライするため
        • Shopifyに負荷かけすぎかもしれない
      • 合計時間は遅くなったので不要なら分割しない方がいい
  • 学び
  • Jetpack Composeの状態管理 sonatard
    状態更新検討メモ
    sonatard  12:56 AM
    rememberは完全にuseStateと一緒だ
    
    sonatard  1:20 AM
    State型で引き回すか、State型に委譲したプリミイティブ型で引き回すか悩ましい
    
    sonatard  1:27 AM
    Reactっぽいのは後者だけど、Jetpack  Compose前者と後者いりまじるから悩ましいな
    1:27
    けど混ざったからといってState型にしかできなあいことって特にないのか?
    1:29
    そうなるとすべて委譲したState型で流しておいて、意識するのはrememberに渡すときにmutableStateOfを使う
    ことだけにした方がいいのかな?
    1:33
    val mutableState = remember { mutableStateOf(default) }
    var value by remember { mutableStateOf(default) }
    val (value, setValue) = remember { mutableStateOf(default) }
    1:33
    あとはどれでいくか
    1:37
    @Composable
    fun StateTest2(text: String) {
        var remText by remember { mutableStateOf(text) }
        var remText2 = remember { mutableStateOf(text) }
        val (remText3, setRemText3) = remember { mutableStateOf(text) }
        Column() {
            Button(onClick = {
                remText = "aaa"
                remText2.value = "aaa"
                setRemText3("aaa")
            }) {
                Text(text = "aaa")
            }
            Text(text = text)
            Text(text = remText)
            Text(text = remText2.value)
            Text(text = remText3)
        }
    }
    1:37
    2はないかなー
    1:41
    1だと型としては、表現されてないのに代入できる場合と代入できない場合があってややこしいな
    1:42
            remText = "a" // ぱっとみ普通の型だけど代入OK
            TextTest(text = remText)
         }
    }
    @Composable
    fun TextTest(text: String) {
        // まったく同じ型なのにこっちではエラー
        text = ""
        Text(text = text)
    }
    1:42
    やっぱり3かな
    1:43
    しかも1だと他のコンポーネントに更新する手段提供できないのかな?
    1:44
    2だと更新できる状態で他のコンポーネントに渡すことになるのかー
    1:45
    そう考えるとやっぱり3かな
    1:46
    他の関数に更新する手段を提供することは稀だし、それは明示的であったほうがいい
    1:48
    @Composable
    fun TextTest2(text: MutableState<String>) {
        text.value = ""
        Text(text = text.value)
    }
    @Composable
    fun TextTest3(text: String, setText: (String) -> Unit) {
        setText("")
        Text(text = text)
    }
    1:48
    更新する手段を上から受け取るパターン
    1:48
            TextTest2(text = remText2)
            TextTest3(text = remText3, setText = setRemText3)
    1:48
    渡しているところ
    1:49
    あと2にすると上のコンポーネントで更新するけど、下のコンポーネントで更新しないのにMutableState渡すとかもしそう
    1:49
    更新はいったん3でいく
    1:50
    Stateではないプリミティブな値も結局再コンポーズされるから値がリアクティブであることは代わりがないのかな
    1:52
    いやけどプリミティブな値の場合は更新されるということがありえないのか
    1:52
    Stateだったら外部ソースからの変更で変わる可能性がある
    MutableStateだと内部として値を書き換える可能性がある
    普通の型は内部で更新できないし、外部ソースから流れてくることもない
    1:53
    つまり、あとは外部ソースと繋がっている型であると意識したいならState型で、そうでないならState型に委譲したプリミイティブ型となる (edited) 
    1:54
    Reactの場合はライブラリがそこを意識しない前提だから、後者しか許してない
    1:54
    そしてReactでは実際後者で困ってないんだよなー
    1:57
    State型使っていると、もし外のソースから繋がらなくなったときにわざわざ型直さないといけないのか
    1:58
    コンポーネントからすると外部と繋がっているかそうでないかは本質的ではなく、ただ値を受け取って表示するということを考えた方がいい気がしてきた
    1:58
    そうなると State型に委譲したプリミイティブ型で統一がよさそう
    1:59
    結論
    rememberの返り値は、val (text, setText) = remember { mutableStateOf("hello") }
    コンポーネントが受け取る型は、State型に委譲したプリミイティブ型
    2:00
    結果としてはReactと同じになった React考えて作られているだろうから大きく外してないはず
    2:00
    やってみてJetpack Compose特有の辛いところがあったらまた考えよう
    
    Terraform CDK yamashou  

    AWS CDKと同じようにプログラムコードで扱うことができる

    Python, Typescript, Java, C#で書くことができる

    特殊な記法などを覚える必要性が低く、エンジニア的には非常に扱いやすいものである

    今うちではできていないが、Constructs Programming Modelにしたがって描けるようになるとなお良いと思っている

2/19 17-18時

  • 改善
  • CRAのejectから自前Webpackへ移行 yamashou  
    • Webpack自体は単純に1枚のjsファイルにする
      • rulesでどんなタイプのファイルをどのように変換するかを決める
      • 各プラグインでの設定が重要(webpackとruleで使うもの)
      • optimizationをうまく利用して最適化する
        • 依存物とプロジェクトファイルを分離して生成
        • cssの最適化
      • 基本的にdev環境とprod環境で使うものが大きく変わるし、それによりファイルサイズも三倍近く変わるから注意が必要
      • webpack自体がかなり色々なことをしてくれる(そのせいでjsやprojectレベルに影響してエラーや自動で書き込まれたりもする)
        • webpack dev server が内部に入ったと書いてあるが、入ったのではなくwebpackが呼ぶようになった
        • 複数のよく使われるwebpack製のものが内部に入っていて、npm i していなくても使えるようになってる
    • emotion 11(これが結局一番時間がかかっている)
      • ドキュメントが散らばっており、webpack 5 x typescriptに対応するにはdocumentとissueを読み込まなければたどり付けなかった
    • webpack.config.tsにするとcross-envやts-nodeなどそれ用のtsconfigを読み込んだりする設定が必要で、eslint側も必要みたいだがよくわからなかった
  • 学び
  • Jetpack Composeの基本 sonatard daneko
    • ほとんどReactに対応する概念があると思って良い
    • 基本的なコンポーネント
      • Column、Row、Box
        • HTMLとは違ってデフォルトは重なるので、基本的にColumnで囲う必要がある
      • LazyColumn、LazyRow、LazyVerticalGrid、VerticalGrid(独自)
      • Text、Button(よくあるボタンのUI)、IconButton(Iconそのものがボタンになる)
      • Spacer、Divider
      • Composition Local、compositionLocalOf()、staticCompositionLocalOf()
      • 定義と渡し方
        val LocalNav = compositionLocalOf<NavHostController>()
        
        @Composable
        fun ShopifyApp(
          val navController = rememberNavController()
        
          Providers(LocalNav provides navController) {
            Home()
          }
        }
        
        使う側
        @Composable
        fun Product() {
            val navController = LocalNav.current
             
        
      • Navigate
      • 定義
        NavHost(navController = navController, startDestination = "home") {
            composable(route = "home") {
                Home()
              }
              composable(route = "favorite_products") {
                      FavoriteProducts()
              }
              composable(route = "collection_product" + "/{collectionId}") { backStackEntry ->
                      val id = Id(backStackEntry.arguments?.getString("collectionId").toString()
                      CollectionProducts(collectionID = id)
            }
        }
        
        使う側
        
        navController.navigate("home")
    • Modifier
      • background
      • padding(marginはない)
      • 
        Modifier.padding(10.dp).background(Color.Black).paadding(1.dp)
      • width、height
        • fillMaxWidth(0.7F) → width: 70%
        • preferredWidth(10.dp) → width: 10px
      • weight
    • MaterialTheme
      • TextStyle
      • class TextStyle(
            val color: Color = Color.Unspecified,
            val fontSize: TextUnit = TextUnit.Unspecified,
            val fontWeight: FontWeight? = null,
            val fontStyle: FontStyle? = null,
            val fontSynthesis: FontSynthesis? = null,
            val fontFamily: FontFamily? = null,
            val fontFeatureSettings: String? = null,
            val letterSpacing: TextUnit = TextUnit.Unspecified,
            val baselineShift: BaselineShift? = null,
            val textGeometricTransform: TextGeometricTransform? = null,
            val localeList: LocaleList? = null,
            val background: Color = Color.Unspecified,
            val textDecoration: TextDecoration? = null,
            val shadow: Shadow? = null,
            val textAlign: TextAlign? = null,
            val textDirection: TextDirection? = null,
            val lineHeight: TextUnit = TextUnit.Unspecified,
            val textIndent: TextIndent? = null
        ) {

      • Theme、Surface
    • コンポーネント階層設計
      • Reactと同じでよさそう