皆さんこんにちは。株式会社コスモルートでアンドロイドアプリの請け負い開発をしているT.Mです。
僕自身コスモルートは2社目で、前職はAndroidアプリの開発や機械学習の業務を行っていました。
その後コンサルタントとして入社後、2年程上流工程を経験してます。
なので仕様変更に対する上流と下流(そもそもこの呼び方が良くない笑)のせめぎ合いや、「これ要件に書いてないですよ?」や「そもそも要件というより前提だよね?」といった喧嘩会議を両側から経験してきました。
要件定義で完璧に仕様が決まり、未来永劫変更が無い—そう断言できれば安心して開発ができます。
しかし実際のところ、プロジェクトは生き物のように変化し、仕様が固まるということは殆どありません。
選択肢は2つ。
1:「仕様が確定しないのが悪いんだ!」と悪態をつく
2:プロジェクトの変化に柔軟な開発を目指す
あなたはどちらを選びますか?
1.Android/Kotlin再入門
この章ではAndroidをJavaでしか書いたことが無い人向けのKotlinの紹介と、僕のように数年開発現場を離れていた人向けのアップデート事項をまとめました
1.1 Kotlinとは?
もともとAndroidアプリの開発にはjavaが必須でしたが、2019年でのI/OではKotlinを第一言語とし、公式サポートもこれまで以上に充実させるとしました。
言語的な特徴はいくつかありますが、中でもnullを上手く扱い、エラーを発生させにくい仕組みが受け入れられました。
まずはそれをお定まりのHelloWorldで見てみましょう。
| val str:String? = null print(str?:”Hello world”) |
`?`が沢山みえますが、これがnullを管理する印です。
具体的には`String?`で定義された変数は**String型**と**null**を許容します。
これはjavaの**String**に相当します。
2段目の`str?:”Hello world”`は**str**がnullの場合、**Hello world**を出力するよという意味です。
一般的にはnullをなるべく除外したいので、?はあまり使いたくありません。
Javaから受け取った値をKotlinに渡す場合や、サーバーからのレスポンスでnullが入り込む場合などは`Type?`で変数を定義します。
変数がnullでない時のみ、関数を適用したい場合があります。
そういう場合は`let`関数がおすすめです。
入力されたパスワードが正しいか判定する場合は、
|
と書けば、`if(input!=null) … else …` のような条件式は不要で、簡潔に記述できます。
1.2 変数の定義方法
変数の定義の仕方について触れておきます。
javaでは変数は2種類で、代入可能なもの(可変変数)と不可能なものです。
kotlinも同じく可変変数と不変変数があり、それぞれ以下の様に定義します。
| val str = “Hello, world” //不変 str = “Hello, kotlin” // 代入不可能なのでコンパイルエラー var str2 = str str2 = “Hello, kotlin” //エラーにならない |
kotlinに限った話ではないですが、なるべく不変変数を使うようにしましょう。
たとえばユーザーの生年月日を定義する場合、`var birthday:LocalDate`とはしないはずです。
見た目は若くできても実年齢は変わらないので、不変であるべきです!
一方で、例えば「パスワードを変更する」や、「パスワードを再登録する」などのユーザーアクションが考えられるので、パスワードは可変です。
| var password:String |
ですね。
同様にニックネームや好きな食べ物などの情報は可変、生まれ故郷や性別は(特別な事情がない限り)不変として良いでしょう。
これで変数の定義方法については終わります。
ただし`var password`には少々問題があります。
このままだと、`0000`や`cosmoroot`のような安易なパスワードが入力される恐れがあります。
そこで、登場するのがjavaでお馴染みのsetter/getterです。
1.3 変数のカプセル化(setter/getter)
例えば開発要件として、**パスワードは4文字以上8文字以下とする**と書いてある場合はどうしますか?
更に**パスワードは暗号化してサーバーに送る**という要件も追加されました。
そこで役立つのがsetter/getterというカプセル化の概念です。
実際にkotlinのコードを見てみます。
| var password:String? = null set(newPass:String?){ // 4~8字以内の場合は val withIn:Boolean? = newPass?.let{IntRange(4,8).contains(it)} //newPassを代入 if(withIn) field = newPass } get = hashed(field) //Hash化関数 password = “password” print(password) // Hash化されたパスワードが出力される password = “tooLongPassword” print(password) //条件に満たさない場合は、nullが出力される |
コード内コメントにある通り、**4文字以上8文字以下**の条件を満たさない場合は代入できませんし(setterによる入力の制限)、出力はHash化されます(getterによる出力の制限)。
ただし、まだ`null`が残っていますね。
改善の余地がありますが、次のクラス定義にまわします。
1.4 クラス定義
上で見てきたユーザー情報はクラスにすることができます。
例として
– ユーザーID
– パスワード
をもつ`User`クラスを定義しましょう。
kotlinでは
| //Userクラス定義 uidは不変 class User(val uid:String,var password:String) val user:User = User(“cosmoroot”,”password”) print(“$user.id”) // cosmoroot と出力 |
と書けます。
javaと雰囲気が似てますが、クラス変数`uid`および`password`をコンストラクタで定義できるのが便利ですね。
更にpasswordは勝手に変更されては困るので、改良します。
| class User(val uid:String,_password:String){ var password:String = _password set(newPass:String){ val withIn:Boolean = IntRange(4,8).contains(newPasss) if(withIn) field = newPass } get = hashed(field) //Hash化関数 } val user = User(“cosmoroot”,”password”) user.password = “tooLongPassword” //無効なパスワードを代入しても print(user.password) //passwordと出力 |
クラス化によってpasswordはUser生成時に指定すればよいので、`null`は削除できました。
ただし、Userクラスにしたので、パスワードはsetter/getterで定義するよりも、**changePassword**関数を定義した方が分かりやすいですね。
| /*** @param _passowrd:パスワード private変数もコンストラクタで定義できる。クラス外からは参照されない。 */ class User(val uid:String,private var _password:String){ fun changePassword(newPassword:String):Boolean{ return if(IntRange(4,8).contains(newPasss)){ _password = newPassword true }else false } } val user = User(“cosmoroot”,”passoword”) user.changePassword(“tooLongPassword”) // return false |
とてもシンプルになりました!
また`changePassword`メソッドを定義したおかげで分かりやすくなりました。
まだまだ続けたいところですが、長くなってきたので、今回はこのあたりで終わりにします。
最近はKotlin関係のオンラインのコースもかなり充実していますし、サンプルアプリの実装例がgithubに載っているので、それを元に勉強するのもおすすめですよ。
次回は「プロジェクトの変化に対応する」を予定しています。
お楽しみに。