iPhone Xを買った
— Xア卜ノレ (@maretol) 2017年11月18日
買った。以下感想とかなんとか
買った理由
- 面白そうじゃん
- 発展途上デバイス大好き
- なんか面白そう
めっちゃ雑に言うとこんな感じ
で、この際だからApple Payとかそのあたりのサービスもがっつり使ってみて、というか端末を2台持ちからiPhone Xの1台運用に変更するかとも思った。
メイン端末としてiPhoneを使ってみた感想はこんな感じ
- 思ったよりアプリ少ない
- いろんなところのレスポンスは悪くない
- でもバグが多いっぽい。早速2回ぐらいバグった
- 片手操作モードないのつらい
- 縦長画面のおかげでバナー広告が結構うざくない
- マジで思ったよりアプリ少ない
Apple Payとかはまだ使ってないのでやんわりと
本当に感想としては思ったよりアプリ少ないの一言に片付く感じ。個人開発のハードル高いのかも。ちょうどいいTwitterクライアントアプリがないなんてiOSで思うとは思わなかった
公式アプリとかの供給は多いのでそういう面は困らない。あとゲーム。Unity製のアプリの動きがとてもいい。
とりあえずTwitterクライアントアプリがないので作る方向で考えつつある。作るとしたらXamarin for iOSで開発することになるかなー、とかビルドにMacいるよなーとか思ってる
MySQLの全部検索の設定で注意すべきところ
MySQLには標準で全文検索機能がある。分かち書きが必要とは言えワイルドカードで検索するよりよっぽどましなので使った方がいいケースも多い。
ただしこの全文検索機能は「検索文字の文字数が4文字以下はヒットしない」という条件がある。まあ高速化のためにはある程度考えるべきなのだろうが、英語ならともかく日本語では4文字以下の単語の比率が結構高いと思うし英語でもcatとかdogとか簡単な単語が引っかからないため、そのあたりは変更しなければならない。
で、ft_min_word_len
の値を1にして再起動、インデックスを張りなおしていざ検索したところ、なぜかヒットしない。
うんうん悩んで設定を見ていくと似たような設定にinnodb_ft_min_token_size
というのもあった。これはエンジンでInnoDBをつかう場合の検索条件らしく、外部キーの設定などでInnoDBを使っていたのでこれかと思いこちらの設定値を0にしたところうまくいった。
多くのfulltext関係の資料ではft_min_word_len
の変更で設定が変わると書いていたので勘違いした。ただ、もしかするとこちらの数値も変更する必要があるのかもしれない。とはいえいちいち変更して試すのがめんどいので申し訳ないが誰かやってまとめておいてほしい
GolangのAppEngineをデプロイしようとしたら失敗した。どうやらファイル名に日本語は使わない方がいいらしい
golang で AppEngine 開発してさあデプロイするぞ!とやったところエラーが出た。
PS > gcloud app deploy
Services to deploy:
(プロジェクト情報略)
Do you want to continue (Y/n)? Y
Beginning deployment of service [news]...
Some files were skipped. Pass `--verbosity=info` to see which ones.
You may also view the gcloud log file, found at
(出力されるログファイルの場所情報略)
#============================================================#
#= Uploading 0 files to Google Cloud Storage =#
#============================================================#
File upload done.
ERROR: gcloud crashed (UnicodeDecodeError): 'utf8' codec can't decode byte 0x82 in position 4: invalid start byte
If you would like to report this issue, please run the following command:
gcloud feedback
To check gcloud for common problems, please run the following command:
gcloud info --run-diagnostics
今までできてて突然できなくなったので変更した場所が悪いのかな?と思うもエラー内容(UnicodeDecodeError)はPythonのエラーらしく、どうやらgcloudコマンド関係がクラッシュした模様(gcloudコマンドはPythonで実装されてる)
とはいえアップデートなどもなかったはずなのでやはりこちらが何か変更したのが悪いはずと思いいろいろと試したところ、どうやらプロジェクトファイル内のドキュメント関係を入れたディレクトリに日本語名のファイルがあることに気づく。
以前のデプロイでは存在していなかったファイルの名前を日本語から適当な英語のファイル名にしたところ無事デプロイ成功
どうやら関係ないファイルでも日本語名のファイルがあると問題が起こるらしい。確かに文字コード関係のエラーだもんね。
なお環境がWindowsなので要はこれShift-JISで名前が入ってるらしくその問題もあるのかもしれない。今後気を付けよう
CircleCIでMavenを使ってGoogle AppEngineをデプロイするのを自動化したい
追記(2017-09-08)
解決してないのでググってたどり着いた人ごめん
タイトルの通り。
GAEのデプロイは2通りあって、appcfgを使うかMavenを使うか
Deploying a Java App | App Engine standard environment for Java | Google Cloud Platform
おススメ(recommended)なのはMavenらしいので、それを使っていたのだが、せっかくだし自動化したいなーと思ってCircle CIでデプロイコマンドに mvn appengine:update
をそのまま入れたところ、まあ当然なのだが認証が通らず止まってしまった。デフォルトではOAuthで認証してキーを取ってきてそれを入れると通るのだが、当然入力する場所はないのでどうしようもない。
というところで止まっている。お盆が明けたら再開予定……
可能ならサービスアカウントを登録させるか引数で渡すべきなのだと思う……
ちなみにほかのデプロイ方法ではどうやらgcloudコマンド用の設定がCircle CIに用意されているらしい。
追記(2017-09-08)
ようやく追記(タイトルもちょっと修正)
とりあえず結論は出来なかった。できなかったというよりわからなかったが近い。
サービスアカウントの情報を渡して認証させてもどうやら maven appengine
コマンドが読んでくれない。
認証関係のオプションを探してみたがそれらしいものはなかった。一応auth関係のオプションも探したがそれらしいものも見つけられなかった。
pythonコマンドを用いたデプロイやらコンテナベースのサービス?なら手段もそれなりにあるっぽいが、残念ながらわからないというのが実情。むなしい
値を返してから代入する
ちょっと前にTwitterで人が死ぬバグといって流れてきたツイートがそれなりに話題になっていたと思う。
人が死ぬバグってあるんだな...今まで平和なプログラミングしかしたことないや。https://t.co/8EtfrW0pvp pic.twitter.com/zF9ZNLfUtu
— Daiius (@DaiiusJmst) 2017年7月17日
これね。出典元は 非推奨だった bool 型に対するインクリメント演算子を削除 - cpprefjp C++日本語リファレンス
これは古いCのコードをもとにしていて、かつ当時はbool型もなかったのでこうなっていたようだが、配列の要素を並べて表示し、それぞれの要素間に,
を表示するといったパターンではおそらく昔はよくあったコードだと思う。
この「配列の要素を並べて、各要素間にはコンマをうって表示する」というケースに類似した処理はよくあるものだと思う。
地味に面倒なことに、この場合「最初は飛ばすがそのあとからは毎回つける」というパターンで記述することが多い。
で、その場合(下のコードはJava)
boolean first = true;
for(Object obj : objList){
if(!first){
System.out.print(",");
}else{
first = false;
}
System.out.print(obj.toString());
}
みたいなコードが必要になったりする。
はっきり言って面倒である。
ちなみにC++では上のリンクであるように昔はインクリメントがあった。bool型(boolean型)のインクリメントはJavaにはないし、C++も今はない。
後述するがインクリメントははっきり言ってわかりにくいものなので最近だとSwiftでは方にかかわらずインクリメント自体がなくなった。
ではこのインクリメントなしで書くにはどうするか、というと、まあ上のように一つフラグを用意してあげてとなるのだが、C++では割と便利な関数ができていた。
それがstd::exchange
というので、std::exchange - cppreference.comにある。
これは「値を返してそのあと代入する」というものである。
ただこれはJavaにはない。Javaにそんな便利なものがあると思ったら大間違いだ。欲しければ作れ。という感じでこんな感じになるだろうか
public class Exchanger<T>{
T value;
public Exchanger(T value){
this.value = value;
}
public T get(T newValue){
T oldValue = value;
value = newValue;
return oldValue;
}
}
使うときはこう
Exchanger<Boolean> first = new Exchanger<Boolean>(true);
for(Object obj : objList){
if(!first.get(false)){
System.out.print(",");
}
System.out.print(obj.toString());
}
ちょっとはキレイになった。
問題点はJavaなんでプリミティブ型が使えないこととか、Integer型のときに +1 で回せないという点あたりか。後者の問題はそのままの値を返すget()メソッドで値を取って+1したものをnewValueとしてget(T newValue)に渡す感じにするだろうか。ジェネリクスを使う以上あまり入り込んだ処理は行いたくない。
いずれにせよJavaだと面倒。ほかの言語であればだいぶ楽(C#とかならLINQ使ったりできるかもしれない)なので調べる価値はあるはず。
ところでインクリメント(と、デクリメント)について。
いわゆる++
だが、先述の通りはっきり言ってややこしい。i++
と++i
の違いなど意識していては可読性が下がるしバグの温床になりかねない。
SwiftではSwift2からインクリメントとデクリメントがなくなったし、正直forループの処理以外で使うこともほとんどないだろう。可能な限り使わないに越したことはない。
C++の場合演算子オーバーロードでは前置か後置かの判定で描き方も面倒になっている。ついでに言うと += などの書き方も正直あまりいい物ではないと思う。
省略することが良いとは限らないし、現在なら基本はすべて記述すべきだと思う。
追記(2017年11月24日)
文字列を合体させて要素の間にコンマを入れたいケースとかは String.join() とかつかうといいよ(なおJavaは8以降にしかないらしい)
こういう多数の人間が必要になりそうな機能はだいたい供給されている(たまにされてない)のでAPIをどんどん調べていこうと思った
コンストラクタの引数がいいのか、setterを使った方がいいのか
クラス変数やメンバ変数を置くとき、当然その変数に何らかの値を入れるものである。
で、その変数になにか値を入れるタイミングはコンストラクタで入れるべきなのか、それとも呼び出しもとでsetterを呼び出して入れるべきなのか、どちらがいいのかわからなくなった。わからないなりになにか文章に直そうと思ってこの記事を記す。
わからないので、もしこの記事で「バカジャネーノ」とか思った方がいれば教えてほしい。教えて。
コンストラクタで渡す場合
要は
Object obj = new Object(hoge);
みたいなケースである。
これが強制されるケースはJavaであればfinal
修飾子を、C#であればreadonly
修飾子を付けた変数はコンストラクタで値を決めるか、変数宣言時に値を決定する必要がある。ちなみにC#のconstは宣言時に値を決定しなければならない。
逆に言えばコンストラクタで値を決定できるともいえる。
メリット
- setterを作らないことでクラス変数やメンバ変数のアクセス制御ができる
- 呼び出し側に記述を作らない(ケース次第)
setterで渡す場合
コードに直すと
Object obj = new Object();
obj.setHoge(hoge);
というケース。
これコンストラクタが強制されるケース以外特に制限はない。
メリット
- setterで制限や値の調整ができる
- 呼び出し側に記述を作る(ケース次第)
- 外部からの値の操作ができる(あんまりよくない)
比較
各々のメリットの欄に書いたが、呼び出し側に記述を作ることが場合によっては良かったり悪かったりする。
例えばゲームプログラミングで敵キャラを生成するときにHPなどの各ステータスをいちいちsetterで渡すのは正しいとは言えない(もっともこの辺は敵の種類を渡したら一発で処理できるようにすべきだし、そうであってもコンストラクタに渡せばいけるはずである)
Enemy enemy = new Enemy(enemyType);
// もっと正しくするにはcreateEnemy(enemyType)とかFactoryパターンやBuilderパターンを使うべきだと思う
こういったケースならコンストラクタに渡すべきだろう。
また、逆に言えば呼び出し側が呼び出すべき内容であればsetterでおくべきだということである。
外部からの操作に関していえば、setterであっても制限もできる。
void setHoge(Object hoge){
if(hoge!=null){
this.hoge = hoge;
}
}
とすれば、nullでない場合だけ入るという形にできる。要は値が設定されていない場合だけ入るという形で、あとから外部で値を変更するというのは通じないことになる(どこかでnullになるような処理でない限り)。
総括
もっと言えば、極論はコードの書き方次第だしある程度の思想が統一された状態で書けばどちらでもいいのだと思う。
思うのだが、いかんせんなんかいい感じの資料とかもないのでいまいちどうやればいいのかわからないという感じはする。
Java Servlet ではPOSTでステータスを受け取れるContentTypeはapplication/x-www-form-urlencodedだけ?
ServletRequestインターフェースのgetParameter()メソッドでパラメータを取り出すとき、GETはできるのにPOSTにした瞬間うまくいかないことがあった。
理由を調べたところ、getParameter()あるいはそれに類する処理をPOSTメソッドのRequestからの場合、content-type=application/x-www-form-unlencoded でなければ読み込めないらしい。
ちなみにgetInputStream()とかを用いて生のデータを読めば別にこのメソッドを使わなくても読めるらしい。つまりBody部に入っているが、パース出来ないか読めないか読まないかそんなところのようだ。 ただしgetInputStream()とかとgetParameter()を併用するとデータがおかしくなることもあるとか。
もともと(というか本来?)POSTはフォームの入力のデータを扱う場合に使うことが多いからその影響かもしれない。もしServletでWebAPIみたいなことしたい、POSTでデータ送信したいってケースで引っかかることがあるかもしれない。
application/json や text/plain なども通らないってのはちょっとつらい。JSONはまあはやってる割に素で対応できる環境が少ないからまあいいけど、うーん。
まあapplication/x-www-form-urlencodedに偽装して送り付けるのが一番楽かな
参考資料
HttpServletRequest (Servlet 2.4 API 仕様)
厳密にはServletRequestインターフェースに実装されてるのでこっちだけど
ServletRequest (Servlet 2.4 API 仕様)
これのgetParameter()に書いてる