かあちゃんエンジニアの気まぐれ開発メモ

フリーランス15年から足を洗ったかあちゃんエンジニアの技術メモ

Google App Engineの落とし穴

結論からいうと、
「フレキシブル環境に課金制限はありません。」
もう、この一言に尽きます。

お金の管理がどうにもずさんなかあちゃんです。
GAEでクラウドアプリを提供したいので、勉強していました。

GAEには、スタンダード環境とフレキシブル環境の2種類があります。
なにが違うかっていうと、こちらなどに詳しくあります。
GAリリース記念!!今更だけどGAE Flexible Environmentのチュートリアルを試してみた! | apps-gcp.com

Google App Engine Flexible と Standardの違い – SIer(業務系SE・PG)からWeb系への転職失敗反省録

柔軟に、自由度が高い、フレキシブル。


はい。

一番の違いは、料金!!!!


よくわからないで、
デプロイしまくっていたら(といってもデプロイがうまくいかず時間ばかりを浪費して動いてない)…とんでもないことに。

今月の請求12万っ!!!

え?
えっ???

かる〜く家賃超えてますけど。

管理画面の「お支払い」ページに、ちぃ〜さなメッセージカードが出てて。
「フレキシブル環境に課金制限はありません。」って書いてある。

電車の中で額見て…


課金制限はありませんでした

ありませんでしたっっ!!!

ありませんでしたっっっっ!!!!

※そそ。イエモンのあれね。

これがうかつだった。
1日あたりの利用料を設定していて、ノーチェックだった。
超えてんだってばとっくに。

まー、トーシロは手を出すなってこった(爆)

フリーランスがチームで開発するときに参考になる提言

かあちゃんエンジニアは、フリーランスで受託開発をやっているのですが。

大きな規模の案件は、とても一人で抱えられないので。
知り合いのフリーランスとチームで開発するようになりました。

お仕事に避ける時間にハンデがあるので、
どうしてもバリバリ単独で動けるエンジニアさんに頼ってしまうことになるのですが。
バグが出ると、どうしても犯人探し。そして計画通りに進まなくなると、モチベーションも落ち、ディスり合う空気がぷんぷんになって、心の病に陥る気配がしてくるのです。

在宅チームなので、コミュニケーションの不足はもちろんのこと。
対話が足りないのは明らかだなぁと、悩んでたらこんな記事に出会いました。

gigazine.net


全てのエンジニア、というか複数人でナニカ為したい方全てに響きそうです。

テーブルの入力欄を矢印キーで移動したいって

テーブル形式になっている入力欄。
エクセルみたいに、矢印キーで入力欄を移動したいやつ。

これは1行の入力欄の数が異なるケースでも動作するように、
単に1行分の入力indexでフォーカスするんではなくて、tdを数えて移動。

$(document).on("keydown", ".arrowable", function(e){

	var index = null;
	var selector = ".arrowable";
	var $this = $(this);

	// 直近の親要素tr 内にあるselector 要素の数を取得
	var parent = this.closest('tr');
	var index = $(selector).index(this);
	
	// thisのjQueryオブジェクトをjavascrptのDOMエレメントに変換する
	var domElement = $this[0];
	
	var distance = '';
	// SELECTボックスの場合はEnter, Shit + Enterで移動
	if (domElement.tagName == 'SELECT') {
		if (e.shiftKey) {
			if (e.keyCode == 13) {
				// Shift + Enterキーの場合は上↑
				distance = 'up';
			}
		} else {
			if (e.keyCode == 13) {
				// Enterキーだけの場合は下↓
				distance = 'down';
				
			}
		}
	}
	
	//  ↓ 下キー
	if ( (e.keyCode == 40 && domElement.tagName != 'SELECT') || distance == 'down'){

		// 最後のtrでなければ、次のtrの同じtd内にあるarrowableへフォーカス
		if ($(parent).next().length) {

			var nextTr = $(parent).next();
			// 同じindexのtdがあれば移動、なかったら移動しない
			var number = $(parent).find('td').index(this.closest('td'));
			var target = $(nextTr).find("td:eq(" + (number) + ")");

			if (target.find(".arrowable").length) {
				target.find(".arrowable").focus();
			} else {
				nextTr = $(nextTr).next();
				target = $(nextTr).find("td:eq(" + (number) + ")");
				if (target.find(".arrowable").length) {
					target.find(".arrowable").focus();
				}
			}
		}
		return false;
	}

	//  ↑ 上キー
	if ( (e.keyCode == 38 && domElement.tagName != 'SELECT') || distance == 'up'){
		// 最後のtrでなければ、次のtrの同じtd内にあるarrowableへフォーカス
		if ($(parent).prev().length) {

			var prevTr = $(parent).prev();
			// 同じindexのtdがあれば移動、なかったらさらに下の行へ移動てしてみる ※空の<tr></tr>対策
			var number = $(parent).find('td').index(this.closest('td'));
			var target = $(prevTr).find("td:eq(" + (number) + ")");

			if (target.find(".arrowable").length) {
				target.find(".arrowable").focus();
			} else {
				prevTr = $(prevTr).prev();
				target = $(prevTr).find("td:eq(" + (number) + ")");
				if (target.find(".arrowable").length) {
					target.find(".arrowable").focus();
				}
			}
		}
		return false;
	}

	//  ← 左キー
	if ( e.keyCode == 37 ){
		if (index > 0){
			$(selector).eq(index-1).focus();
		}
		return false;
	}

	//  → 右キー
	if ( e.keyCode == 39 ){
		if (index < $(selector).length - 1 ){
			$(selector).eq(index+1).focus();
		}
		return false;
	}
});

セレクト欄で下矢印が効かないと困るので、除外した。
でも要素がSELECTかどうかを判定する処理がjQuery でうまく動かせなくて、ネイティブjava script のElementで取得し判定。
なんかかっこ悪い感じだけど、やり方わからずやっつけ。
他の作業者から引き継いだソースで、空の行が入っているという怪しい状態。綺麗につくってあるテーブルなら、小手先の回避策は不要。 このあと、テキスト入力欄で左右の移動ができない問題が発覚し、 結局Enterキーとtabでの移動に修正するハメに。そうだよなぁ。なんできづかなんだ。 フロントエンジニアとして不覚....orz 下は、EnterKeyバージョン。

    $(document).on("keydown", ".arrowable", function(e){

        var index = null;
        var selector = ".arrowable";
        var $this = $(this);

        // 直近の親要素tr 内にあるselector 要素の数を取得
        var parent = this.closest('tr');
        var index = $(selector).index(this);

        // thisのjQueryオブジェクトをjavascrptのDOMエレメントに変換する
        var domElement = $this[0];

        //  ↓ 下キー
        if (e.keyCode == 13 && !e.shiftKey){

            // 最後のtrでなければ、次のtrの同じtd内にあるarrowableへフォーカス
            if ($(parent).next().length) {

                var nextTr = $(parent).next();
                // 同じindexのtdがあれば移動、なかったら移動しない
                var number = $(parent).find('td').index(this.closest('td'));
                var target = $(nextTr).find("td:eq(" + (number) + ")");

                if (target.find(".arrowable").length) {
                    target.find(".arrowable").focus();
                } else {
                    nextTr = $(nextTr).next();
                    target = $(nextTr).find("td:eq(" + (number) + ")");
                    if (target.find(".arrowable").length) {
                        target.find(".arrowable").focus();
                    }
                }
            }
            return false;
        }

        //  ↑ shift + enterキー
        if ( e.shiftKey && e.keyCode == 13 ){
            // 最後のtrでなければ、次のtrの同じtd内にあるarrowableへフォーカス
            if ($(parent).prev().length) {

                var prevTr = $(parent).prev();
                // 同じindexのtdがあれば移動、なかったらさらに下の行へ移動てしてみる ※空の<tr></tr>対策
                var number = $(parent).find('td').index(this.closest('td'));
                var target = $(prevTr).find("td:eq(" + (number) + ")");

                if (target.find(".arrowable").length) {
                    target.find(".arrowable").focus();
                } else {
                    prevTr = $(prevTr).prev();
                    target = $(prevTr).find("td:eq(" + (number) + ")");
                    if (target.find(".arrowable").length) {
                        target.find(".arrowable").focus();
                    }
                }
            }
            return false;
        }

        //  ← shift + tabキー
        if ( e.shiftKey && e.tabKey ){
            if (index > 0){
                $(selector).eq(index-1).focus();
            }
            return false;
        }

        //  → tabキー
        if ( e.tabKey && !e.shiftKey ){
            if (index < $(selector).length - 1 ){
                $(selector).eq(index+1).focus();
            }
            return false;
        }
    });

データベースに作成日時、作成者とかを自動で入れたいのだ

MySQLの5.6から更新日時は自動で入れられるようになったみたいですね。

へぇ〜便利。
MySQL5.6.5からDATETIME型で行生成時刻と更新時刻を自動でセットすることができるようになりましたよ

んで、さっそくSpring Bootで実装。
JPAツールでテーブルからEntityを自動生成。
作成日付設定せずに、Insert してみたらおこられた。
やっぱ値は入れないとだめなのだわ。ちぇ。


テーブルの作り方はここを参考にさせていただきました。
Spring JPAでCreatedTimeとUpdatedTimeを自動設定する | エンジニアっぽいことを書くブログ


ぐぐってみたら、Spring Dataのアノテーションを使うと、更新日時・更新者など自動でセットしてくれるとのこと。あるんだ!
taka-2.hatenablog.jp


AuditingConfigクラスで、更新者のところだけカスタマイズが必要で、ログインID(Integer) に変更した。

java

public static class SecurityAuditor implements AuditorAware {
@Override
public Optional getCurrentAuditor() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return Optional.ofNullable(((UserInfo)principal).getPersonId());
}
}

Entityクラスには下記のアノテーションを追加します。

@EntityListeners(value = AuditingEntityListener.class)
クラス名のアノテーションに追加。
 
@CreatedBy
登録した人

@CreatedDate
登録した日

@LastModifiedBy
最終更新者

@LastModifiedDate
最終更新日



作成前、更新前などの永続化処理にフックして値を入れる共通クラスを作る、という方法もあったけどこっちのがスッキリしてて簡単だった。
フック処理については↓
Spring JPAでCreatedTimeとUpdatedTimeを自動設定する | エンジニアっぽいことを書くブログ

Hatena Blogデビュー

FBでがっつり技術系のことを書くと、なんかドン引きな空気を感じてしまって。
日々のお仕事で気づいたこと、発見したこと、どこかに残したいなーって思ってHatenaデビューしました。

さてさて、続けられることやら。
よろしくお願いしま~っす。