IM-Workflowの案件状態を判定する方法

intra-martでIM-Workflowの案件状態を判定する方法を紹介します。

IM-Workflowの案件情報を取得する際、案件の状態によってAPIを使い分ける必要がありますが、対象の案件の状態が「未完了」か「完了」かがわからないことがあります。

その場合、案件状態マネージャ (UserMatterStatus) を使用することで、案件状態ごとに処理をわけることができます。

案件状態による処理分岐の実装

以下ソースです。

案件状態マネージャ (UserMatterStatus) で案件状態を取得して、案件状態ごとに分岐し、APIを適切に使い分けています。

// 案件状態を取得する
String searchLevel  = "1";// "0":未完了案件のみ検索、"1":未完了/完了案件を検索、"2":未完了/完了/過去案件を検索
UserMatterStatus userMatterStatus = new UserMatterStatus(searchLevel);
UserMatterStatusModel userMatterStatusModel = userMatterStatus.getMatterStatus(systemMatterId);
String matterStatusCode = userMatterStatusModel == null ? null : userMatterStatusModel.getMatterStatusCode();

// 案件状態による分岐
if (MatterStatus.matSts_Active.toString().equals(matterStatusCode)) {
    // 未完了案件の場合
    ActvMatterNode actvMatterNode = new ActvMatterNode(systemMatterId);
    //…処理
} else if (MatterStatus.matSts_Complete.toString().equals(matterStatusCode)) {
    // 完了案件の場合
    CplMatterNode cplMatterNode = new CplMatterNode(systemMatterId);
    //…処理
}

ここでは未完了/完了案件を対象としていますが、処理対象の案件を変えたい場合(過去案件も含めたい場合など)は、案件状態マネージャ (UserMatterStatus) のコンストラクタのパラメータ「searchLevel」を変更してください。

intra-martとkintoneを連携してみる

ワークフロー(intra-mart)の申請データをアプリ(kintone)に連携させてみました。

intra-martのLogic Designerとkintone REST APIを使い、ノンプログラミングで実現することができました。

今回はその際の手順を整理したいと思います。

やったこと

f:id:hamaguchiyu:20190628175059p:plain

1. kintone

1.1. kintoneアプリをつくる

kintoneのアプリを作ります。

f:id:hamaguchiyu:20190628165235p:plain

アプリのAPIトークンを生成します。アクセス権にもチェックを入れておきます。

f:id:hamaguchiyu:20190628180518p:plain

2. intra-mart

2-1. 申請画面をつくる (BIS)

BISでフォームを作成します。 f:id:hamaguchiyu:20190628180954p:plain

2-2. REST定義をつくる (Logic Designer)

Logic Designerの [ユーザ定義] > [REST定義新規作成] からREST定義を作成します。

入力値には下記を設定します。

  • apiToken、domain、app ・・・ kintoneに接続するための情報
  • record ・・・ kitoneに登録する情報 f:id:hamaguchiyu:20190628181335p:plain

リクエスト情報・レスポンス情報を設定します。 上記の入力値で定義した「domain」「apiToken」を使用して、エンドポイント・リクエストヘッダを設定します。

f:id:hamaguchiyu:20190628181456p:plain

2-3. ロジックフローをつくる (Logic Designer)

[ロジックフロー定義一覧] からロジックフローを新規作成します。

フローには上記で作成したREST定義(kintone_register1)を設定します。

f:id:hamaguchiyu:20190628182616p:plain

入出力設定、定数設定の設定を行います。

入力出力設定には申請画面の入力値(textbox1)を定義します。

定数設定にはkintoneの接続情報(apiToken、app、domain)を定義します。

f:id:hamaguchiyu:20190628182640p:plain

REST定義に入力、定数の値をマッピングします。

f:id:hamaguchiyu:20190628182657p:plain

2-4. 案件終了処理を設定する (BIS)

BISで [外部連携] > [データソース] よりデータソースを作成します。フロー定義には上記で作成したロジックフローを指定します。

f:id:hamaguchiyu:20190628182747p:plain

BISの[フロー編集]から、上記で作成したロジックフローを案件終了処理に指定します。

f:id:hamaguchiyu:20190628182815p:plain

以上で設定は完了です。

3. 実行結果

intra-martのワークフローを承認して案件を完了させてみます。

無事にkintoneアプリにintra-martのワークフロー申請情報が登録されました。

f:id:hamaguchiyu:20190628182928p:plain

Logic Designerとkintone REST APIを使えば、intra-mart x kintone連携も簡単に実現できますね。

AsciiDocの良いところ

開発部のS.Kです。 AsciiDocについて少し調べてみたので、共有してみたいと思います。

AsciiDocとは?

AsciiDocは、軽量のマークアップ言語です。 Markdownを知っている方は、それとよく似た言語と考えていただければ、分かりやすいと思います。 知名度で言えばMarkdownの方が圧倒的に高いですが、AsciiDocにはMarkdownには無い機能がいくつかあります。

AsciiDocの利点

表の幅広い記述・表現が可能

AsciiDocは表を色々な記法で記述できます。 Markdownと同じような罫線風の記述も出来ますし、csvのようなカンマ区切りの記述も出来ます。 表示に関しても、セル内での改行やセル結合も可能です。 Markdownでも表は描けますが、あまり細かい記述はできません。

外部ファイルを文書内に埋め込める

include構文を使うことで、外部ファイルを文書に埋め込むことができます。 これは画像の埋め込み表示とは異なり、AsciiDocで書かれた文書をその位置に差し込むように利用することが出来ます。 これを用いることで、複数の文書で共通する記述を共有したりできます。 また、エクステンションを追加すればplantUMLで記述したUMLを表示することもできるので、そういったものを読み込むのも効果的です。

まとめ

AsciiDocを総評すると、Markdownをより高機能かつシステマチックにした感じの言語です。 Markdownで文書管理したいけど機能が少し物足りない、という方はAsciiDocも検討してはいかがでしょうか。 AsciiDocを記述する専用テキストエディタとしては、AsciidocFXなどがあります。 それ以外にも、Atom, VSCode, SublimeTextなどの有名エディタに拡張機能がそれぞれ存在するので、試してみるのも良いと思います。

初心者の小石_データベースとストレージの関係

はじめに

お久しぶりの投稿となります、G.Mです。
まだまだ寒い日が続きます。関東でも積雪があり、この時期に入ってもまだまだ厳しい冬が続きます。
皆さま、日々業務や学業がお忙しいところかとは存じますが、体調管理は万全にしていきましょう。

今回は表題の通り、intra-martにおける『データベースとストレージの関係』についてご紹介させていただきます。intra-martにおいては基本的な内容であり、公式ドキュメントにも記載されてはいるのですが、非常につまづきやすい内容だと個人的に思っており、今回取り上げようと思い立ちました。

データベースとストレージの概要

まず、データベースとはなに? ストレージとはなに? というあたりについては、皆さますでにご存知と思われます。もし理解できているかどうか自信がないという方は、この機会に押さえておきましょう。

intra-martにおいても、もちろんデータベースとストレージは利用されています。そこで、いったい何につまづきやすいのかというと、それらの関係性を見落としやすいという点です。

多くのシステムにおいて、必要な情報はデータベースに保管することでしょう。実際にintra-mart環境を構築するにあたっても、PostgreSQLOracleSQLServerといったデータベースを用意していると思われます。

では、ストレージについてはどうでしょう。intra-martをセットアップする際に保存先を指定するのですが、デフォルト指定のままでも問題なく動作するため、あまり意識していない場合があるかもしれません。
というより、intra-martに初めて触れ、とりあえず環境を構築してみようと試みている方々の大半は、まったく意識していないのではないでしょうか。

データベースとストレージの関係

データベースとストレージの関係性を見落としやすい、と前述しました。実は、intra-martにおいてデータベース(テナント)とストレージは原則1対1の関係になっています。intra-mart上のデータを、データベースとストレージそれぞれに分割して保存している、というイメージです。

データベースとストレージ
データベースとストレージ
つまり、もしもデータベースの中身を削除して新しい環境を作りたいと思ったなら、ストレージも完全に削除し、新しく作り直す必要があるわけです。

ストレージの存在を意識していないと、そのことを見落としてしまいます。
環境を再作成するのに、データベースは削除したけれどストレージはそのままだとか。
環境を別にもう一つ作ろうとしているのにストレージの保存先を変更せず、2つの環境から同じストレージを参照してしまっているとか。
現環境を別の環境に移行するにあたり、データベースの中身は移したけれど、ストレージを移していなかったとか。
そうして、システムが起動しなくなってしまった、ワークフローのデータが表示されなくなってしまった、よくわからないけど何かがおかしい、という事態に陥った経験をお持ちの方は多いのではないでしょうか。

マニュアル通りにやったのに壊れた
マニュアル通りにやったのに壊れた

実際にどのデータがデータベースに保存され、どのデータがストレージに保存されるか、というのをすべて洗い出すのは非常に困難です。
また、intra-martのバージョンが進むことで、保存先が変更されたり、設定で任意に変更できるようにもなっています。たとえば、ワークフローについては下記を参照してください。

https://www.intra-mart.jp/document/library/iap/public/im_workflow/im_workflow_specification/texts/setting_guide/setting_list/tenant_unit/setting_guide_18.html

もちろん、大切なデータがどこに保存されているかを把握しておくのは大事なことです。しかし、とにかく覚えておかなければならないことは、データベースとストレージは対になっている、という一点です。これを忘れないだけでも、環境構築における事故はぐっと減るのではないでしょうか。
少なくとも、現場に新規参入した新人社員さんなどには、まず先に教えてあげたい内容ですね。

テナントが複数あったり、バーチャルテナントを利用していたり、あるいは分散環境だったり。場合によって、データベースとストレージの関係もかなり混み行ってきます。ですので運用にあたっては、この2つの扱い方を明確にしておくことを強くお勧めします。

おわりに

私が初めてintra-martに触れたとき、その環境セットアップにとても苦労したことを覚えています。
何度も失敗し、原因不明のエラーに悩み、しばらくそうしているうちにようやく、仕組みが分かるようになっていきました。
そういった経験やノウハウはぜひとも形に残して、後続の人たちの手助けとなることを祈ります。

受け継がれるナレッジ
受け継がれるナレッジ

新年度もあと少し。4月入社する新人さんたちには、少しでも早く実力をつけ、私に楽をさせて欲しい会社に貢献できる人材に成長して欲しいですね!

JDK11へのバージョンアップについて

開発部のS.Kです。 だいぶ久しぶりの投稿となります。

今回はJDKの移行で少々苦戦したので、その話を少々。 OracleJDKのリリースサイクルを変え、長期サポート版が無償では公開されなくなるという話題が、ずいぶん前からありました。 実際に、OracleJDK8の無償公開版の更新は、先月(2019年1月)で停止しています。 そのため、OpenJDK11への移行を行ってみました。

所感としては、OracleJDKからOpenJDKにすることでの問題はあまり無さそうです。 ただ、そもそもJDKを11へバージョンアップするというところでは、色々と気をつけなければいけない感じです。

JDK11では、非推奨となっていた様々なモジュールが削除されています。 個人的に一番影響がありそうに思えるのは、JAXBでしょうか。 スキーマが定義された設定ファイルを、Javaプログラムから簡単に読み書きするためのモジュールです。 JDKに同梱されなくなっただけなので、別途追加することも出来るのですが、そうするとクラスローダー絡みと思われる問題が起きることがありました。 これまではJava本体と同時に読み込まれていたクラスが、もう少し後のタイミングで読まれることになるため、思わぬところでClassNotFoundExceptionが発生したりします。 クラスの読み込みに関しては結構Javaの深い知識が要求されるので、原因を調べるのが大変でした。

今後もJDKのバージョンアップは定期的に必要となる作業なので、この知見を今後に活かしたいと思います。

FormaDesignerで画面の見栄えをよくしてみた

intra-mart Accel Platform 2018 Winter(Urara) でFormaDesignerのアイテムに「iAP UIデザインモード」機能が追加されたので早速試してみました。

主に入力アイテム、共通マスタアイテムが対応されているようです。

www.intra-mart.jp

今回やったこと

社内で運用しているBISで作成した申請書の入力項目(アイテム)を「iAP UIデザインモード」に設定していきました。

設定後はこんな感じです。

見栄えがすごくよくなりました!

f:id:hamaguchiyu:20190119142201p:plain

設定方法

設定はいたって簡単で、アイテムのプロパティで「iAP UIデザインモード」のチェックをONにするだけです。

f:id:hamaguchiyu:20190119132549p:plain

注意点としては、設定した際に若干アイテムのサイズが広がってしまうのと、表示位置が最前面になってしまうため、設定した後にアイテム配置の調整が必要です。

画面に配置したアイテムの数が多いとかなり骨の折れる作業になりそうです。(今回は数が少なかったのでそこまで大変ではありませんでしたが。。)

所感

他の申請書やFormaアプリも「iAP UIデザインモード」に対応していきたいと思います。

設定をアイテムごとに地道にやっていくしかなさそうなので、 システム全体で「iAP UIデザインモード」のデフォルト設定をONにできたり(→forma-config.xmlの<ui-theme-mode>で設定できるようです)、画面単位で一括ON/OFF設定できたりする機能があればいいな、と思いました。

intra-martの隠しコマンド?

はじめに

みなさまこんにちは、またしてもG.Mです。
外は随分と涼しくなってきました。早々秋物に着替えた方も多いのではないでしょうか。
9月も半分を回り、平成最後の年末が見えてくる頃合です。
これからも何かと『平成最後の××』が盛りだくさんですので、張り切っていきましょう。

さて今回は、intra-martのワークフロー開発で役に立つ豆知識を一つご紹介します。
intra-mart技術者、特にintra-mart開発を最近始めた方向けのテーマです。

【前置き】システム案件IDとユーザデータID

初めてintra-martのワークフローに触れるという方が、まずぶつかるがこの聞き慣れない単語『システム案件ID』ではないでしょうか。
さらに『ユーザデータID』というものもあって、頭の中でごっちゃになりやすい要素ですね。

いずれも、ワークフローを起票・申請したとき、その案件を特定するために用いられる一意のIDです。
『システム案件ID』と『ユーザデータID」は1:1の関係にあり、 どちらか一方だけあれば、案件について欲しい情報を引き出すことができます。

このとき、それぞれの用途は以下のようになっています。

  • システム案件ID(SystemMatterId):ワークフロー側が採番し、システム内部でのみ利用するID
  • ユーザデータID(UserDataId):ユーザコンテンツ側が任意のタイミングで採番し、業務データとの関連付けなどに用いるID

二つのIDの関係イメージ
二つのIDの関係イメージ

システム開発において、ワークフローと連携する業務テーブルの外部キーとして用いるのは『ユーザデータID』である、と覚えておけば、ひとまず問題ありません。

逆に、intra-martがもともと持っているテーブルからデータを取得する場合には『システム案件ID』をキーとして利用します。
APIの引数などでしばしば要求されるかと思われます。

システム案件IDを知りたい

システム案件IDがあれば、案件の情報はなんでも取得できます。
しかし、intra-martの標準画面を見る限り、システム案件IDという項目は見当たりません。
もちろんデータベースをのぞけば分かりますが、それではあまりに手間ですね。

そこで今回は、簡単にシステム案件IDを確認する方法をご紹介します。

intra-martの隠しコマンド

intra-martの標準画面である『未処理一覧画面』を開いてください。

未処理一覧画面
未処理一覧画面
この状態で、キーボードから『Ctrl + Shift + i』を入力してみましょう。
隠しコマンド入力後イメージ
隠しコマンド入力後イメージ
一覧の一番左に、システム案件IDを表示する列が現れました。
また、『Ctrl + Shift + o』を押すと元に戻ります。

簡単にシステム案件IDを確認できましたね!
これは開発の中で非常に重宝するのではないでしょうか。
同じコマンドを使って、他の一覧(一部を除く)でも同様の操作が可能です。

intra-martの隠しコマンド?

このコマンドは、intra-martをご存じな方でも、あまり知る機会のないものではないでしょうか。
隠しコマンドと言いつつ、実は公式ドキュメントにも載ってはいるのですが、
有用性の割に、トラブルシューティングの片隅にTipsとして記されているのみです。

intra-mart IM-Workflow トラブルシューティング
https://www.intra-mart.jp/download/product/iap/im_workflow/im_workflow_troubleshooting/texts/assemble_information/index.html#tips

それから、確認した限りでは、intra-mart開発者ブログの昔の記事にて紹介されていたりしました。

intra-mart Developer Site
https://dev.intra-mart.jp/intra-mart_advent_calendar_2013_14im-workflow/

もう五年も前の記事ですか……。
2013年ということは、『intra-mart Accel Platform』の初期には既に存在していたコマンドなのですね。

Tips
intra-mart Accel Platform(iAP)は、2012年秋からの呼称となります。
以降、春夏秋冬(後に秋がなくなる)のシーズンごとにバージョンアップする今のスタイルに変わりました。

もちろん、現時点での最新バージョン(2018Summer)でもこのコマンドは有効です。

いずれにせよ、intra-martのガイドラインを隅々まで読破していないと、あとあとまで気づけない可能性は大いに有り得そうです。

おわりに

intra-mart開発ブログいわく、今回ご紹介したようなコマンドは他にもあるようです。
ゲームの裏技を探すかのごとく、片っ端から調べてみるのも面白いかもしれません。
が、そういった調査に割ける時間もなかなかありませんし、ぱぱっと一覧にして見せてもらえたらうれしいナ、というのが正直なところですね。

それでは、今回はこれまで。
時節柄、体調も崩しやすいかと思われますので、みなさまくれぐれもご自愛くださいませ。

多要素認証を活用しよう

はじめに

こんにちは、前回に引き続きG.Mです。

ようやく秋らしい気候になったかと思えば猛暑がぶり返し、台風が逆走したと思えば次はダブル台風の到来。
なんとも波乱に満ちた八月もまもなく終わりますね。みなさま、いかがお過ごしでしょうか。

今回は『多要素認証』についてお話ししたいと思います。
この記事については、インターネットに触れるすべての方に一読していただきたい内容となっています。

後半は弊社、株式会社グローバル・ソリューションズ(以下GSOL)の製品もご紹介していきますので、最後までどうぞお付き合いください。

認証とは

まず、認証とは何でしょうか。

何かのサービスを受けるときに、自分が正規のユーザーであること、または『私が本物の私であること』を証明することを認証と言います。そしてそのために使うのが、秘密の文字や番号、生体情報です。 最近どんどん身近になっていますね。

例を挙げてみましょう。

このように、今や誰しもが自分だけのパスワードを持ち、日常的に認証を行っています。

多要素認証とは

では、多要素認証とは何でしょうか。

例えば『パスワードによる認証』に加え、もう一つ『指紋による認証』など別の認証を続けて行う方式のことです。複数の認証を必要とするから『多要素』と呼ぶ、分かりやすいネーミングですね。

多要素のイメージ
多要素のイメージ

また、異なる認証を二つクリアして初めてログインできるような仕組みのことは、特に『2段階認証』と呼びます。
2段階認証のイメージ
2段階認証のイメージ

最近になって増えてきたとされる認証方式ですが、一部銀行などではもっと昔から採用されていました。
利用者の大切な資産を守ろうとする金融機関の、セキュリティに対する厳格な姿勢がうかがえますね。

認証方法が変わってきた契機

最近になって増えてきた、と上述しましたが、それはなぜでしょうか。どんな契機があって、新しい認証方法が登場したのでしょうか。
実は昨年(2017年11月)、総務省の『国民のための情報セキュリティサイト』にて、こんな発表があったのです。

利用するサービスによっては、パスワードを定期的に変更することを求められることもありますが、実際にパスワードを破られアカウントが乗っ取られたり、サービス側から流出した事実がなければ、パスワードを変更する必要はありません。

さらに、こう続きます。

むしろ定期的な変更をすることで、パスワードの作り方がパターン化し簡単なものになることや、使い回しをするようになることの方が問題となります。

このように、パスワードの定期変更はする必要がない、むしろリスクがある、と明記されています。

Tips
※下記サイトから引用しておりますので、全文はリンク先をご覧ください。
http://www.soumu.go.jp/main_sosiki/joho_tsusin/security/business/staff/01.html

驚いた方も多いのではないでしょうか。
ひと昔前は『パスワードは定期的に変更する』のが当たり前でした。
Webサービスなどでは、最後にパスワードを変更してから三カ月を経過したら、強制的にパスワード変更画面が表示される――ということもしばしばありました。

新しいパスワードを要求する画面イメージ
新しいパスワードを要求する画面イメージ

確かに、定期的にパスワードを考えるのも面倒なもので、つい『MGs1kIgs0l@0001』→『MGs1kIgs0l@0002』というような単純な変更にしてしまいがちです。
これが逆に危険ということで、定期的なパスワード変更を推奨しなくなった、ということですね。

日進月歩の情報分野では、今まで常識とされていたルールが目まぐるしく入れ替わる。これがITの難しいところであり、素晴らしいところでもあります。
パスワード認証についても、今回のことで大きな方針転換がなされたと言えるでしょう。

最適な認証

では、今日の『最適な認証』とはなんでしょうか?
最新のセキュリティ対策をまとめる『OWASP Top 10 - 2017』にはこのように記述されています。

かつてベストプラクティスとされてきたパスワードの定期変更や複雑性の要求は、ユーザーに弱いパスワードを繰り返し使うよう促すとの見方があります。そこで、あらゆる組織がNIST 800-63に従ってこのようなプラクティスをやめ、多要素認証を使うことが推奨されています。

Tips: NIST 800-63とは
アメリカの政府機関が、アメリカ政府各省庁・各機関に対して発行する電子認証ガイドライン

この記事の冒頭で触れた『多要素認証』が登場しました。
これまで使っていたパスワードの定期変更はやめて、多要素認証を使いましょう、という記述です。

Tips
全文は下記PDFをご覧ください。
https://www.owasp.org/images/2/23/OWASP_Top_10-2017%28ja%29.pdf

こういった流れの中で、日本でも多要素認証が広がりつつあるわけですね。

弊社GSOLの取り組み

NTTデータ・イントラマート社のパートナー会社である私たちGSOLでは、intra-mart製品として、2013年から『2段階認証&ログイン履歴』の仕組みを提供しています。

Tips: intra-martとは
『intra-mart Accel Platform』
NTTデータ・イントラマート社が販売している製品で、システム開発時に利用するアプリケーション構築基盤です。
詳しく知りたい方は、ぜひ検索してみてください。

intra-martで標準利用できるパスワード認証に加え、ワンタイムパスワード認証を使用することで、2段階認証を実現しています。

Tips: ワンタイムパスワード認証とは
一度のログインに一度きり使えるパスワードを通知して、それを入力することで認証をクリアする方式です。

ワンタイムパスワードはログインごとに別途通知されますので、万が一パスワードが盗まれていても、その通知を盗聴されなければ、なりすましログインの危険性は低くなります。

ワンタイムパスワードの通知方法は様々ありますが、弊社製品においては大きく二つあります。

  • スマートフォンアプリである『Google 認証システム』のコードを利用する
  • intra-martに登録したメールアドレスに都度送信する

どちらも原理は同じですが、『Google 認証システム』はスマートフォンAndroid / iPhone)を持っていないと利用できないデメリットがあります。

スマホアプリを利用しない人もいる
スマホアプリを利用しない人もいる

その点、メール送信なら、アドレスとネット環境があれば誰でも利用可能です。
このように、システム利用者の傾向を見つつ、最適な通知方法を選択することができます。

なお、『2段階認証&ログイン履歴』の設定は画面やAPIから可能です。
さらに、ノンコーディングシステム開発ができるIM-LogicDesignerとの連携することでも、2段階認証の設定が行えます。

Tips
詳しくは弊社のintra-mart ソリューション 製品情報サイトをご覧ください。
http://global-solutions.co.jp/documentation/index.html

まとめ

それでは、今回のまとめです。

  • 多要素認証を活用しよう!
  • GSOLの『2段階認証&ログイン履歴』をよろしく!

インターネット上のセキュリティ対策はイタチごっこです。今このとき最新最良のセキュリティも、十年もすれば時代遅れと言われていることでしょう。

十年後の技術
十年後の技術イメージ

インターネットと実生活が切っても切れないほど密接になった現代では、私たちのような情報技術者のみならず、すべてのネット利用者が、セキュリティを意識していかなくてはなりません。
今回の記事が、その意識向上の一助になればと願っています。

それでは、また次回もよろしくお願いいたします。

IM共通マスタの期間化を利用してみよう

ご挨拶

みなさま初めまして、G.Mと申します。
理系出身のSE・プログラマでありながら、小説を書くのが好きだという変な技術者です。

今年から株式会社グローバル・ソリューション(以下GSOL)に中途入社致しまして、このたび本ブログの投稿を任せていただきました。

今回のテーマ

さて、今回の記事のテーマですが、intra-martが持つIM共通マスタの『期間化』についてご紹介していきます。
intra-martを導入したら、どんなことができるんだろう? とご検討中の方々の一助になれたらと思います。

Tips
intra-martってなんだろう? という方もまだまだ大勢いらっしゃるかと思われますが、気になった方はぜひ検索してみてください。
機会があれば、このブログでもあらためてご紹介するかもしれません。

マスタの期間化

1.IM共通マスタ

intra-martは、そのシステムを円滑に動かすため、『IM共通マスタ』という情報をデータベースに持っています。
マスタとは、ユーザ(社員)情報、会社・組織情報、品目(商品)情報など、システムを稼働させるにあたって欠かせない、基本的な情報のことです。

Tips
マスタについてもっとよく知りたいという方は、マスタデータやトランザクションデータをキーワードとして、調べてみてくださいね。

例えば、intra-martを使って構築した勤怠管理システムであれば、
ひとつの会社の中にいくつもの組織があり、さらにその組織それぞれに大勢の社員が所属している……という情報が、このIM共通マスタに保存されています。

マスタ情報のイメージ図
マスタ情報のイメージ図

ところで、会社ではしばしば組織の統廃合が行われます。となればもちろん、それにあわせてマスタも更新する必要があります。
廃止される組織の情報はどうすればよいでしょうか? 思い切って、データベース上からその組織の情報を物理削除してしまいましょうか?
ですがその場合、後から廃止された組織のことを調べようにも、データはもう存在しませんので、確認が難しくなってしまいます。

そんなときは、IM共通マスタが持つ『期間の分割』と『構成からの除外』という機能を活用しましょう。

2.期間の分割

IM共通マスタ上で、組織情報は期間情報を持っています。つまり、この組織は1970年1月1日から2099年12月31日まで有効ですよ、というような情報を保持しています。
期間の分割とは文字通り、その期間情報を二つに分けます。

組織分割のイメージ図
組織分割のイメージ図

『この組織は1970年1月1日から2018年7月31日で有効であり、さらに2018年8月1日から2099年12月31日まで有効である』というように、期間を分けてしまうのです。
このとき、前者を期間A、後者を期間Bとしましょう。

同じ組織でも、ある日を境に状況が変わったときなどに、この分割は役に立ちます。
この組織が2018年7月31日まで存在し、それ以降は廃止されたとするならば、期間Aをそのままにして、期間Bの情報のみ更新すればいいのです。

組織廃止のイメージ図
組織廃止のイメージ図

これなら廃止後も情報は残っていますので、将来必要になってから情報を取得することも可能です。便利ですね。

3.構成からの除外

組織を廃止する日付で期間を分割したら、廃止される期間の組織情報を修正しなくてはなりません。
通常、不必要な期間は『無効化(論理削除)』してしまえば大丈夫です。
これならば、あとから廃止組織の情報を調べることもできますし、さらに分割した別の期間で廃止組織を復活させることも容易です。組織に所属しているユーザもそのままですので、誰が所属していたかも保持しておけます。

ただし組織に関しては、『構成からの除外(論理削除)』をオススメします。
つまり、組織は有効な状態のままで、階層構造から外してしまうのです。

構成からの除外イメージ図
構成からの除外イメージ図

構成に残したまま無効化すると、組織マスタの操作画面上で組織名が赤字のまま残ってしまいます。

組織を無効化した場合
組織を無効化した場合

ですが構成から除外すれば、画面上からも組織名が消えますので、きれいに整理できますね。

組織を構成から除外した場合
組織を構成から除外した場合

構成から除外した組織は、一般ユーザの目には映らなくなります。
しかしデータとしては有効なままですので、そのまま別の組織の下部組織として配置換えするなどが可能となります。
また、退職した社員データをまとめておくための仮組織として、構成から除外した組織を利用するという手法も考えられます。

4.プログラムからの操作

期間についての操作は、IM共通マスタの各種画面から実行できますが、APIでも同じことができます。
例えば組織であれば、CompanyManagerというAPIを使います。
以下にメソッドを例示します。

メソッド名 役割 利用にあたり必要な情報
getDepartmentTerm 機関の検索 会社・組織検索条件、有効日付
separateTermDepartment 期間の分割 会社・組織検索条件、期間コード、分割日付
moveTermDepartment 期間の変更 会社・組織検索条件、期間情報

これらのメソッドを用いれば、マスタメンテナンス画面上でできるほとんどのことが、Javaプログラムでも実行できます。

Javaプログラムで操作できるということは、例えば休職申請ワークフローの案件終了時に自動で休職期間をマスタ登録したり、IM-FormaDesignerやTERASOLUNAを使って独自に作った画面上で期間の操作を行ったりもできます。
夢が広がりますね!

夢が広がっている図

Tips
APIの詳しい機能については、公式リファレンスをご覧ください。
https://www.intra-mart.jp/apidoc/iap/javadoc/im_master_apidocs/jp/co/intra_mart/foundation/master/company/CompanyManager.html

まとめ

それでは、今回のまとめです。

  • intra-martの持つマスタ情報は期間化できる!
  • 期間を分割して、過去の情報を保持できる!
  • 廃止組織は『構成から除外』しよう!

いかがでしたでしょうか?
今後は、intra-martの紹介や小ネタの共有、最新技術やITニュースにちょっと触れてみたり、弊社GSOLのお話もしていけたらと思います。

私もまだまだ勉強中の身ではございますが、これからもどうぞよろしくお願いいたします。

Final Tips
intra-martは日々進化しておりますので、今後のアップデートで仕様が変わる可能性があります。

今年も内定者の研修にProgateを使ってみた話

開発部のTです。
一年近く更新をさぼっていましたが、再開します。

去年に引き続き、今年も新入社員の研修(今回は内定者研修)にProgateを使ったので、 継続して利用したことで気づいたことや、弊社の新入社員への研修内容について共有したいと思います。

ちなみに1年前に導入した時の所感についての記事は以下になります。

gsol.hatenablog.com

Progateとは

prog-8.com

Progateの解説は数多存在するため詳細は割愛しますが、イラスト中心の直感的なスライド資料と実践的な演習問題の添削によって、初学者でも楽しくプログラミングの基本の「き」を学べるサービスです。

今回は内定者研修の教材として、以下のレッスンを3ヶ月かけて受講してもらいました。

Progateによる内定者研修

今年の内定者研修は1月から3月に実施しました。
研修では内定者の時間的都合を尊重して、特に弊社側で厳守すべきスケジュールを設けずに個人のペースでProgateのレッスンを進めてもらいました。
※とはいえ流石に基準となるスケジュールがないと予定通り進めるのも難しいので、毎週5時間程度の受講で上記の全コースが完了できる点と、レッスンを受ける際の適切な順番(フロントエンド→バックエンド→その他の順番)を内定者に伝えています。

去年はあまり効果を実感できず…

ちょっと余談ですが、去年Progateを利用した時は情報系出身のとても優秀な学生が受講者だったこともあり、Progateの効果がいまいち把握できませんでした…
優秀な学生が入社してくれることはとても嬉しいのですが、Progateの全レッスンをすぐに完了させてくれる等、中々に研修担当者泣かせの子でした。

今年は効果を実感できた!

今年は内定者の子にプログラミング未経験の文系の学生がいて、Progateを通じて初学者からエンジニア見習いレベルまで成長していることを確認できたので、良い効果があることを実感できました。
内定者の子には3月からアルバイトとして本社で働いてもらっているのですが、先輩社員と技術的な会話が成立する程度には成長できています。
新卒採用の一次面接の時点で、「プログラミング未経験ですが大丈夫ですか?」といった質問をしていたことを思い出すと、今年もProgate使ってよかったなあとしみじみと感じます。

Progateのどの辺りでスキルを付けることができたかを内定者の子に聞いてみたところ、
コースの後半で難易度が飛躍的に上がる箇所があり、そこを自力で調べて解決することでスキルを付けることができたという感想を聞くことができました。
技術的な問題を如何に調べるかがエンジニアにとって最も重要なスキルなので、そのスキルを初学者の時点から身に着けられるサービスであるという点が、Progateがここまで支持されている理由なのかなと感じました。

仲間募集中!

グローバル・ソリューションズでは、新卒採用で仲間を募集しています。弊社は初学者の方に成長できる環境、様々なことを経験、チャレンジできる環境を提供できます。興味のある方は、以下から説明会にエントリーしてみてください。

job.rikunabi.com

またWantedlyでは、新サービスの開発コアメンバーとして大いに力を発揮してくれる方を募集しています(昨日募集を開始しました)。新卒中途は特に問いませんので、弊社のサービス開発に少しでも興味のある方は以下からエントリーお願いします!

www.wantedly.com

新入社員の研修にProgateを使ってみた話

開発部のTです。

4月からの新入社員研修にProgateというサービスを使ってみました。Webサービスを利用した新入社員研修は初めての試みだったので、私個人の所感も交えて紹介しようと思います。

Progateとは

prog-8.com

初学者向けのオンラインプログラミング学習サービスです。以前から新入社員研修で使ってみたいと思っていたので、今年度から試験的に導入してみました。

f:id:gsol-dev:20170501101523p:plain

学習資料のスライドが初学者向けにとてもわかりやすく記載されてます。画像はProgateトップページより引用しています。

f:id:gsol-dev:20170501101529p:plain

学習資料に対応した演習をこなしながら学習を進めていく形式となっています。この画像もProgateトップページからの引用です。

実際に利用してみた感想

以下、私個人の所感です。

初めてのプログラミング向き

学習スライドが読みやすいように図が多め、文章少なめだったり、演習にヒントがついていたりと、とにかくプログラミング初心者に優しいサービスの作りになっている印象です。本を買って勉強する場合と比べて、かなり勉強しやすいと思います。

場合によっては他の研修と併用が必要

言語によっては学習範囲が狭いため、他の教材(本とか)での学習が必要になると思います。例えば自社の場合、クライアントサイドの研修に関してはProgateのHTML&CSSjQueryで新人の研修教材として十分でしたが、サーバー言語のJavaJavaScriptについてはProgateの内容では不十分そうだったので、Progate学習後に本を読んで勉強をしてもらっています。

ちなみに自社の開発にRailsを使っている場合は、HTML&CSS + jQuery + Ruby on Railsで新人研修としては十分な印象です。

まとめ

以上、Progateの紹介と新入社員研修に使用した感想でした。最初にプログラムに触る教材としてはとても良いサービスなので、来年度も新入社員研修に使ってみようと思います。

CentOS Dockerコンテナの日本語ロケール設定方法

開発部のTです。

今回はCentOSのDockerコンテナで日本語ロケール設定方法について紹介します。

CentOSでのロケール設定方法

以下Dockerfileのサンプルです。

FROM centos:centos7

RUN rm -f /etc/rpm/macros.image-language-conf && \
    sed -i '/^override_install_langs=/d' /etc/yum.conf && \
    yum -y reinstall glibc-common && \
    yum clean all

ENV LANG="ja_JP.UTF-8" \
    LANGUAGE="ja_JP:ja" \
    LC_ALL="ja_JP.UTF-8"

CMD bash

補足

これまでは以下の様なDockerfileでもロケールの設定ができていたのですが、1392855 – build-locale-archive: build-locale-archive.c:301: fill_archive: Assertion `used < head->namehash_used' failed.で報告されている不具合によって、去年末頃からロケールの設定ができなくなっています。

FROM centos:centos7

RUN yum -y update && \
    yum -y reinstall glibc-common && \
    yum clean all

ENV LANG="ja_JP.UTF-8" \
    LANGUAGE="ja_JP:ja" \
    LC_ALL="ja_JP.UTF-8"

CMD bash
# コンテナ内でlocale -aを実行してもCロケールとPOSIXロケール以外が存在しない。コマンド実行する度にwarningログが出力される。
$ locale -a
/bin/sh: warning: setlocale: LC_ALL: cannot change locale (ja_JP.UTF-8)
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_COLLATE to default locale: No such file or directory
C
POSIX

そのため、glibc-commonを再インストールする前にrm -f /etc/rpm/macros.image-language-confsed -i '/^override_install_langs=/d' /etc/yum.confを実行することで不具合を回避しています。

intra-martのエラー発生時にSlackに投稿する方法の紹介

開発部のTです。

今回はlogbackの機能を使って、intra-martでエラーが発生した時にSlackにエラー内容を投稿する方法を紹介します。

Slackの設定

SlackのIncoming Webhooks機能を使って、 特定のチャンネルにintra-martのエラー内容を投稿するためのWebhook URLを発行します。 (手順の紹介は省きます)

自社ではエラーが発生すると、:imp:の絵文字で投稿するように設定しています。

f:id:gsol-dev:20170123201536p:plain

Appenderの実装

Appenderによって、エラーログをSlack APIの仕様に基づいたJSON形式に変換し、Webhook URLに対してPOST送信します。 長文のエラーログをSlackに投稿できるように、attachments属性にエラーログを設定しています。

以下Appenderのソースです。

package jp.co.gsol.logback.appender;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Layout;
import ch.qos.logback.core.UnsynchronizedAppenderBase;

import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.arnx.jsonic.JSON;

public class SlackAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {

    private static final String PRETEXT = "【社内システム】iAPエラーログ";
    private String url;
    private String channel;
    private Layout<ILoggingEvent> layout;
    private int timeout = 10000;

    @Override
    protected void append(final ILoggingEvent event) {
        try {
            final URL apiUrl = new URL(url);
            final StringWriter w = new StringWriter();
            w.append("payload=").append(URLEncoder.encode(createAttachmentsStr(layout.doLayout(event)), "UTF-8"));
            final byte[] bytes = w.toString().getBytes("UTF-8");

            final HttpURLConnection con = (HttpURLConnection) apiUrl.openConnection();
            con.setRequestMethod("POST");
            con.setDoOutput(true);
            con.setConnectTimeout(timeout);
            con.setReadTimeout(timeout);
            con.setFixedLengthStreamingMode(bytes.length);
            con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

            final OutputStream os = con.getOutputStream();
            os.write(bytes);

            os.flush();
            os.close();
        } catch (IOException e) {
            addError(channel + "投稿時にエラーが発生しました", e);
        }
    }

    /**
     * ログフォーマットをJSON形式に変換
     * @param text
     * @return
     */
    private String createAttachmentsStr(final String text) {
        List<Map<String, Object>> attachments = new ArrayList<>();
        Map<String, Object> attachment = new HashMap<>();
        attachment.put("pretext", PRETEXT);
        attachment.put("text", text);
        attachments.add(attachment);
        Map<String, Object> map = new HashMap<>();
        map.put("attachments", attachments);
        return JSON.encode(map);
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(final String url) {
        this.url = url;
    }

    public String getChannel() {
        return channel;
    }

    public void setChannel(final String channel) {
        this.channel = channel;
    }

    public Layout<ILoggingEvent> getLayout() {
        return layout;
    }

    public void setLayout(final Layout<ILoggingEvent> layout) {
        this.layout = layout;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }
}

im_logger.xmlの設定

im_logger.xmlにSlackAppenderの設定を行います。 intra-martのログ仕様書に基づいて、 ログ出力したい情報を<layout>タグに設定します。<url>タグにはSlackのWebhook URLを設定します。

以下、自社のim_logger.xmlの設定の抜粋です。

    <appender name="SLACK" class="jp.co.gsol.logback.appender.SlackAppender">
        <channel>#in-house-error-log</channel>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}]
thread: [%thread]
level: [%-5level] logger: [%logger{255}]
tenant id: [%X{tenant.id}] log id: [%X{log.id}] request id: [%X{request.id}]
user type: [%X{user.type}] authenticated: [%X{authenticated}] user cd: [%X{user.cd}]
log message code: [%X{log.message.code}]    message: %msg%n
%ex{full}
            </pattern>
        </layout>
        <url>https://hooks.slack.com/services/XXXXXXX/YYYYYYY/ZZZZZZZZZZZZZZZZZZZZZ</url>
    </appender>

    <appender name="ASYNC_SLACK" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="SLACK" />
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
    </appender>

    <root>
        <level value="info" />
        <appender-ref ref="ASYNC_SLACK" />
    </root>

Slackに投稿される内容

intra-martでエラーが発生すると、Slackに↓の様な投稿が自動で行われます。

f:id:gsol-dev:20170126195917p:plain

投稿を展開するとExceptionの詳細が見れます。

f:id:gsol-dev:20170126195941p:plain

Exceptionが長すぎると、途中で省略されてしまうので、いつか修正したいです。

以上、intra-martのエラー発生時にSlackに投稿する方法の紹介でした。

JavaScriptを使った開発に便利な定番ライブラリ

開発部のS.Kです。

JavaScriptの定番ライブラリについて紹介します。

lodash.js

非常に幅広く便利な機能を提供してくれるライブラリです。 主にコレクションやオブジェクトに関しての機能が中心で、かゆいところに手が届くようなユーティリティをたくさん備えています。

Moment.js

日付や時刻に関する機能を提供するライブラリです。 JavaScript標準の機能だと、日付の操作に不便なことが多々あります。 このライブラリは、そんな日付関係の処理を補ってくれるため、非常に便利です。

この2つで、細かな使い勝手がかなり改善されます。 画面構築と操作に関しては、jQueryやAngular.js、最近ではReact.jsなど様々な選択肢がありますが、この2つのライブラリはどの場合でも役に立つと思います。

当然使い方を覚える必要はありますが、それを補って余りあるメリットがあると思うので、ぜひ活用してみてください。

docker-compose runでport mappingされず小一時間悩む

開発部のTです。

docker-composeを使っていたらタイトル通りの内容で悩みました。結論としてはドキュメントをよく読んで使おうって話なだけなのですが。。。

経緯

以下の様なdocker-compose.ymlを作って、dockerコンテナ上でNode.jsプロジェクトのインストール、起動すると、コンテナ内で起動しているサーバーにアクセスできずに悩みました。。。

# docker-compose.yml
version: '2'
services:
  graphql:
    image: node:alpine
    volumes:
      - .:/usr/src
    ports:
      - "3000:3000"
    privileged: true
# Node.jsプロジェクトをcheckout
git clone https://github.com/kadirahq/graphql-blog-schema.git
cd graphql-blog-schema
git checkout build-schema

# 作成したdocker-composeでインストール、起動
docker-compose run --rm graphql npm install --prefix=/usr/src
docker-compose run --rm graphql npm start --prefix=/usr/src

# 別ターミナルでコンテナ内のサーバーにアクセスするとConnection refused
curl http://localhost:3000
curl: (7) Failed to connect to localhost port 3000: Connection refused

原因と解決

調べてみると(というかリファレンスに書いてありました)、docker-compose run --service-portsとしないと、docker-compose.ymlファイルのport mappingが無視されるようです。以下引用です。

The second difference is the docker-compose run command does not create any of the ports specified in the service configuration. This prevents the port collisions with already open ports. If you do want the service’s ports created and mapped to the host, specify the --service-ports flag:

docker-compose run --service-portsを指定して無事動きました。

docker-compose run --rm --service-ports graphql npm start --prefix=/usr/src

# curlでコンテナ内のサーバーにアクセスできる
curl http://localhost:3000
<html>
  <head>
    <title>Sample App</title>
    <link rel="stylesheet" type="text/css" href="/static/graphiql.css">
  </head>
  <body>
    <div id='root'>
    </div>
    <script src="/static/bundle.js"></script>
  </body>
</html>

以上、ドキュメントをよく読んで使おうという話でした。