プログラマー定年まであと一年

34回目の誕生日を迎えてしまった。タイトル通り、プログラマー定年まであと一年。まぁ、今の職場にいる限りは、35歳どころか40歳になってもまだ余裕でコード書いてそうだ。そういったキャリアパスが用意されているわけじゃなくて、単に上が詰まっているからなんだけど。

このままでいいとは思っていないし、子供が幼稚園に行きだしたら家計が赤字転落しかねないので、なんとかしなければいけないのだが、仕事と子育てに忙殺されてなかなか思うようにいってない。一番望みのあったプライベートプロジェクトも結局ストップしてしまった。小遣い程度のお金ですら、稼ぐのは難しい。ビジネスを起こして家族を養っている人は凄い。 社員を養っている人にいたっては凄すぎる。

今の職場で急激に収入が上がることはまず無い。 かといって福岡で探してみても、今より良い条件の場所もそうそう無かったりする。「 住んでる場所が収入を決める」というのは誰のツイートだったか。 まったくその通りだと思う。

というかマネージャー経験が無い時点で転職は諦めている。 技術基盤チームみたいなことばかりやってたからな。 仕事内容自体はそこまで不満なくて、ただ今後のキャリアをどうしたものか悩んでいて、 とりあえずプライベートプロジェクトで何か当てる以外に、 今の状況を打開する方法が思いつかない。 詰んだ感があるな。

Azure App Services から Azure Database for PostgreSQL に接続できるようにする方法

Azure App Services のアウトバウンド IP を、Azure Database for PostgreSQLファイアウォール規則に追加する必要があるみたいだ。

Azure App Services のアウトバウンド ID は

  • [プロパティ] - [送信 IP アドレス]

で確認できた。4 つの IP アドレスが表示されているので、4 つすべてをファイアウォール規則に追加して、ようやく接続できるようになった。

まだプレビューだから仕方ない。正式リリース時には Azure SQL Database みたいに Azure 内部からの接続を許可するオプションが付くでしょ。きっと。

Spring Security を使って Basic 認証 を実装してみた

Spring Boot で実装している Web API に、Spring Security を使って認証を追加することにした。 最終的には OAuth にする予定だけど、今はまだ検証用のプロトタイプを作っている段階なので、とりあえず Basic 認証で。

まず build.gradle を修正して、Spring Security を追加する。

buildscript {
    ext {
        springBootVersion = '1.5.4.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
}


dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    testCompile('org.springframework.boot:spring-boot-starter-test')

    // Spring Security を追加
    compile('org.springframework.boot:spring-boot-starter-security')    
}

Basic 認証を組み込んだ、最小の Spring Boot アプリケーションがこちら。

package jp.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
public class BasicAuthExampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(BasicAuthExampleApplication.class, args);
    }
    
    @RestController
    public static class HomeController {
        @GetMapping("/api/goodmorning")
        public String goodMorning() {
            return "Good morning";
        }
        
        @GetMapping("/api/hello")
        public String hello() {
            return "Hello world";
        }
    }
    
    @Configuration
    @EnableWebSecurity
    public static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
            authenticationManagerBuilder.inMemoryAuthentication()
                .withUser("test_user").password("test_pass").roles("USER");
        }
        
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.httpBasic() // Basic 認証を有効にする
                .and()
                .authorizeRequests()
                    .antMatchers("/api/goodmorning") // /api/goodmorning は認証不要
                    .permitAll()                
                .anyRequest()
                    .authenticated(); // それ以外は認証必須
        }        
    }
}

Python の REPL で動作確認。

>>> import requests
>>> requests.get("http://localhost:8080/api/goodmorning").text
u'Good morning'
>>> requests.get("http://localhost:8080/api/hello").text
u'{"timestamp":1498106201915,"status":401,"error":"Unauthorized","message":"Full authentication is required to access this resource","path":"/api/hello"}'
>>> requests.get("http://localhost:8080/api/hello", auth=("test_user", "test_pass")).text
u'Hello world'

Spring Boot で Web アプリを開発する環境の構築メモ

Java で Web アプリを開発する場合、今なら Spring Boot が良さそう。早速、開発環境を構築してみた。

JDK のインストー

Java SE Development Kit 8 - Downloads

Spring Tool Suite のインストー

IDEIntelliJ IDEA。…と言いたいところだけど、先立つものが無いので、 Eclipse ベースの Spring Tool Suite(STS) をインストールした。

spring.io

マシンにインストールしてある Java は 64bit 用なのに、32bit 用の STS をダウンロードしてしまい、無駄に嵌った。

Gradle のインストー

ビルドツールは Gradle を使ってみたいので、Gradle をインストール。

Gradle Build Tool

Binary-only の zip ファイルをダウンロードして展開し、bin にパスを通しておく。

Buildship のインストー

STS から Gradle を呼び出せるようにするために、 Eclipse Marketplace から Gradle の Buildship をインストールする。

projects.eclipse.org

センターリバー

会社帰りに、ソラリアステージ地下2階にある『センターリバー』に行ってきた。昼休みに行ける距離ではあるけど、いつも並んでいるので、昼休み中に食べ終われる気がしない。今回みたいに夜行くのが安心。注文したのはもちろんハンバーグのセット。

サラダはドレッシングたっぷり。

コーンポタージュスープ。美味だった。

ライス。

ハンバーグは自分で好みの焼き加減に焼いて食べるスタイル。 ニンニクのソースをかけて食べてみたら、 口の中がニンニクの香りで満たされていると錯覚するくらいに風味と旨味があった。 これ食べた後で人にはとても会えない。

後半は鉄板が冷めてきて、なかなか思うように焼けなかった。 鉄板を温めてくれるサービスとかあるのかな。 この手のスタイルの場合、極みやみたいに焼き石で焼く方が良いんじゃないだろうか。 焼き石なら交換も容易だし。

関連ランキング:洋食 | 天神駅西鉄福岡駅(天神)天神南駅

金田屋

行橋市にある『金田屋』が福岡市に出店していた。ラーメンスタジアムにではなく、路面店を。 場所は博多座の裏、とり田の隣。 昼休みになんとか行ける距離だったので食べに行ってきた。

ラーメンとご飯と餃子のセットを注文。

ラーメンのスープはとてもクリーミーで、とんこつのポタージュスープのよう。麺との絡み具合は言うことなし。チャーシューは甘辛い味付けで、自分好みだった。チャーシュー麺にしても良かったな。餃子も記憶と変わらずジューシーでご飯が進んだ。3個ではとても食べ足りないくらいだ。

関連ランキング:ラーメン | 中洲川端駅呉服町駅祇園駅

一やのごはん

夕飯に定食が食べたくなって、 向かったのは春吉にある『一やのごはん』。 夜の部開店時間ちょうどに着くつもりが、 看板を見落としてしまい、結構先まで行ってしまった。 なぜ見落としたのか不思議だ。

魚と肉どちらにするか悩んだ末に、チーズ入りメンチカツ定食(750円)を注文。 チーズに惹かれてしまった。

チーズ入りのメンチカツは見た目以上に食べごたえがあった。 かかっているソースは単なるトンカツソースではなく、 甘口でデミグラスっぽい。 このメンチカツに良くマッチしていた。

500円の定食メニューもあったりして、 天神・渡辺通の周辺にある店の中ではリーズナブルな方。 ボリュームあるのでコスパ良し。 もっと天神寄りにあればランチに結構な頻度で利用しただろうな。

関連ランキング:おでん | 渡辺通駅天神南駅西鉄福岡駅(天神)