無名関数での再帰処理に使うことができた。擬似的な識別子として扱えることを利用できた。スマートな処理追加の解法とは関係なさそうだ。単純に関数名に引数を渡すように書くことで呼び出すが、それよりアドバンスな呼び出しをする関数が提供されている。argsArray)apply関数は、JavaScriptの関数オブジェクトが持っている関数なので、関数なら基本的に使用できる。使って参照するオブジェクトとなる。呼び出し先関数の引数を収めた配列これは、たとえばすでに配列になっているものを分解して引数として渡す手間を省いたり、既存の関数を非破壊的に上書きすることに使われる。クリックされた要素自体が入っていることが想定されるものである。第2引数として渡した配列長2の配列はそのまま呼び出し先関数の第1引数・第2引数となり、キモとなる演算(ここでは加算や乗算)が行われる。書かずに、呼び出し先変数で書くべきだろう。呼び出し先変数に渡すことはできなかった。引数として追加してやればよいが、そのためには既存の関数に引数の定義を追加しなくてはならない。使った処理は大したことない上に仮に呼ばれすぎでも問題はない処理なので、これで良いこととしてしまった。その先へ引き回す、というコードであることがわかった。章のように呼び出し先関数を修正することで対応した。コードリーディングを終えて確かに動的にハンドラを生成するためだったり重複コードをまとめるのにはこの手法は有効であると感じたが、読むのに時間がかかってしまった。引き回しは修正の難易度が高かった。中だったが、異なる呼び出し先をこれから呼ぼうという場所で書くは憚られ、結果として呼び出し先変数でも書けることがわかったので良かったが、気づいていなければかき混ぜてしまう修正になりかねなかった。確かにスマートな書き方だがメンテナンスが楽じゃないという点では微妙で、私がPMならレビューで弾く、そんなコードだった。コードリーディングをしていて、なんだこれって思ったのでまとめてみます。行うコードが見つかった。「二重否定」というよりは「否定の二重適用」というような挙動だった。毎度のことながらここまでは検索用の文なので、以降は日本人に戻ってカタカナで書きます。!!$foo;というようなコードを見つけた。2文字の演算子なので、一見比較演算子か論理演算子かと思ったのだが、コードの文脈上違うようだ。(bool)$foo;と同義のようだ。二重否定でboolean型へのキャストとなるのか二重否定は、このように置き換えられる。);否定を行う論理演算子を一度適用し、さらにもう一度否定している流れである。PHPではエクスクラメーションマークによる否定ではboolean型への暗黙的なキャストが行われ、boolean型にキャストされたものに対してもう一度否定をしてやることで、キャストしつつ元々の結果に反転させることで、遠回りにキャストを実現している。2回目の論理否定となる。"1"というような変換と似た、演算での暗黙変換を利用するキャストの手法である。PHPでの比較演算では、2つの変数の比較結果のbooleanを変数に押し込めたい時、どうすればよいだろうか。PHPでは比較演算の結果は必ず返却されるため、if文の条件式中で使うだけではなく変数に代入することもできる。$piyo);これらはすべて等価である。二重否定によるキャストは、単純に2つ書いただけでそんなことが可能であると知らなければ読めないので、いささか可読性に欠けると言える。他にスマートな書き方はないだろうか。以下は全て二重否定と等価の書き方である。true);もっとありそうだけど、思いつくのはこれくらい。三項演算子かな、と思う。論理積はスマートだけど、他に良い方法あるし、これをあえて選ばなくても、というくらいかな。リテラルへの適用ちなみに、$fooの部分はリテラルであってもよい。!!(1+2+3);ここで、ちょっとガチャガチャとやってみよう。PHPでは、0以外の数字、及び、'0'以外または''以外の文字列リテラルはtrueとなる。演算子で繋ぐことによって、整数リテラルを文字列リテラルに変換することができる。これと二重否定を絡めてみよう。bool(true)この通りたった3行で型がゴシャゴシャになるので、絶対にやるなよ!!!!!!そんなことしねえと思ったそこのお前!!!!!長いこと煮詰まったコードではこれらが分散して、たとえば$fooの初期化が120行目、リテラル変換が140行目、二重否定が170行目にそれぞれあったりするんだからな!!!!その間に煩雑なコードが追加されていったりするから$fooについて追うまで気づかないんだ!!!!!絶対にこの手の成長をする種を蒔くな!!!!!!!結論:どれ使ったら良いのこれはチームが採用している規約などに応じて変えるべきだとは思うが、規定がないのであれば、ボトムの実力に合わせるべきである。false;}が強いと思う。これは教科書みたいな技術書にも最初の方に書いてあるようなif文でしかないので。それ以上の実力があるなら、キャストかboolval()の利用。演算結果を変数に押し込めることを知っているレベルなら、三項演算子や論理積が強いと思う。見た目にもtrueとの演算であることがすぐわかり、そもそもtrueとfalseの文字列が出てくるのでgrepや目検にも強いという有用性がある。何らかの定数が導入されて比較対象を変える場合にも、明示的に比較演算子やtrueなどbooleanリテラルがコードに現れているとわかりやすい。二重否定は、それがシンタックスエラーではなく成立するということを知らない限り使えない局所的な知識なので、推奨はできない。なってしまうのか、ということをよく知らずに、ばかなことをしてしまったなー、という記事です。これは検索ワードのための文なので、ここから日本人になります。なにをしたのか前提マテビュービューマテビューのリフレッシュとロックリフレッシュ時のロック対策あるビューのFROM句にいるマテビューをリネームするとどうなるのか実際に何が起こっていたか解決したかったじゃあどうすればよかったのかなにをしたのかあるマテビューを作り、そのマテビューをFROM句とするビューを作った。そこで、ロジックで分岐させてどのビューを読むのか、というようなことをしていた。いう、SELECTすら許さない強いロックがかかる。それを嫌って、同じマテビューを2つ用意して交互にリフレッシュとリネームをしながら、常にリフレッシュしていないマテビューが存在するようにしていた。マテビューをFROM句とするビューがあるとき、そのマテビューをリネームするとビューはどうなるのか。実装時の私は、全く気づいていなかったのである。前提ここではサンプルとして、下記のような構成とする。商品テーブルで、名前とカテゴリ、値段を持っている。この話で重要なのはカテゴリだけなので、他はてきとう。商品マテビューのカテゴリごとにビューが作ってある。なんでだろうね?インデックス貼っとけば速いしviewじゃなくていいじゃんなんだけど、サンプルってことで許して欲しい。LOCKという強い排他ロックがかかる。リフレッシュ中は他からのSELECTを待たせることになる。大した事ないマテビューならよいが、10秒もユーザは待ってくれないので、対策が必要となる。リフレッシュ時のロック対策いろいろやり方はあるのだが、私がとったのは、2つのマテビューを交互にリフレッシュしていく方式。同じ構成のマテビューを2つ用意し、片方をリザーブとする。その上で、リフレッシュの際にはリザーブだけ更新し、リザーブとそうでない方をリネームで入れ替える。すると、ビジネスロジックから発行されるクエリは常にリザーブでない方をSELECTするため、ロックの対象にはならない、という方式である。これは具体的には、下記のようなクエリになる。tempは交代のためのただのプレースホルダなので、処理が終わればもう存在しない。次に同じ処理が走ると、下記のようになる。存在するサイクルとなる。これらをトランザクションに包み込んでしまえば、うまくいくはずだった。あるビューのFROM句にいるマテビューをリネームするとどうなるのかあたりまえの話だけど、ひも付けが変わる。category_id=1;をみると、先程のサイクル上にいるマテビューをFROM句としている。このマテビューがあのサイクルにのるとどうなるのかを、このFROM句に対応するマテビューに☆印をつけることで追いかけてみる。なってしまったのである。)どういうことかというと、マテビューがリネームされても、そんなマテビューないよってことにならないように、追跡してくれるのだ。あったりまえじゃ〜ん。他言語によるビジネスロジックからの読み込みはテーブル名による参照で、ビューからの読み込みは内部参照値によるものなのだ。ビジネスロジックからマテビューを検索するぶんにはこれでよい。ビューがこのマテビューを使う場合は話が違ったということだ。この流れを繰り返すと、このビューは、奇数回ではバージョンが上がらず、偶数回で一気に2段階バージョンが上がる奇妙なビューとなった。奇数回のリフレッシュは実質意味がない。その上、これがやっかいなのだが、偶数回ではビューが見てしまっているリザーブに対してそのままリフレッシュをしてしまう。実際には2回に1回発生していたことになる。悲しい以外の言葉がない。実際に何が起こっていたかなんか反映遅いよね2回連続でリフレッシュすると変わる気がするよくわかんないねえとりあえずこのマテビューに修正入るんで確認しますあ〜〜〜そういうことか!!!!!解決したかったとりあえず一旦の対策として、リフレッシュして3回リネーム後、改めてビューを再定義して、リザーブじゃないほうに紐付けるとしてみた。ハマってしまったのではないか、と予想している。幸いにもすぐロックは解除され、無限にガッチリハマってしまったというほどの事故ではなかったのだが、それは混雑具合に左右されうる話。すればよかったのかどうすればいいんですか?9.4以降にバージョンアップするそもそもマテビューをFROM句とするビューを作らないDB設計を最初からちゃんとするのどっちかが正解っていうか両方やるのが正解だと思う。うまくはいかないけど。パネルを追加・表示するまで月花です。Bracketsの拡張機能を作ってみたので、その話をします。最終的に搦め手になり、いろんな場所をいじったので記事が長くなるため、3つくらいに分ける。この記事では、Bracketsの拡張機能を追加し、機能が搭載されていないパネルを表示するまでとする。次の記事で機能の紹介をし、最後の記事で実際に拡張機能として搭載して完成するまでの話をする。Sierraにはアップデートしてないんですけど、多分動くと思う。なんか動画にしようと思ったけど、よくわからなかったので静止画です。BracketsからiTunesを操作することで、コーディングをしながら1画面で快適なミュージックライフをサポートする。音楽を全部詰めてぐちゃぐちゃなシャッフルをするタイプなので、ウィンドウ切り替えたりスマホいじったりで中断するのが嫌だったので。developer.apple.comこれまで、スクリプトやAutomatorからアプリを操作する場合はAppleScriptのみが対応していたが、JavaScriptでも書けるようになった。使ってみようかな、という動機しか無く、最終的にJavaScriptである必要はなくなった。当初は、BracketsはJavaScriptでできていて、かつアプリなので、横断してそのまま呼べるんじゃないかと思っていたが、そうはいかなかった。いうのも、Brackets自体がブラウザであるようで、エディタなどの機能はその上で動くフレームワークに過ぎなかった。あれば、ブラウザからローカルのアプリが動かせるというのはセキュリティ的に危険極まりないのでできるわけがなかった。そのため、搦め手で実装することにした。Brackets自体からでは無理だが、権限のあるユーザが、適切なスクリプトを動かせばよい。具体的には、mac標準のapacheでローカルサーバを建て、その中のPHPからJXAで書いたjsファイルを実行する。BracketsからこのPHPへは、ajaxによる非同期通信で行う。この流れであれば、サーバ上のバッチが動くのと同義になるため、動かせるはずだ。いうか、動かすことができた。基本的にはBracketsAPIのページを参考に組み立てていく。APIBracketsはJavaScriptのフレームワークなので、言語は全てJavaScriptとなり、画面上の全てはHTMLである。Chromiumで動いているようで、Chromeの開発者ツールとほぼ同じものが立ち上がった。呼べるので、変数ダンプもらくちんで非常に助かる。拡張機能の雛形のようなものを探してみたが見当たらなかったので、既存の拡張機能を拝借して、中身を書き換えることで実装するのが楽だと思う。ドキュメントとにらめっこして、作りたい拡張機能に必要なモジュールを追加したり、逆に削除していけばいい。ファイル構成はこんな感じになる。package.jsonで、これらはそれぞれ、拡張機能のメイン関数と情報定義を行う。公開しないのであれば、package.jsonは適当でいいんじゃないかと思う。公開するなら、説明文とかライセンスはキッチリ書こう。この内容が拡張機能検索画面に載ると思う。書くべきことここでは、紹介した画像のような、エディタの下にパネルを追加する形式の拡張機能を作る際に、どのような手順で何を書いていくかを説明する。次のようなフェーズに分ける。拡張機能のメイン関数となる。あるが、厳格モードが必要かどうかはよくわかっていないが、よほど汚いコードを書かざるを得ない場合でもない限り、厳格モードでもさほど問題はないだろう。内に収まっていると思ってほしい。依存モジュール読み込みフェーズまずは、これ移行の処理を行っていくために、Bracketsフレームワーク(以下このように呼称するが、正式な名称ではない)の必要なモジュールのインスタンスを確保する。APIこんな感じで、API辞書とにらめっこして、必要なものを読み込んでいこう。絞り込んでいけば、パネルの追加に必要な関数がわかる、という具合だ。そのページには、そのモジュールが依存しているモジュールも記載されているので、それも読み込む必要があるが、なくても動いたりする。テスト実行時に管理者ツールを起動しておくと、足りなかったときはエラーが出るので、それで潰していってもよい。設定読み込み・登録フェーズたとえば、パネルを開きっぱなしにして閉じて、再度開いた時に、この設定に状態を書き出しておけば、以前の状態に復帰できる。);必要な数だけ登録しておくとよい。この拡張機能の場合は、開いているか閉じているか、だけとなった。実際にパネルを開く際に、定義した設定に書き込んだり読み込んだりするので、今はどんな名前の設定を保持したいか定義するだけ。コマンド設定・登録フェーズユーザがメニューから何か選んで実行する際には、コマンドという形式で呼ばれてくる。今回はパネルを開いたり閉じたりするトグルコマンドを定義する。第三引数は、メニューが押下された際に実行する関数で、無名関数としてもいいと思う。次に、定義したコマンドをメニューに追加する。このアプリでは、Macでいうところの上部にあるあのテキストメニューと、エディタ画面の右端にあるアイコンメニューに登録する。いう名前のトグルボタンが追加された。テンプレート読み込みフェーズパネルやアイコンのデザインを定義するテンプレートやCSSを読み込む。htmlファイルにしてもいいし、DOMを作って叩き込んでもよい。);これはあくまでもテンプレートのため、動的に動く部分はJavaScriptでDOM操作を行い、表示していく。ボタン類以外は空の、構造だけのテンプレートでよい。標準で扱えるようなので、大規模になる場合はそれで実装するのがいいだろう。</div></div>この拡張機能では、こんな感じのテンプレートになった。でてきているけど、本筋ではないのでファイルツリーとかサンプルコードとしては記載しない。ディレクトリ作って、CSS追加で読み込むだけ。必須関数定義フェーズ前項までで、ようやく定義が終わり、ここからは実際にビジネスロジックを書いていく。このフェーズでは、今回の拡張機能に必須な関数を定義していく。なった際に呼ばれる関数を実装する。各種リスナーの定義を行っている。ユーザ関数で、詳しくは次の記事で扱うが、ここでは基本的にリスナーの定義・登録に留めるとスッキリすると思う。現在再生中の曲を取得する関数で、初回実行による初期化と5秒ごとのタイマー実行の定義を行っており、定義の範疇からは抜け出していない・・・と思っている。その後、アイコンメニューへのリスナー追加と、設定ファイルから前回の情報を読み出して、パネルを開いておく、ということをやっている。ユーザ関数定義フェーズ前項でいくつか呼び出していたような、独自関数の定義を行う。ビジネスロジックは基本的にここで書くべきだと思う。今回は下記のような独自関数を実装した。絡み、ややこしいので次の記事で詳しく話す。まとめここまでで、ビジネスロジックを抜きにして、ユーザ関数の定義やリスナー追加もふっ飛ばせば、とりあえずパネルが開くだけの拡張機能ができているはずだ。あとはガリガリビジネスロジックを載せていくだけとなる。SQL芸人としての活動のメモです。今回は、正規化された一対多のテーブルから、多の方を一行を連想配列のJSONにしながら、複数の行をJSONにする、入れ子構造のJSONを抽出します。結果的になんてことない単純なクエリになったのですが、割とパズル的に悩んでしまったので、残しておきます。3人の生徒に、それぞれに2回の試験があり、その合計6つの結果を生徒ごとに分割して描画したい、というシナリオで書いていきます。例では、PHPでHTMLを出力することにします。生徒ごとにまとめてさらに3回のループを行うか、ソートしてから、前のループと生徒IDが違えば閉じタグと開きタグを出力する、みたいなことになりますが、条件式多くて読みづらいです。生徒ごとにまとめるところまでSQLにやらせてしまいましょう。レコードの集約はJSONにすれば、言語に依存しません。理想の抽出結果アプローチ横に広がっている試験データを連想配列に集約する生徒ごとに連想配列にした試験データを集約する取れたレコードをPHPで扱うテーブル構造のサンプル例では、生徒テーブルと試験テーブル、そしてそれらを繋ぐ生徒-試験リレーションテーブルの3つのテーブルが存在しているとする。そこから、生徒テーブルを軸にして、生徒数分のレコードの中に、複数の試験をまとめて収めるJSONを書いていく。95なお、本来であれば試験名と日付も正規化するべきであるが、今回の話にはそれほど影響しないので、簡略化のために今回は正規化しない。95しかし、これでは、たとえばPHPでこれを処理する場合、愚直にやれば6回ループになり、テーブルならtrタグが6つできたりする。いうテーブルを描画するならそれでいいが、生徒ごとのブロックとして閉じタグを挟みたい場合に厄介となる。3つにどうにか収めるように配列を操作するループを別途書いたり、ソートしてから生徒が変わったかを検知するif文を書いたりしないといけないので、端的にいってクソである。{試験内容のJSON}こうなればよい。このJSONには、例でいえば、配列長が2で、その中には試験のデータをいれた1つの連想配列がはいっていればいい。3回のループで生徒ごとに区切りつつ、内部のループで2つの試験のデータを出力すればいいのだ。この条件に合う結果のJSONは、たとえばこうなる。}]"長くなったが、このJSONを作り、上のレコードを抽出することを目的とする。アプローチまず、これを実現するためには、2回の集約が必要となる。横に広がっている試験データを連想配列に集約する生徒ごとに連想配列にした試験データを集約する横に広がっている試験データを連想配列に集約するまずは、試験データを1レコードずつ連想配列に変換していく。次のステップで生徒IDを使うので、ここで生徒-試験リレーションテーブルをJOINして、生徒IDも含めてしまおう。{試験内容のJSON}(省略)このためには、json_agg関数を用いる。BYには生徒ID、試験IDを指定して、試験テーブルのデータを集約する。そのためのクエリは、単純に上記を落とし込んで、こうなる。ASCすると結果は、このようになる。すべてのカラムを出すしかないので、カラムを絞りたい場合は、サブクエリにするかWITH句で追い出しておく必要がある。ここで、当初の目論見とはことなり、連想配列が配列長1の配列に入ってしまっていることに留意しておく。BYに生徒IDのみを指定し、再度json_aggにかけてやればよい。postgresのjson_aggは内部でjson型を扱えるため、JSONの中に「JSONの形をしたstring」が入ってしまい、最終的にjson_decodeした結果をjson_decodeする必要がある、なんてことにならないようなツリー状にまとめてくれる。そのため、そこのところは考慮せず、単純にさきほどのクエリをサブクエリとして、json_aggをかけてやるだけでよい。student_id;これだけでよい。[{"exam_id":6,"exam_name":"期末試験","date":"2017-09-30T00:00:00","math_point":75,"japanese_point":85,"english_point":95}]]生徒3人と試験6回のデータが3レコードとなって収まった。SQLはここまでで、ここからはビジネスロジックのお話になる。ここでは、PHPで行うとするが、JSONなので言語には依存しない。取れたレコードをPHPで扱う想定仕様は、生徒ごとに開きタグと閉じタグを出力し、生徒ごとのブロックを描画するものである。入れたとすると、下記のようなPHPで扱う事ができる。//閉じタグ描画処理}以上で、postgresに仕事をさせ、PHPに楽をさせることができた。例では単純なものだったのでJOINが少なかったが、本来はもっと正規化してあるはずなのでサブクエリがごちゃつきがち。WITH句やviewに、いかにわかりやすく追い出すかが出来るSQL芸人になれるかどうかのカギである。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。