Kotlinのリファレンスを読んでいるメモ

Kotlinのリファレンスを読んでいる

kotlinlang.org

諸事情でKotlinを覚えるかとなったので

速習 Kotlin: Javaより簡単!新Android開発言語を今すぐマスター 速習シリーズ

速習 Kotlin: Javaより簡単!新Android開発言語を今すぐマスター 速習シリーズ

とりあえずこれをざっと読んだけど結局リファレンスを読んでいる この本はJavaわかれば電車とかでびゃっと読めてなんとなくKotlinかけるようになると思うのでやる気あんまないけどざっくり把握したいみたいな時には良さそう try式ないとかあったのでなんとなく書くレベルで必要なのが網羅できてるかというとなんとも言えない

やる気があるならリファレンス読めば良さそう だいたいのことがそう

どこまで読んだか忘れちゃうのでメモレベルのメモ

Control Flow: if, when, for, while

  • ifが式なので三項演算子ない
  • if式はelseないとだめ
  • when(switchみたいの)もそう
  • 引数なしwhenはif-else ifのノリで使える
    • else ifだらけになる場合こっちのが良さそう

Returns and Jumps

  • ラムダ式のなかでreturnするとラムダ式を書いた関数からreturnされちゃう
    • ラムダ式だけをreturnしたい場合はラベルで頑張る
    • 匿名関数で書けば匿名関数だけreturnできる
    • こはちょっと微妙な気持ちなったけどラベルガンガン使ってく文化なのかな

Classes and Inheritance

  • プライマリコンストラクタはbodyを持てないので、initブロックで初期化処理を書く
  • initブロックは複数かける。書いた順に実行される
  • initブロックではプライマリコンストラクタの引数を参照できる
  • プライマリコンストラクタの引数はクラスのフィールドになる
    • valで宣言した引数はread-onlyなフィールドになる
fun main() {
    var test = Test("test")
    println(test.value)
}

class Test(var value:String){
    init {
        println("You can read property defining at Primary Constructor. $value")
    }

    init {
        println("You can define multiple initializer")
    }
}
  • 全てのinitializerはセカンダリコンストラクタよりも前に実行される
  • プライマリコンストラクタがないとデフォルトコンストラクタを生成される。デフォルトコンストラクタを露出せずプライマリコンストラクタを定義したくない場合、引数なしでprivateなプライマリコンストラクタを定義する
  • プライマリコンストラクタの引数が全てデフォルトを持っていると、JVM上ではそのデフォルトを使う引数なしコンストラクタを生成する
  • 全てのクラスはAnyを継承している
  • 継承する場合は継承元のコンストラクタで初期化してあげること
open class Super(val a:Int, val b:Int)
class Child1(a2:Int, b2:Int): Super(a2,b2)
class Child2: Super {
    constructor():super(1,2)
}
  • オーバーライドできる要素にはopenを明示する必要がある
  • overrideしたメソッドを、さらに継承したクラスでoverrideするのを防ぐ場合はfinal
open class Super {
    open fun method() {
        println("parent")
    }
}

open class Child1 :Super(){
    override fun method() {
        super.method()
        println("child1")
    }
}

class Child2 :Child1(){
    override fun method() {
        super.method()
        println("child2")
    }
}

fun main(args: Array<String>) {
    Child2().method()
}
  • プロパティもオーバーライドできる
    • あんまり用途がわかってない
    • カスタムアクセサの拡張とかだろうか🍙
  • 派生クラスの初期化よりもベースクラスの初期化のが先に走る
  • ベースクラスのinitializerでopenなメンバを使わない
    • 派生クラスでoverrideしたメンバが初期化されてないのにinitializerで呼ばれる形になるので、予期しない動きをする可能性がある
  • ベースクラスが複数あって同じメンバが存在したらオーバーライド必須
  • クラスはstaticなメソッドを持てない
    • トップレベル関数を定義しよう
    • クラス経由で関数を呼びたいが、初期化はしない場合はオブジェクト宣言orコンパニオンオブジェクト

Properties and Fields

  • backing fieldの参照はカスタムアクセサを介さない
  • カスタムアクセサの中でフィールドを参照すると再帰になって死ぬ
  • backing propertiesの用途がよくわからない
  • lateinitをつけた変数はインスタンス生成時に初期化しなくてもコンパイルエラーにならない
    • ただし、初期化せずにコールすると例外
    • DIとかの文脈で使うらしい
      • Setterインジェクションとか?
      • Nullableでnullで初期化するより取り回しいいのかな?

interfaces

  • インターフェースはプロパティをもてる
    • が、abstructかカスタムアクセサの実装のみ
    • backing fieldはもてないし、カスタムアクセサから触れない
  • 複数のインターフェースを実装した時にシグネチャが被るメンバがあったらそいつはオーバーライドしないといけない

Visibility Modifiers

  • トップレベルに関数を定義できる
  • トップレベルの要素に対するVisibility Modifiers
    • privateはfile内から参照、internalはモジュール内から参照できる。protectedはつけられない
  • クラスのメンバに対するVisibility Modifiers
    • privateはクラス内、protectedはそのクラスとサブクラスから、internalはモジュール内から参照
  • モジュールはまとめてコンパイルした組み合わせのこと?🍙

Extensions

  • こんな感じですでにあるクラスを拡張できる
fun String.yeah(){
    println(this)
    println("yeah")
}

fun main(args: Array<String>) {
    "oh".yeah()
}
  • メンバと拡張関数のシグネチャが同じだとメンバが優先される
    • ハマりそう
  • Nullable型を拡張するとレシーバがNullableになる
    • レシーバがnullでも呼べる
  • 拡張プロパティ
    • カスタムアクセサだけ
    • プロパティとかフィールドとかの言葉の定義を一回整理したい🍙
  • クラスのなかで他のクラスを拡張できる
    • 定義したクラスの中でだけ有効っぽい
class C (val value:Int)

class D {
    fun C.a(){
        println(this.value)
    }

    fun b(c:C){
        c.a()
    }
}

fun main(args: Array<String>) {
    D().b(C(1))
}

Data Classes

  • Lombokの@Dataみたいな
    • 生成されたメソッドはprimary constructorで定義したメンバしか使わない

Generics

  • 型パラメータが推論できる場合は、コンストラクタ呼び出し時に省略できる

class A(val value:T) class B()

fun main(args: Array) { var a = A(1) var b = B() // コンパイルエラー }

  • in/outはこの記事がわかりやすかった
  • inは型パラメータが引数の型にだけ使われるマーク
    • だったら、Tが引数の型のメソッドがある
    • その型パラメータが設定されたクラスのメソッドは、Tの継承クラスを渡せるはず
  • outは型パラメータが戻り値の型にだけ使われるマーク
    • 戻り値を、そのクラスの親としてそのまま格納できる
  • ちょっとなんか怪しいのであとでもう一度🍙

Nested and Inner Classes

  • ネストされたクラスにinnerがついてるとouterを参照できる
class A (val value:Int){
    inner class B {
        fun print() {
            print(value)
        }
    }
}
  • 匿名クラスはobjectつける
interface A {
    fun print()
}

abstract class B {
    abstract fun print()
}

fun main(args: Array<String>) {
    val a = object : A {
        override fun print() {
            print("test")
        }
    }

    a.print()

    val b = object : B() {
        override fun print() {
            print("test")
        }
    }

    b.print()
}
  • Sam変換微妙に理解できてない🍙
  • Javaの関数型インターフェースにのみ使えるっぽい
fun test(s:Comparator<Int>) {
    s.compare(1,2)
}

fun main(args: Array<String>) {

    test(Comparator { o1, o2 -> o2 - o1 })
    test({ o1, o2 -> o2 - o1 }) // これなんでだめ?

}

Enum Classes

  • こんなんできる
enum class Test {
    A {
        override fun print() {
            println("AAAA")
        }
    },
    B {
        override fun print() {
            println("BBBB")
        }
    };

    abstract fun print()
}

fun main(args: Array<String>) {
    Test.A.print()
    Test.B.print()
}
  • interfaceを実装できる
    • メンバはclassに定義してもいいし、enum値に定義してもいい
interface A {
    fun A()
}

interface B {
    fun B()
}

enum class E:A,B {
    ENUM{
        override fun B() {
            println("BBBB")
        }
    };

    override fun A() {
        println("AAAA")
    }
}

fun main(args: Array<String>) {
    E.ENUM.A()
    E.ENUM.B()
}

Object Expressions and Declarations

  • なんかの方を継承したanonymous classのインスタンス生成には、object式を使う
  • object式に複数の型を渡す奴が何なのかよくわからん🍙
  • 匿名オブジェクトをpublicな関数で返すと、そのオブジェクトのメンバにはアクセスできない
  • クラスっぽい感じでobjectを宣言するとシングルトンになる
    • スレッドセーフ
    • 初期化はスレッドセーフ
    • 何かのクラスを継承できる
  • クラス内のオブジェクトはcompanionで宣言できる
  • コンパニオンオブジェクトがあんまり理解できてない?🍙

Type aliases

typealias Maaaap = Map<String, Map<String, String>>

fun main(args: Array<String>) {
    val map : Maaaap = mapOf("p" to mapOf("c" to "v"))
}
typealias F = (Int) -> Int

fun main(args: Array<String>) {
    var a:F = {a:Int -> a}
}
  • ネストされたクラスにも行ける
    • インナークラスとネストされたクラスの違いが理解できてない🍙
  • あくまでエイリアスで同様の型として扱われる
typealias Integer = String

fun method(value:String) {
    print(value)
}

fun main(args: Array<String>) {
    val ok:Integer = "YEAH"
    method(ok)
}

Inline classes

  • こういう使い方であってるんだろうか
class Yes {
    fun yes(){
        println("yes")
    }

}

inline class LoggingYes(val value: Yes) {
    fun yes(){
        log.info("--- yes start ---")
        value.yes()
        log.info("--- yes end ---")
    }
}
  • 普通のクラスとの違いがよくわからない🍙
    • これはパフォーマンスの話だけ?

Delegation

  • byに指定したプロパティの引数をオブジェクトでインターナルに保存し、そのクラスが持っている全てのメンバをbyが指定されたクラスのメンバとして扱える

Delegated Properties

  • カスタムアクセサの共通化のためにgetterとsetterを定義したクラスを作ってbyで委譲できる
  • lazyにLambdaを渡すと遅延評価できる
import kotlin.reflect.KProperty

class Data {

    var count:Int = 0
    val a:String by lazy {
        println("compute")
        count++
        "ohhhhhhhhhhhhhhhhhhhh"

    }
}

fun main(args: Array<String>) {
    val e = Data()
    println(e.count) // 0
    println(e.a) // ここでlazyに定義したLambdaが計算される
    println(e.count) // 1
    println(e.a) // 2回目はそのまま返す
    println(e.count) // 1
}
  • Delegates.observableはsetterの処理を委譲
    • 型と変更前、変更後の値が参照可能
import kotlin.properties.Delegates

class Data {
    var a:String by Delegates.observable("initial"){
        property, oldValue, newValue ->
        println("$property from $oldValue to $newValue")
    }
}

fun main(args: Array<String>) {
    val e = Data()
    e.a = "a" // var Data.a: kotlin.String from initial to a
}
  • vetoableはbooleanを返すラムダを定義してfalseを返すと値を更新しない
import kotlin.properties.Delegates

class Data {
    var a:String by Delegates.vetoable("initial"){
        property, oldValue, newValue ->
        println("$property from $oldValue to $newValue")

        if (newValue == "fuck") {
            false
        } else {
            true
        }
    }
}

fun main(args: Array<String>) {
    val e = Data()
    e.a = "a"
    println(e.a)
    e.a = "fuck" // この代入は無視される
    println(e.a) // a
}
  • なぜmapに委譲できるのかよくわからない 🍙
    • 委譲プロパティの要件を満たしてないように見えてる
  • local変数も委譲プロパティ使える
    • 使い所難しい気もする
  • provideDelegate理解できてない 🍙

Functions

  • デフォルトの引数は継承しても引き継ぐ
open class Yes {
    open fun hello(value:String = "hello") {
        println(value)
    }
}

class Yes2: Yes() {
    override fun hello(value: String) {
        super.hello(value)
        println("hello2")
    }
}

fun main(args: Array<String>) {
    Yes2().hello();
}
  • 戻り値が不要な場合、戻り値はUnitとなる
    • この時の型の指定はOptional
  • 1つの式だけの関数は中括弧を省略できる
fun a(a:Int, b:Int) = a * b

fun main(args: Array<String>) {
    println(a(2, 3)) // 6
}
  • 戻り値の型は推論されない
  • 可変長引数はvararg
  • infix function
infix fun String.join(value:String) = this + value

fun main(args: Array<String>) {
    println("YEAH" join "OHHHHHHHHHH")
}
  • ローカルな関数定義ができる
    • あんまり用途わかってない
fun main(args: Array<String>) {
    fun yes() {
        println("yes")
    }

    yes()
}

Higher-Order Functions and Lambdas

  • 関数型は関数型インターフェースじゃなくてこんな感じ
val sum1 = { x: Int, y: Int -> x + y }
val sum2:(Int, Int) -> Int = { x,y -> x + y }

fun main(args: Array<String>) {
    println(sum1.invoke(1, 2))
    println(sum2.invoke(1, 2))
}
fun test(text:String, func: (String) -> String){
    println(text)
    println(func(text))
}

fun main(args: Array<String>) {
    test("yes", {it + "func"}) // 引数が一つならitで参照できる
    test("yes"){it + "func"} // 関数型の引数が最後なら外に出せる
}
  • 無名関数だとこうなる
fun test(text:String, func: (String) -> String){
    println(text)
    println(func(text))
}

fun main(args: Array<String>) {

    var a = fun(a:String): String {
        return a + "func";
    }

    test("yes", a)
}

* 外側のスコープの変数にアクセスできるし、変更もできる

fun main(args: Array<String>) {
    var a = 1
    var b = {println("b");a = 100}
    println(a) // 1
    b() // bの関数をコール
    println(a) // 100
}
fun main(args: Array<String>) {
    val join = fun String.(arg:String): String = this + arg // レシーバ付き関数は
    println("yes".join(" no")) // yes no // このノリで使える
}

2019年3月にやったこと

色々忙しかったのであんまり何もしてない。中国語の勉強を始めた。 英語、中国語、アルゴリズムをメインにやっていきたい。

Release It! 本番用ソフトウェア製品の設計とデプロイのために

9章まで見た。「タイムアウトさせよう」「ネットワークを介した接続は失敗する可能性が常にあるからな」みたいな局所局所の話は実感できるんだけど、ブレーカーがどうとか、こういう変なアクセスがいっぱいきたからメモリが爆発してどうこう、みたいな話が、わかるけど実感はできてない気がする、という状態である。 多分私はこういう話を実際に体験しないと実感できないことが多いんだけど、体験するためのハードルがでかいなーみたいなことを考えている。 読み終わったら現状のアーキテクチャに適用できるとしたらこれ、みたいなことを考えられたら良さそう。

英語

English Bellを40レッスン受講した。道のりが長い。 再来月はTOEICを受ける。大学の後輩とTOEICを競うことになった。

中国語

https://www.amazon.co.jp/dp/4863922191をひたすら読んでるが、まだ始めたばかりで挨拶が覚えられないレベル。6月に中国語検定準4級を受ける予定でいる。辞書ひくのが面倒だなーと思っている。あと、調べた単語をメモできる辞書のアプリが欲しい。

書いた記事

qiita.com

でかいPRをレビューするときに、ファイルごとにレビュー済みマークをつけるためのChrome拡張を作った。ここ最近はずっとこれを使ってレビューしているが結構便利だと思う。

これからやること

  • 読書会プラットフォーム作る
  • プログラミングコンテスト攻略のためのアルゴリズムとデータ構造
    • 読む
  • ElectronかWebアプリ(サーバなし)でNature RemoのPC用クライアントを作る
    • なぜか俺は音声やスマホよりもPCで操作したい時がたまにある
      • あとはSPAとJSの学習用に
        • 読書会プラットフォームの後
  • Goならわかるシステムプログラミング
  • 英語
  • 中国語
  • Release It!
  • ここ最近ほとんど業務でプログラミングをしなくなって、調整とかレビューとかばっかしてるがかなり雰囲気でやってるので、マネジメント系の本を読もうとしている
    • なにがいいのかよくわからん
  • Effective Go - The Go Programming Language
  • パタヘネ

なぜ私はソースコードレビューをするのか

この文章は一般論としてなぜソースコードレビューをするのか、ではなく、私が個人として、コードレビューをしているモチベーションはなんなのかを整理するために書いた。

最近ずっとソースコードレビューをしているが苦痛になってきた。ので、ソースコードレビューをやめるか、ソースコードレビューを苦痛でなくするか、苦痛なまま続けるか、いずれかを選ぶ必要がある。 やめる案に関しては、一旦考えないことにする。レビューがビジネスに対して与えるメリットが、レビューのコストを上回るかどうかは正直よくわからない。 これがわかるとやめる選択をとれたり、レビューに対する苦痛が少し減ったりする気がするが。 今の所はどうしても、メリットがあるからレビューをする、というよりも開発に対する美意識としてやるべきだと感じているからやる、という感覚でレビューをしている気がする。

どのようなコードのレビューをしているかというと、複数の似たようなサービスを、統一されたインターフェースで呼び出すためのプロキシのようなサービスを開発していて、そのサービスが統合可能なサービスを追加するためのコードをレビューをしている。 「設計から外れたコードが書かれていないか」「何か複雑で特殊なことをする必要があるときに、良い感じの構造になっていそうか」「統合先のサービスの仕様に乗っ取っているか」「いわゆるプログラミングとして、あまりよろしくないコードになっていないか(変数名が変だとか)」「テストが網羅的か」といった観点でのレビューをしている。

なぜレビューをしているか。私の場合は主に「1. 人はミスするので、それを減らしたい」、「2. 視点を増やしたい」、「3. 読んでいて辛い気持ちになるコードを増やしたくない」の3点である。 教育としてのレビューを行なっている感覚はあまりない。以前の環境では教育が8割くらいの気持ちだったので、ここの感覚はコードを書く人の能力に寄ると思っている。 特に1と2が重要だと思っている。1は単純にヒューマンエラーをダブルチェックで減らそうぜ、みたいな話で、2はいろんな視点でコードを見たいという話だ。 いろんな視点で、というのはなんと言えばいいのか、いろんな経験から踏まえて、というのがいいのだろうか。

アプリケーションが正しく動かない原因は色々あるが、単純なミスだけではなく経験からくる知見がないと防げないものがあると思っている。 例えば複数のトランザクションが複数のリソースをロックする場合に、リソースをロックする順序がトランザクションごとに異なるとデッドロックする可能性がある、みたいな話だ。 そういった観点は他にも色々あると思っていて、賢い人なら論理的思考力と想像力で防げるのかもしれないが、私には無理だ。 そして、私は当然全ての知見を持っていないし、他の人も大抵の場合そうだと思っているので、視点を増やすのが重要だと思っている。

バグを完全になくすことはできないが、個人的には時間をかけてでもレビューをすべきだと思えるくらいにはバグを減らせるのではないかと思っている。 計測したことはない。どう計測すれば良いのだろうか。何かデータがあれば見たいが、コードを書く人のレベル感でこのあたりの感覚はかなり変わってくると思っており、計測って可能なんだろうかとも思っている。 やるべきかどうか、についてはアプリケーションの用途にもよると思っていて、バグってたら都度都度直せばいいや、みたいなものであればそれはそれで良いと思っている。 ただし、現在開発しているアプリケーションをそういった類のものだと思っていないので、レビューを続けている。

3については自己満足かもしれない。バグの少ないプログラムを書くためには、コードの綺麗さよりもテストにこだわった方が効率が良いと思っているからだ。 しかし、謎解きのようなコードを読んでいるとすごくモチベーションが落ちて効率が落ちるので、個人的には力を入れている。 ただしあくまで私の感情の話で、読みづらいコードによってモチベーションが落ちるのが一般的でないのであれば、ここに関してはそれほどこだわらなくても良いのではないかとも思っている。

2019年2月にやったこと

花粉が出てきてつらい。

Release It! 本番用ソフトウェア製品の設計とデプロイのために

4章の後半まで見た。ここまでは基本的に事例の紹介でここから対策という感じ。基本的にリソースを分割して障害の伝搬を防ぐ話と、タイムアウト設定して完全にロックしたままにならないようにしようぜみたいな話が多いっぽい。

読書会プラットフォームを作り始めた

読書会プラットフォームを作り始めた。 本検索して読書会登録するとdiscordのURL吐き出されるみたいな感じのやつ。

フロントがReact.jsでバックエンドがGAE+Golangで作っている。2人で作ってて私はバックエンドを作っている。 まだほぼ何もない。認証の仕組みを作っているところ。GAEもFirebaseもめちゃくちゃサクサク動かせてすごい。

3月中にリリースできたら嬉しい。

基礎から学ぶ Vue.js

ざらざらっと全部読んでなんとなく挙動はわかった気がする。webpackとかvue-routerとかはよくわかってない。

lorcaでtreviewのUI作った

inabajunmr.hatenablog.com

Vue.jsがなんとなくわかったので画面を作ってみた。lorcaもなんとなく触れるようになったっぽい。

プログラミングコンテスト攻略のためのアルゴリズムとデータ構造

ちょろちょろ読み始めた。いくつかソートを実装したあたりでまだ本番感はあんまりない。今月中に読み終わりたい。

情熱プログラマー ソフトウェア開発者の幸せな生き方

トイレとかでちまちま読んでる。

英語

12レッスン受講した。だれているが当面これを終わらせる方向で頑張ることにした。

書いた記事

qiita.com

qiita.com

qiita.com

これからやること

  • 読書会プラットフォーム作る
  • プログラミングコンテスト攻略のためのアルゴリズムとデータ構造
    • 読む
  • ElectronかWebアプリ(サーバなし)でNature RemoのPC用クライアントを作る
    • なぜか俺は音声やスマホよりもPCで操作したい時がたまにある
      • あとはSPAとJSの学習用に
        • 読書会プラットフォームの後
  • Goならわかるシステムプログラミング
  • 英語
  • Release It!
  • ここ最近ほとんど業務でプログラミングをしなくなって、調整とかレビューとかばっかしてるがかなり雰囲気でやってるので、マネジメント系の本を読もうとしている
    • なにがいいのかよくわからん
  • Effective Go - The Go Programming Language

GitHubのPRの差分を見るときレビュー済み/未レビューをファイルごとにTODOリスト化したい

でかいPRがあるととりあえず差分を上から見てくんだけどこの上から見てく、ってのは本当は間違ってると思ってて多分見てく上で正しい順番みたいなものがある

複数レイヤーにまたがったPRだったら依存される側から見てくべき、とか

実装とFW的な奴がごっちゃに飛んできたらFWから見てくべき、とか

ただしそれとは別に、全部の差分を見たい、というのがある

それで、上から見てくと"全部みる"、という意味では効率が良い

というか見たいとこから見てくと全部見たかどうかわからなくなる

ので、見たい差分を選んで、見終わったら見終わったマークをつけるような奴が欲しいなと思った

イメージ的には

  1. 差分のページに行くとデフォルトで全部の差分が閉じた状態で表示
  2. 開いてレビュー
  3. 完了したら見たよマークをつけるとなんか背景とかがわかりやすい色になる

そういう感じのやつ

とりあえず全ファイルを閉じたかったのでそれはこんなん

Array.from( document.getElementsByClassName("file") ).forEach(e => {e.classList.remove("open"); e.classList.remove("Details--on")});

3/2 追記 作った

chrome.google.com

qiita.com

treviewにlorcaでGUIをつけてみた

前作った「GitHubのtrendingって面白いけど毎日同じのでがちだから今日の新着的なのだけみたいなー」と思って作ったやつに画面をつけてみました。

GitHub Trendingに毎日同じリポジトリがいるのを見たくないので俺がその日初めて見るリポジトリだけを見るためのツールを作った - チョキチョキかにさん

インストールとかはGitHubからです。とりあえずmacosの64ビットのバイナリしかないです。

github.com

画面はこんなんです。余白が多いのでなんとかしたい。

f:id:inabajunmr:20190211003059p:plain

技術とかの話

Lorca

Lorcaを使いました。 github.com

めちゃくちゃ雑にいうとElectronみたいな感じで画面作れてさらにJSの関数にGoの関数をバインディングできるやつです。 ただし

Unlike Electron it doesn't bundle Chrome into the app package, but rather reuses the one that is already installed.

です。 HTMLだけ書けばあとは雰囲気でCLIGUIにできる気がします。 データの受け渡しはJS->Goは勝手にJSONをオブジェクトにマッピングしてくれて、逆はJSONで受け渡しができます。

JSからGoはこんな感じでGoからJSはこんな感じでした。

静的コンテンツ込みのビルドがよくわかんなかったのでゴニョゴニョしたらできたのでそっちはQiitaにあげました。

qiita.com

ロスコンパイルはよくわかんないというか手元で起動できなくてどっちにしろテストできないので一旦やめました。workspaceとかを使えばいいという説もあります。

Vue.js

使ったけどなんか使った範囲ではわかったけど、って感じでなんとも言えない感じでした。ただまあ使った範囲では便利っぽい感じでした。 とりあえずAPIでとってくるデータとformの入力値を定義して前者はビューにバインドして後者はwatchでGoの関数を呼び出してました。それくらいしかしてないです。

今ふと「開発用のVue.jsでそのままバイナリをリリースしてしまった・・・」ってのを思い出したんですが全部HTMLに直接CDNで埋め込んでるのでビルドがめんどくさいですね。 この辺のフローとかはちゃんと学ばないといけない気がしました。

オンライン読書会のプラットフォーム

  • 本検索できる
  • 本の中に読書会リソースを登録できる
    • 読書会の中に参加者の概念がある
    • 読書会からDiscordか何かに飛べる
  • 本に感想とか進捗とか書ける

だいたいそんなイメージ

画面一覧

  • 技術書一覧
  • 技術書詳細
    • 開催中の読書会一覧がみれる
    • 読書会登録できる
    • 本の感想とか登録できる?
  • 読書会登録
    • タイトルとか詳細とか登録できる
    • スケジュール登録できる
      • 毎週金曜日19:00-20:00とか
    • 登録するとdiscordのリンクが払いだされる
  • 読書会詳細
    • discordのリンクとかタイトルとか詳細とか表示される
    • 参加するリンクから参加できる
    • 参加するリンクなしでいきなりdiscordでもいいけど参加人数とかは見れるようにしたい
  • あとはまあ普通のユーザ登録とか
    • GitHubログインだけでいいと思っている