Goalist Developers Blog

Angularで WARNING in Circular dependency detected だよ〜ドラえも〜〜ん

はい。
ゴーリスト開発の飯尾です。

タイトルの通りなんですけど
別に解決してないんですけど

Angular CLI を1.1.3から1.5.5にアップデートしたら
アラ〜〜〜

WARNING in Circular dependency detected:
src/app/services/auth.service.ts -> src/app/services/request.service.ts -> src/app/services/auth.service.ts

WARNING in Circular dependency detected:
src/app/services/request.service.ts -> src/app/services/auth.service.ts -> src/app/services/request.service.ts

とはいえ、コンパイル自体は通るしプロダクション用ビルドも普通にできる……

どうする???

github.com

「Angular CLI 1.3.0から起こる」
「showCircularDependenciesをfalseにして見えなくすればOK」

そんな……
うるせーから黙らせる的な発想でいいの……

いったん、循環参照になっちゃうメソッドを別サービスに出してそれぞれDIする

警告オフにして他の問題に気づかないとかちょっと避けたいので……

社内Angularの雄にきいてみる

f:id:y-iio:20171215182535p:plain

ウオ〜〜〜
そういう!ことなのか!!?

Angular5にアップデートしてHttpモジュールを変更するゾ

こんにちは🍣
ゴーリスト開発の飯尾です

Angular4.3以下から5にアップデートするとき
Httpクライアントモジュールは @angular/http が非推奨になったので
@angular/common/http を使うように変更しました

どんなかんじに書き換えたのかまとめてみました

Before

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Http, Headers, Response, RequestOptions } from '@angular/http';
import { MyResponse } from '../entity/my-response';

@Injectable()
export class RequestService {

  constructor(private http: Http) { }

  public post(params: string): Observable<any> {
    const headers: Headers = new Headers({
      'Content-Type': 'application/json',
      'dataType': 'json'
    });
    const options: RequestOptions = new RequestOptions({headers: headers});
    return this.http.post(REQUEST_URL, params, options)
      .map((res: Response) => {
        return new MyResponse(res.json());
      });
  }

}

After

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpClient } from '@angular/common/http';
import { MyResponse } from '../entity/my-response';

@Injectable()
export class RequestService {

  constructor(private http: HttpClient) { }

  public post(params: string): Observable<any> {
    return this.http.post<MyResponse>(REQUEST_URL, params);
  }

}
import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class MyInterceptor implements HttpInterceptor {

  constructor() { }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const req = request.clone({
      setHeaders: {
        'Content-Type': 'application/json',
        'dataType': 'json'
      }
    });
    return next.handle(req);
  }
}

違いはなんなん

ヘッダーのオプション設定は今までのが使えなくなったので
HttpInterceptorに出して使うようにしてみました

レスポンスの型指定ができるようになったので嬉々として使ってます

ついでに

こんな記事もこの前書きましたの

developers.goalist.co.jp

初めまして、Pattamada Ponnapa Chinnapa です!

Hello World!

That's what every programmer says first, right?

あ、すみません、日本語のブログでしたね(言語制限がないと言われてますが、さすがに最初から全部英語などにしたら、みんな逃げちゃいますね)。

タイトルはそうなんですが、チナパと申します、新しくゴーリストの開発部に入った者です!

f:id:c-pattamada:20171207152452j:plain

^- 私

今回、軽く自己紹介させていただきます! 母国はインドです!ただし、日本には現在五年目です! さて、次の質問はいつもカレーについてなので、納得します、インド人らしくカレーがすきです、 日本のカレーもその範囲の中に来ます、もちろん

プログラミングに関して、詳しい知識はまだないんですが

  • Java Javascript PHP Python

  • はみんな少しできます。AIにもとても興味があります!

ここまで読んでくれた皆さんに、もし機械学習に興味があればここででも第一歩踏めます!

MNIST For ML Beginners  |  TensorFlow

グーグル翻訳が気に入らない人のために、これからのポストはこの話題にしようと思ってますので、楽しみにしてください!

どうせ誰も見ないけどSwiftのガイドライン的なものを少しずつ作る

こんちは。渡部です。

f:id:watabe1028:20171129095304p:plain

確かゴーリストでは昨年あたりにようやくJavaのコーディング規約を作りました。
一体どれほどの社員が見たでしょうか?
CTOは規約を守っているのでしょうか?
三項演算子にスペースは入れてくれているのでしょうか?
 
社内にSwiftユーザ少ないけどこれからきっと増えるから
ガイドラインを作っとこ、と思ったので少しずつブログで作っていきます。

 

命名規約

クラス名、構造体名、列挙型名、プロトコル名

基本キャメル型ですよね。
宗教論争になりますがここではキャメル型で通します。

class GoalistModel {}

protocol GoalistModelDelegate: class {}

enum Week: String {}

struct Author {}

 
 

グローバル定数名、クラス定数名

こちらは大文字のスネーク型を使います。
完全に好みだけど世の中的にこれが多い気がします。
でふぁくとすたんだーど。

public let GOALIST_VALUE_NAME = "hokoriwomotsu"

class GoalistModel {
   static let TABLE_NAME = "GOALIST_TABLE"
}

 
 

変数名、関数名

もちろんキャメル型。

var userName: String = "watabe"

func sendMessage(textMessage: String) -> Void {

}

 
 

定義方法

変数、定数

1行で複数の宣言はやめましょう。
基本醜い、見にくいです。

let userName: String = "watabe"
let userId: Int = 0

letとvarの違いは
letは定数、varは可変と認識してます。
間違ってたらすんません。

 

型宣言

基本します。
明確な場合はしなくても良くね?
と言われますがダメです。(圧)

let text = "hello"         // は?
let text: String = "hello" // OK

let text = data["text"] as String         // は?
let text: String = data["text"] as String // OK

 
 

配列の初期化

色々あって何がよいやら、ですが以下の記述方法にします。
完全に好みです。

let member = ["watabe", "moritsugu", "iio", "chinapa"]           // は?
let member: [String] = ["watabe", "moritsugu", "iio", "chinapa"] // OK

 
 

今回は終わり

いやーガイドライン作成って大変ですね。
今日は面倒になってきたからこの辺にしておこう。そうしよう。

次は構文とか決めていきます。

いまさらだけどSketch共有会をやってみた

こんちは。渡部です。

f:id:watabe1028:20171128210227j:plain

今回は先日やったSketch共有会の様子を紹介します。

開催の経緯

開催したきっかけは
Sketch使ってもっと効率よくプロトタイプ作りてぇなぁと思っていた時
レタスデザイナーの日報にSketchのことが書いてあったので

f:id:watabe1028:20171128210422p:plain

と返信したら

奇声エンジニアから圧力がきました。

f:id:watabe1028:20171128210436p:plain

みんな気になっていたみたいです。

 
わたわたしながらスケジュールを調整して(もらって)
開催しました。
 
 

参加者

デザイナー3名、エンジニア3名(うち大阪からのリモート1名)。
リモートで画面共有ができる便利な時代ですね。

f:id:watabe1028:20171128210452j:plain

 
 

内容

エンジニアが自分を含めSketchには無知なので
主にSketchで何ができるかの共有です。

 
それからプラグインでこんなことできるよ〜という話をして
プロトタイプをこうやって作って
共有すれば効率的に進められるよ〜
すげぇぇぇぇ!
ってなって終わりました。
 

主には

www.tam-tam.co.jp

www.webprofessional.jp

これらと同様の内容です。
スクショや写真を撮り忘れたのでこちらを参考にしてください。

 

所感

なかなか好評でした。

f:id:watabe1028:20171128210628p:plain

エンジニアもデザイナーもこういった共有をしておけば
お互いの作業が楽になりますもんね。
 
お互いの作業を楽にするためには
お互いの作業を理解しておく必要がありますね。
 
ちなみにデザインは開発フローの中で最も重要だと思ってます。
デザインさえしっかりしていればフロントの開発はなんとかなっちゃいますし
機能やAPIもそれとなく想像できます。
 

次回

次回は実際に手を動かすワークショップを開催します。
ひっそりと姿を消した社内プロジェクトの画面を作成します。

次回はきっとデザインブログで更新されるので(圧)
そちらもチェックしてみてください。

AWS LambdaをJavaで書いていた人がPythonで書くためにすること

こんにちは。ゴーリスト開発の盛次です。

Javaが大好きだけどPythonでもAWS Lambdaを書いてみるかー、と思った人のための記事です。

開発環境

Windows10
PyCharm
Python3.6

開発環境を作る

とりあえずインストールが楽そうなのでAnacondaを利用します。
Anacondaのインストール方法は世の中に優れた記事がたくさんあるのでそちらにお任せします。
JetBrains製品が大好きなのでIDEはPyCharmを使います。
CommunityとProfessionalの2種類がありますが、無料のCommunityで問題ないです。リモートデバッグを使う場合はProfessionalが必要です。
こちらもインストール方法は世の中の優れた記事にお任せします。

ライブラリまわりについて

Javaをeclipseとかで開発するときのプロジェクトに相当するのはPythonでは仮想環境だと思います。
従って、まずは仮想環境を作ります。私の環境ではPyCharmを立ち上げたままAnacondaを入れると、再起動しないとcondaにパスが通ってない状態でした。

conda create -n my_env python numpy scipy

my_envが仮想環境の名前になります。python numpy scipyなどは最初からinstallしておきたいパッケージを指定します。
scipy=0.12.0のようにすることでバージョン指定も可能です。

仮想環境の一覧と仮想環境の切り替えは以下です。

conda info -e # 利用できる仮想環境の一覧を表示
activate my_env # Windows
source activate my_env # Mac/Linux

基本的に「conda insall hogepackage」でinstallしますが、見つからない場合があるので、良く見るパッケージ管理ツールpipもインストールします。

conda install pip

awsまわりのライブラリはboto3を利用します

pip install boto3

利用ライブラリの書き出しは以下です

pip freeze > requirements.txt

lambda-uploaderの利用

Lambdaへのアップロードにはlambda-uploaderを使います。

pip install lambda-uploader

50MB以下なら直接アップロードして適用できます。それ以上はlambda-uploaderでzipにして後は自分でS3にアップして適用するいつものやつになります。

AWSの認証情報との紐づけはprofileを作り、アップロード時に指定します。
とりあえずaws-cliが必要なので

pip install awscli

hoge-profileという名前でプロファイルを作成

aws configure --profile hoge-profile

AWS Access Key ID [None]: {Your Access Key Id}
AWS Secret Access Key [None]: {Your Secret Access Key}
Default region name [None]: ap-northeast-1
Default output format [None]: json

アップロード時のコマンド。

del *.zip
lambda-uploader --virtualenv=C:\hoge\my_env --profile=hoge-profile

コマンドの実行はlambda-uploaderの設定ファイルであるlambda.jsonが置かれているディレクトリで打つ前提です。
ビルドにミスるとゴミzipが出来上がって、次に実行する時にこのzipが含まれて大きなzipになるのでdelで削除しています。Linuxの場合は読み替えてください。
lambda-uploaderを使うとlambda.jsonとこのコマンドだけでアップロードが完了します。凄く便利。

lambda.jsonについて

lambda-uploaderの設定ファイルのlambda.jsonの内容は見れば分かるものばかりですが、注意すべきなのはname、handler、roleの3つだと思います。

{
  "name": "hogeFunc",
  "description": "write description",
  "region": "ap-northeast-1",
  "handler": "hoge.lambda_handler",
  "role": "arn:aws:iam::xxxxxxxxxxxx:role/hoge_lambda_exec_role",
  "timeout": 300,
  "memory": 128
}

nameはアップロード先のLambda Functionの名前と一致させる必要があります。
handlerはhoge.pyというファイルにlambda_handlerというメソッドを定義している場合です。Lambdaで実行されるメソッドになります。
roleはhogeFunc実行用のroleの値を入れる必要があります。

API GatewayのLambdaプロキシ統合を使う場合

API Gatewayの設定でLambdaプロキシ統合(Lambda Proxy Integration)を使うと普通に文字列をreturnするとinternal server errorで怒られます。 以下のようにstatusCode body が必須、必要な情報はbodyに入れます。 'Access-Control-Allow-Origin': '*'を設定したheadersも入れることになると思います。

return { 'statusCode': 200, 'body': 'Hello from Lambda' }

Javaぽく書きたい!

Python3.5からType Hintsという機能が導入されました。
実行時には完全にコメント扱いなので好きなだけ書いていいです。
変数宣言の型と関数の戻り値の型などを明示できます。
Type Hintsの静的なチェックにはmypyを使います。

pip install mypy
mypy hoge.py 

以下は私がLambdaのレスポンスをクラス化したいと思い、Pythonの命名規則の規約をガン無視してJavaぽく書いたコードになります。
自分で定義したclassに対してはjson.dumpsが使えないので、EntityBaseクラスにtoJson()メソッドをもたせ、継承してゴニョゴニョしています。
Lambdaで実行するメソッドの戻り値はDict[str, Any]でとりあえずは大丈夫でした。

def lambda_handler(event:Dict[str, Any], context) -> Dict[str, Any]:
    resultResponse:ResultResponse = ResultResponse(...)
    # 省略
    return resultResponse.toDict()

class ResultResponseBody(EntityBase, Generic[T]):
    def __init__(self:'ResultResponseBody', code:int, msg:str, data: object)  -> None:
        self.code:int = code
        self.msg:str = msg
        self.data:object = data

class ResultResponse(EntityBase, Generic[T]):
    def __init__(self:'ResultResponse', status:int, code:int, msg:str, data:object=None) -> None:
        # data:object={} とすると怒られるのでこの形が正しいらしい
        # https://docs.quantifiedcode.com/python-anti-patterns/correctness/mutable_default_value_as_argument.html
        if data is None:
            data = {}

        self.statusCode:int = status
        self.headers:Dict[str, str] = {  # Lambda_Proxyを有効にするのでCORSはAPI Gatewayではなくここで何とかする必要がある
            'Access-Control-Allow-Origin': '*'
        }
        #self.body:str = json.dumps(ResultResponseBody(code, msg, data)) # 自作クラスに対しては無力な模様
        self.body: str = ResultResponseBody(code, msg, data).toJson()

class EntityBase(Generic[T]):
    # from collections import namedtuple を使う方法もあるけど、、、
    def jsonToEntity(self:T, jsonString:str) -> T:
        dictObj = json.loads(jsonString)  # ファイルオブジェクトからのときはload 文字列からのときはloads
        for key in dictObj.keys():
            setattr(self, key, dictObj[key])
        return self

    # object的な感じで来たものを対象クラスに入れていく、keyはObjectの方をベースにする
    def translateTo(self:T, obj:Dict[str, Any]) -> T:
        for key in obj.keys():
            value:Any = obj[key]
            if value is None and isinstance(getattr(self, key), str):
                value = ''
            setattr(self, key, value)
        return self

    # なんか良い感じにjson.dumpsが動くかと思いきや、自作クラスは全く動かないという悲しい現実
    # relation等があって内部に別クラスを持つ場合はそのクラスがEntityBaseを継承していれば再帰的にうまくいくはず
    # それ以外の場合は。。。
    def toJson(self) -> str:
        res:Dict[str, Any] = {}
        for key in self.__dict__.keys():
            target:Any = getattr(self, key)

            if isinstance(target, EntityBase):
                res[key] = target.toJson()
                continue
            if isinstance(target, Decimal):
                decimalVal:Decimal = target
                strDecimalVal:str = str(decimalVal)
                if '.' not in strDecimalVal: 
                    res[key] = int(strDecimalVal)
                    continue
                else:
                    raise TypeError(key + strDecimalVal + " is invalid at base.py toJson")

            if isinstance(target, List):  # Listの中がentityの場合はここ
                listJson:str = ''
                for eachTarget in target:
                    if len(listJson) > 0:
                        listJson += ','
                    if isinstance(eachTarget, EntityBase):
                        listJson += eachTarget.toJson()
                    else:
                        listJson += json.dumps(eachTarget)
                res[key] = '[' + listJson + ']'
                continue

            if isinstance(target, Dict): # dataにEntityBaseを継承しないで直接Dictを突っ込んだ場合
                res[key] = json.dumps(target)
                continue

            res[key] = target

        return json.dumps(res)

    def toDict(self) -> Dict[str, Any]:
        ret:Dict[str, Any] = {}
        for key in self.__dict__.keys():
            ret[key] = getattr(self, key)
        return ret

まとめ

アップロード周りはlambda-uploaderの使い勝手が非常に良いです。
Type Hintsはかなり良いと思います。Pythonでも型に基づいてIDEのサポートをフルに受けたいという人にはお勧めです。

【2017年】マテリアルデザインのライブラリをかんたんに比較

こんにちは。ゴーリスト開発の飯尾です。

今回のお題は
マテリアルデザイン

material.io

現代っぽくスマートですね。
Googleが推奨しているというのだから乗るしかない、このビッグウェーブに
最近ではGoogleカレンダーのUIもマテリアルデザインに変わりましたね

GoogleカレンダーのWeb版がデザインを一新 | TechCrunch Japan

フレームワークどれ使う?

さて、このマテリアルデザインを実現するためのCSSフレームワーク
いろいろあります

おなじみBootstrapのCSSをマテリアルっぽくしたものとか

JSフレームワーク別に最適化されたものも

何使ったらいいんだ!とおもったのでちょっと調べてみました。

1. Material Design Lite

getmdl.io

  • Googleの開発者がメンテ
  • GitHub Star 20,006(ユーザー多め)
  • 開発がすでに「Material Components for the Web」に移行しているためサポートは限定的(ぐぬぬ)

2. Material Components for the Web

material.io

  • Material Design Liteの後続
  • ド公式のGoogleが管理してる最新版(安心)
  • GitHub Star 6,613(まだあまり普及してないのかね)

3. Materialize

materializecss.com

  • GiuHub Star 30,010(一番人気)
  • 充実のコンポーネント(マジパネッス)(リッチなWebサイト作るならこれ)
  • サイズはデカイ

4. MUI - Material Design CSS Framework

www.muicss.com

  • 軽量!簡素!
  • GitHub Star 3,679(う〜ん)
  • Angular対応してるのか〜とおもったらAngularJSだった(がっかりさせおって)



だいたいわかってきたぜえ

まあ私が個人的に使いたいのはAngularで組むWebアプリなんで
Angular Material 一択ですが!フハハ!ハハ!

皆さまも素敵なビッグウェ〜ブライフをお楽しみください🍌