SINKCAPITAL
SINKCAPITAL
employment company Blog
flutter(dart)を触ってみた感想
櫻井 裕司
2020-11-18 櫻井 裕司
tech

背景

 弊社では以前アプリ側のデータ収集知見を溜めるために自社iosアプリを作成していたのですが、 最近androidアプリのご要望も多かったのでflutterの勉強を開始しました。 iosユーザーが過半数を占める日本でandroid側のご要望される理由としては、 「全てのユーザーにリーチしたい」「価格の安いandroid端末を利用したい」 といった理由があるようです。 なおandroidのネイティブを勉強しなかった理由としては完全にCTOの趣味(新しい物好き)になります。 強いて言うとすれば今後弊社で開発予定のプロダクトにおいて、 ios・android両方で利用できることが便利であったことが理由として挙げられます。
 flutter(dart)の特徴は様々なサイトでまとめられているのですがjava・javascriptと似た言語のようで、 javaはほぼ触ったことがないですがそれ以外の言語との比較等しつつ、 flutter(dart)を触ってみた所感をまとめていければ良いかなと思います。

テストで作成した機能

 inputだけをして覚えられる性格ではないので、 今後プロダクトで使うであろう「認証機能(firebase)」「カメラ機能」の機能を持ったアプリを作りつつ勉強を行いました。

  • メインでカメラ画面があり、右上からログイン左下で撮影が行える
  • ログインは別画面で指定のアカウントでログインが行える(現状googleのみ)
camera

使ってみて気になった箇所

 Hello Worldレベルしかまだできていないですが、 その範囲で気になった点を以下にまとめてみようと思います。 (誤解している箇所も多いと思うので、修正コメント等いただけるととても嬉しいです)

デザインパターン

 swiftを始める際にデザインパターンを真似すると割とうまくいったので、 flutterでも同様にデザインパターン(BLoC)を真似するところから始めてみました。 今後理解が進んだ際に再度ちゃんとまとめてみようと思っていますが、 一番の特徴はVIEWの部分をwidgetと言う単位で細かく分けているところだと思います。 swiftはページ単位で要素を配置していましたが、 flutterは細かい要素を組見合わせて作る設計になっており、 どちらかと言うとHTMLの様に箱で管理するイメージに近いのだと思います。

画面遷移

 画面遷移についてはNavigatorと呼ばれるものを利用し、 画面移動(push)・画面を戻る(pop)を利用して画面遷移する様です。 swiftではsegueを利用していましたがなるべく一度表示した画面を再利用すると言う思想は同じ様です。 そのためswiftと同じ様に画面更新されない問題にはまりました。。。 一度表示した画面を更新をする場合は画面を戻る(pop)だけではなく、 明示的に更新( setState(() {}); )をしないといけない様です。 現時点では画面移動(push)をawaitを使って呼び出しその後ろに更新処理を入れているのですが、 そのやり方がいいのかはまだ判断がついていないです。

同期・非同期処理

 dart言語は基本的に同期で動くためログイン機能を追加しようとすると、 どうしても非同期処理を入れる必要がありました。 ( Firebase.initializeApp() を実行しないとログイン状態が取れないため) 詳しいやり方はFlutterでFirebaseを使うときのFirebase.initializeApp()の呼び方を参考にさせていただいたのですが、 Future を利用すればそのままNodejsのco的な記載方法ができるためとても便利でした。

触ってみた感想

 swiftの感覚で触るとかなり迷うところが多く、 同じアプリでもコードの思想が大きく違っているところはとても新鮮でした。 そしてflutterの売りでもあるios・android両方のシミュレーターで同じアプリが動かせる点はとても便利だと感じました。 まだまだコードの中身が綺麗に分離できていない点が多々あるので、 自社プロダクトを作りつつflutterのデザインパターンへの理解を深めていければと思います。
 最後に作成したコードをいくつか載せておくので、 気になった方はみてコメントをいただけると幸いです。 (なお実際はfirebaseを利用する際にいくつか設定が必要なため、コード単体ではエラーが出るので注意してください)

コード集

ディレクトリ構成

$ tree
.
├── app
│   └── widgets
│       ├── components
│       │   └── login_button.dart
│       └── screen
│           ├── camera.dart
│           ├── camera_display.dart
│           └── login.dart
└── main.dart

各種コード

import 'package:flutter/material.dart';
import 'package:test_app/app/widgets/screen/login.dart';
import 'package:test_app/app/widgets/screen/camera.dart';

void main() {
  // この一文を入れないとエラーになる
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'TEST',
        theme: ThemeData(
          primaryColor: Colors.blueGrey[800],
          visualDensity: VisualDensity.adaptivePlatformDensity,
        ),
        home: CameraHome(),
        routes: <String, WidgetBuilder>{
          '/camera': (BuildContext context) => CameraHome(),
          '/login': (BuildContext context) => LoginPage(title: 'firebase login'),
        });
  }
}
// firebase auth
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';

class LoginPage extends StatefulWidget {
  LoginPage({Key key, this.title}) : super(key: key);

  final String title;

  
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  final GoogleSignIn _googleSignIn = GoogleSignIn();
  final FirebaseAuth _auth = FirebaseAuth.instance;

  Future<User> _handleSignIn() async {
    GoogleSignInAccount googleCurrentUser = _googleSignIn.currentUser;
    try {
      if (googleCurrentUser == null)
        googleCurrentUser = await _googleSignIn.signInSilently();
      if (googleCurrentUser == null)
        googleCurrentUser = await _googleSignIn.signIn();
      if (googleCurrentUser == null) return null;

      GoogleSignInAuthentication googleAuth =
          await googleCurrentUser.authentication;
      final AuthCredential credential = GoogleAuthProvider.credential(
        accessToken: googleAuth.accessToken,
        idToken: googleAuth.idToken,
      );
      final User user = (await _auth.signInWithCredential(credential)).user;
      print("signed in " + user.displayName);

      return user;
    } catch (e) {
      print(e);
      return null;
    }
  }

  
  Widget build(BuildContext context) {
    return WillPopScope(
        onWillPop: () {
          Navigator.of(context).pop("戻るアイコンからの遷移");
          return Future.value(false);
        },
        child: Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  RaisedButton(
                    child: Text('Sign in Google'),
                    onPressed: () {
                      _handleSignIn()
                          .then((User user) => Navigator.of(context).pop("戻るアイコンからの遷移"))
                          .catchError((e) => print(e));
                    },
                  ),
                ]),
          ),
        ));
  }
}
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'package:path/path.dart' show join;
import 'package:path_provider/path_provider.dart';

import 'package:test_app/app/widgets/screen/camera_display.dart';
import 'package:test_app/app/widgets/components/login_button.dart';

class CameraHome extends StatefulWidget {
  // final CameraDescription camera;

  // const CameraHome({Key key, @required this.camera}) : super(key: key);
  const CameraHome({Key key}) : super(key: key);

  
  State<StatefulWidget> createState() => CameraHomeState();
}

class CameraHomeState extends State<CameraHome> {
  // デバイスのカメラを制御するコントローラ
  CameraController _cameraController;

  LoginButton loginButton = new LoginButton();

  var action;

  // コントローラーに設定されたカメラを初期化する関数
  Future<void> _initializeCameraController() async {
    // デバイスで使用可能なカメラの一覧を取得する
    final cameras = await availableCameras();

    // 利用可能なカメラの一覧から、指定のカメラを取得する
    final firstCamera = cameras.first;

    // コントローラを初期化
    _cameraController = CameraController(
        // 使用するカメラをコントローラに設定
        firstCamera,
        // 使用する解像度を設定
        // low : 352x288 on iOS, 240p (320x240) on Android
        // medium : 480p (640x480 on iOS, 720x480 on Android)
        // high : 720p (1280x720)
        // veryHigh : 1080p (1920x1080)
        // ultraHigh : 2160p (3840x2160)
        // max : 利用可能な最大の解像度
        ResolutionPreset.max);
    // コントローラーに設定されたカメラを初期化
    return _cameraController.initialize();
  }

  
  void initState() {
    super.initState();
  }

  
  void dispose() {
    // ウィジェットが破棄されたタイミングで、カメラのコントローラを破棄する
    _cameraController.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('カメラ撮影画面'),
        actions: [loginButton],
      ),
      // FutureBuilderを実装
      body: FutureBuilder<void>(
        future: _initializeCameraController(),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            // カメラの初期化が完了したら、プレビューを表示
            return CameraPreview(_cameraController);
          } else {
            // カメラの初期化中はインジケーターを表示
            return const Center(child: CircularProgressIndicator());
          }
        },
      ),
      floatingActionButton: Column(
        verticalDirection: VerticalDirection.up, // childrenの先頭を下に配置
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          FloatingActionButton(
            child: const Icon(Icons.camera_alt),
            heroTag: 'camera',
            // ボタンが押下された際の処理
            onPressed: () async {
              try {
                // 画像を保存するパスを作成する
                final path = join(
                  (await getApplicationDocumentsDirectory()).path,
                  '${DateTime.now()}.png',
                );
 
                // カメラで画像を撮影する
                await _cameraController.takePicture(path);
 
                // 画像を表示する画面に遷移
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => CameraDisplay(imgPath: path),
                  ),
                );
              } catch (e) {
                print(e);
              }
            },
          ),
          Container(
            // 余白のためContainerでラップ
            margin: EdgeInsets.only(bottom: 16.0),
            child: FloatingActionButton(
              child: const Icon(Icons.settings),
              heroTag: 'setting',
              onPressed: () {
                showDialog(
                  context: context,
                  builder: (context) {
                    return AlertDialog(
                      title: Text('サンプルダイアログ'),
                      content: Text('アプリを閉じますか'),
                      actions: <Widget>[
                        FlatButton(
                          child: Text("CANCEL"),
                          onPressed: () => Navigator.pop(context),
                        ),
                        FlatButton(
                          child: Text("OK"),
                          onPressed: () => Navigator.pop(context),
                        ),
                      ],
                    );
                  },
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}
import 'package:flutter/material.dart';
import 'dart:io';

class CameraDisplay extends StatelessWidget {
  // 表示する画像のパス
  final String imgPath;

  // 画面のコンストラクタ
  const CameraDisplay({Key key, this.imgPath}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Picture'),
        ),
        body: Column(
          // Imageウィジェットで画像を表示する
          children: [Expanded(child: Image.file(File(imgPath)))],
        )
    );
  }
}
import 'package:flutter/material.dart';

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';

class LoginButton extends StatefulWidget {
  final LoginButtonState abs = LoginButtonState();

  void refresh() {
    debugPrint("abs refresh");
    abs.refresh();
  }

  
  LoginButtonState createState() => abs;
}

class LoginButtonState extends State<LoginButton> {

  final GoogleSignIn _googleSignIn = GoogleSignIn();

  void refresh() {
    debugPrint("refresh");
    setState(() {});
  }

  Future<void> _handleSignOut() async {
    debugPrint("sign out");
    try {
      await FirebaseAuth.instance.signOut();
      await _googleSignIn.signOut();
    } catch (e) {
      debugPrint(e);
    }
    refresh();
  }

  
  Widget build(BuildContext context) {
    return FutureBuilder(
        // Initialize FlutterFire:
        future: Firebase.initializeApp(),
        builder: (context, snapshot) {
          if (snapshot.hasError) {
            debugPrint(snapshot.error.toString());
            return Center(
                child: Text(
              snapshot.error.toString(),
              textDirection: TextDirection.ltr,
            ));
          }

          // Once complete, show your application
          if (snapshot.connectionState == ConnectionState.done) {
            final User currentUser = FirebaseAuth.instance.currentUser;
            if (currentUser == null) {
              return IconButton(
                icon: Icon(Icons.login),
                onPressed: () async {
                  final result = await Navigator.pushNamed(context, "/login");
                  refresh();
                },
              );
            } else {
              return IconButton(
                icon: Icon(Icons.logout),
                onPressed: () {
                  _handleSignOut().catchError((e) => print(e));
                },
              );
            }
          }
          // Otherwise, show something whilst waiting for initialization to complete
          return Center(
              child: Text(
                'Loading ...',
                textDirection: TextDirection.ltr,
              ));
        });
  }
}

参考リンク

SinkCapitalではデータに関する支援を行っています

弊社はスペシャリスト人材が多く在籍するデータ組織です。 データ分析や分析基盤の設計などでお困りの方がいらっしゃれば、 まずは無料で、こちらから各分野のスペシャリストに直接相談出来ます。

Azure DevOps上でterraformを用いたAzureのIaC管理方法
櫻井 裕司
2024-03-23 櫻井 裕司
tech
企業内データを参照するChatGPTによる社内Q&Aシステムを構築または利用する際のデータ管理について特に注意すべき観点を整理します。特にAzureを利用することを前提にシステムを構築する際のポイントも併せて紹介します。
ChatGPTを用いた企業内システム構築におけるデータ管理の心得
サカモト
2024-02-07 サカモト
tech
企業内データを参照するChatGPTによる社内Q&Aシステムを構築または利用する際のデータ管理について特に注意すべき観点を整理します。特にAzureを利用することを前提にシステムを構築する際のポイントも併せて紹介します。
BIツール機能比較〜Tableau VS Looker Studio〜
髙津 未紗希
2023-11-04 髙津 未紗希
tech
近年ではBIツールの需要が高まると同時に様々なBIツールが増えていますが、その中でもTableauとLooker Studioは利用者の多い主要ツールとなっています。そこで今回はTableauとLooker Studioを機能別に比較します。
Terraform Cloudを利用した、CI/CD戦略と最適なterraformディレクトリについて考えてみた。
松戸 誠人
2023-04-20 松戸 誠人
tech
terraformリソースとクラウドへの適応は様々な手段がある。Actionsでクラウドにapplyされるなど、その中でも管理しやすいと考える、Terraform Cloudを利用したCI/CD及びterraformのディレクトリ設計及び、ブランチ戦略について紹介する。
TerraformとGitHub Actions(CI/CD)を用いたGitHub repositoryの管理
井上 聖士
2023-04-14 井上 聖士
tech
今回は、TerraformのCI/CDをGitHub Actionsを利用して構築する方法についてご紹介します。Terraformを使ってGitHubのリポジトリを作成し、GitHub Actionsを使ってCI/CDを自動化する方法を実際の手順とともに解説します。この記事を読むことで、TerraformとGitHub Actionsを使った開発の流れを学習することができます.最終的には、以下の画像のように、GitHub上で管理されるリポジトリを作成することができます。
GitHub Actionsを用いてReactのサイトをGitHub Pagesに公開する方法
井上 聖士
2023-04-13 井上 聖士
tech
今回はReactを使用したWebサイトの構築から、GitHub Actionsを利用した自動化ビルドやデプロイ、そしてGitHub Pagesでの公開方法まで、一連の流れを紹介します。この記事を読むことで、Reactを使用してWebサイトを作成する方法や、GitHub ActionsによるCI/CDの構築方法を学ぶことができます。最終的には、以下のようなWebサイトをGitHub Pages上で公開することができます。
【事例紹介】クックビズ株式会社様の分析環境の新規構築をお手伝いさせていただきました
櫻井 裕司
2023-03-15 櫻井 裕司
tech case
フード関連業に特化した有料職業紹介事業などを提供するクックビズ株式会社様は、15周年を迎え、新コーポレートアイデンティティを制定など大きな変革を行っていました。本体機能とともに力をいれたのが分析環境の刷新であり、今後会社をデータから支える分析環境づくりの方法を模索されており、弊社ではデータ分析環境構築のお手伝いをさせていただきました。今回、弊社はこれらの課題に対してSinkCapitalのサポートを依頼してくださったデータチームの上岡さん・角田さん・宮川さんに導入結果や使用感について伺いました。
Pythonの因果分析ライブラリCausalNexの紹介
田中
2023-03-07 田中
tech
ベイジアンネットワークは、ディープラーニング(深層学習)等とは違い変数間の因果関係を捉える事が出来るため、病気の原因分析、気象予測、マーケティングなどで活用されています。今回は、Pythonでのベイジアンネットワークを用いた因果分析について紹介します。
GCP上のWebログデータ処理パイプライン:生データ処理から機械学習まで
謝暁鋒(シャギョウホウ)
2023-03-01 謝暁鋒(シャギョウホウ)
tech
不定期でGoogleCloudStorageにアップロードされているWebログデータに対し、毎日0時にComposer内ではDataprocがデータを前処理しBigqueryにアウトプットします。その後VertexAIにモデルのトレーニングを行い、処理完了後slackに結果を投げます。
世界各国で利用されるCRMツール、Hubspotを既存の自社サイトに対して導入してみました。
櫻井 裕司
2023-01-23 櫻井 裕司
tech
世界各国で利用されるマーケティングプラットフォームツールであるHubspotを弊社の自社サイトに導入してみました。マーケティング、営業、カスタマーサービスなど様々なサービスがありますが、今回は主にサイト上でのリード獲得部分の導入について説明ささせていただければと思います。
海外で有名なデータ統合Saasプロダクトであるfivetranを利用してみました
櫻井 裕司
2023-01-12 櫻井 裕司
tech
海外で有名なデータ統合Saasプロダクトであるfivetranを利用してデータ連携をしてみました。日本では類似のサービスとしてtroccoがありますが、troccoとの違いも整理していければと思っています。
【事例紹介】freee株式会社のデータ分析業務をお手伝いさせていただきました
櫻井 裕司
2022-12-28 櫻井 裕司
tech case
人事労務・会計などを含むクラウドERPを提供するfreee株式会社(以下、freee)は、既存事業の伸びに加えて受発注やタスク管理など新規領域開拓も加わり成長を続けています。それに伴いデータ分析環境の保守管理や、データ利用者からの問い合わせ対応に取られる時間が増えてしまい、分析業務に当てる時間が圧迫されていました。今回、これらの課題に対してSinkCapitalのサポートを依頼してくださったAnalyticsチームの鎌田さん・福田さん・鈴木さんに導入結果や今後の見通しについて伺いました。
Pipedrive Web Formsでutmを取得する方法
丸山 慎也
2022-12-07 丸山 慎也
tech
Pipedrive には、ウェブフォーム(Pipedrive Web Forms) という機能があります。今回はこの Pipedrive Web Forms の送信時に、utmを取得する方法についてまとめました。
データ周りで話題のdbt(data build tool)をBigQueryを使ってみました
櫻井 裕司
2022-12-05 櫻井 裕司
tech
ETL・ELTのLoad部分を担うオープンソースサービスであるdbtを使ってみて、既存のサービスとの比較を行いました。既存のサービスにない多くの特徴を持っていますので、もし気になった方はぜひ見ていただければと思います。
【事例紹介】IVRy様の分析基盤データパイプラインの設計・開発をお手伝いさせていただきました
櫻井 裕司
2022-11-23 櫻井 裕司
tech case
電話自動応答サービスを展開されているIVRy様に対し、弊社でデータパイプライン構築のお手伝いさせていただきました。その中で重視した考え方や設計思想、また構築後の使用感などを記事にまとめさせていただきましたので、データパイプラインをご検討中の方は是非ご参考にしていただけますと幸いです。
Snowflakeにterraformを導入する方法
櫻井 裕司
2022-10-08 櫻井 裕司
tech
0からSnowflakeにterraformを導入した際の方法をご紹介します。Snowflake独自の注意点なども記載させていただきましたので、そちらもご参考いただけると幸いです。
BQにおけるSQL検算を効率化する無料chrome拡張機能をリリースいたしました
櫻井 裕司
2022-09-01 櫻井 裕司
tech
BigQueryのjoin句を含むstandardSQLを入力することで、join前後でのレコード数の変化を返すSQLを自動でクリップボードにコピーする無料chrome拡張機能をリリースいたしました。
社内ドキュメントにNotionを導入して感じた事
櫻井 裕司
2022-04-02 櫻井 裕司
tech
社内ドキュメントをNotionに寄せることで見えてきたメリット・デメリットをまとめていきたいと思います。また使う中で感じたいくつかの要望もまとめていこうと思います。
「BIツール」活用 超入門 Google Data Portalではじめるデータ集計・分析・可視化 第3章 BIツールに関する知識をつける
白井 透
2022-03-31 白井 透
techinternlearning
【「BIツール」活用 超入門 Google Data Portalではじめるデータ集計・分析・可視化 第3章】現在長期インターンをさせてもらっているSinkCapitalさんの方で、データ系の業務に携わることになりそうなのですが、それの準備期間として紹介していただいた本をまとめていきたいと思います。
「BIツール」活用 超入門 Google Data Portalではじめるデータ集計・分析・可視化 第2章 さまざまな分析をしてみよう
白井 透
2022-03-30 白井 透
techinternlearning
【「BIツール」活用 超入門 Google Data Portalではじめるデータ集計・分析・可視化 第2章】現在長期インターンをさせてもらっているSinkCapitalさんの方で、データ系の業務に携わることになりそうなのですが、それの準備期間として紹介していただいた本をまとめていきたいと思います。
「BIツール」活用 超入門 Google Data Portalではじめるデータ集計・分析・可視化 第1章 分析ダッシュボードを作ってみよう
白井 透
2022-03-29 白井 透
techinternlearning
【「BIツール」活用 超入門 Google Data Portalではじめるデータ集計・分析・可視化 第1章】現在長期インターンをさせてもらっているSinkCapitalさんの方で、データ系の業務に携わることになりそうなのですが、それの準備期間として紹介していただいた本をまとめていきたいと思います。
Ruby on Rails チュートリアル第14章をやってみて & まとめ
白井 透
2022-02-20 白井 透
techinternlearning
【Ruby on rails 第14章】インターン先の方から、「これやっとけば、だいぶいい感じだよ!」と言われたので、Ruby on railsのチュートリアルをやってみたいと思います。
Ruby on Rails チュートリアル第13章をやってみて
白井 透
2022-02-20 白井 透
techinternlearning
【Ruby on rails 第13章】インターン先の方から、「これやっとけば、だいぶいい感じだよ!」と言われたので、Ruby on railsのチュートリアルをやってみたいと思います。
Ruby on Rails チュートリアル第12章をやってみて
白井 透
2022-02-19 白井 透
techinternlearning
【Ruby on rails 第12章】インターン先の方から、「これやっとけば、だいぶいい感じだよ!」と言われたので、Ruby on railsのチュートリアルをやってみたいと思います。
Ruby on Rails チュートリアル第11章をやってみて
白井 透
2022-02-19 白井 透
techinternlearning
【Ruby on rails 第11章】インターン先の方から、「これやっとけば、だいぶいい感じだよ!」と言われたので、Ruby on railsのチュートリアルをやってみたいと思います。
Ruby on Rails チュートリアル第10章をやってみて
白井 透
2022-02-18 白井 透
techinternlearning
【Ruby on rails 第10章】インターン先の方から、「これやっとけば、だいぶいい感じだよ!」と言われたので、Ruby on railsのチュートリアルをやってみたいと思います。
Ruby on Rails チュートリアル第9章をやってみて
白井 透
2022-02-16 白井 透
techinternlearning
【Ruby on rails 第9章】インターン先の方から、「これやっとけば、だいぶいい感じだよ!」と言われたので、Ruby on railsのチュートリアルをやってみたいと思います。
Ruby on Rails チュートリアル第8章をやってみて
白井 透
2022-02-14 白井 透
techinternlearning
【Ruby on rails 第8章】インターン先の方から、「これやっとけば、だいぶいい感じだよ!」と言われたので、Ruby on railsのチュートリアルをやってみたいと思います。
Ruby on Rails チュートリアル第7章をやってみて
白井 透
2022-02-14 白井 透
techinternlearning
【Ruby on rails 第7章】インターン先の方から、「これやっとけば、だいぶいい感じだよ!」と言われたので、Ruby on railsのチュートリアルをやってみたいと思います。
Ruby on Rails チュートリアル第6章をやってみて
白井 透
2022-02-13 白井 透
techinternlearning
【Ruby on rails 第6章】インターン先の方から、「これやっとけば、だいぶいい感じだよ!」と言われたので、Ruby on railsのチュートリアルをやってみたいと思います。
Ruby on Rails チュートリアル第5章をやってみて
白井 透
2022-02-12 白井 透
techinternlearning
【Ruby on rails 第5章】インターン先の方から、「これやっとけば、だいぶいい感じだよ!」と言われたので、Ruby on railsのチュートリアルをやってみたいと思います。
Ruby on Rails チュートリアル第4章をやってみて
白井 透
2022-02-11 白井 透
techinternlearning
【Ruby on rails 第4章】インターン先の方から、「これやっとけば、だいぶいい感じだよ!」と言われたので、Ruby on railsのチュートリアルをやってみたいと思います。
Ruby on Rails チュートリアル第3章をやってみて
白井 透
2022-02-08 白井 透
techinternlearning
【Ruby on rails 第3章】インターン先の方から、「これやっとけば、だいぶいい感じだよ!」と言われたので、Ruby on railsのチュートリアルをやってみたいと思います。
Ruby on Rails チュートリアル第2章をやってみて
白井 透
2022-02-07 白井 透
techinternlearning
【Ruby on rails 第2章】インターン先の方から、「これやっとけば、だいぶいい感じだよ!」と言われたので、Ruby on railsのチュートリアルをやってみたいと思います。
Ruby on Rails チュートリアル第1章をやってみて & 自己紹介
白井 透
2022-02-07 白井 透
techinternlearning
【Ruby on rails 第1章】インターン先の方から、「これやっとけば、だいぶいい感じだよ!」と言われたので、Ruby on railsのチュートリアルをやってみたいと思います。
Nuxt上でのd3を利用した散布図の作成方法
櫻井 裕司
2021-10-29 櫻井 裕司
techdataAnalytics
クリック可能な散布図をNuxtjs上で作成する場合にd3.jsが汎用性が高く便利でした。利用するにあたって難しかった点などを備考録としてまとめています。
アクセスログを可視化しGAのデータを直感的に理解できる型態にする試み(ネットワーク型)
櫻井 裕司
2021-09-05 櫻井 裕司
techdataAnalytics
ビジネスに活きる分析を進める上で弊社では「理解できる」ことを重要と考えており、特に直感的理解は可視化を進める上で特に重要だと考える内容の一つです。弊社では様々なお客様のデータ分析を進める上で常により示唆の大きい可視化を追求しており、今回はその中で最近試みているネットワーク側の可視化についてまとめたいと思います。
代表櫻井による特別講演会が白陵高等学校で開かれました
櫻井 裕司
2021-07-31 櫻井 裕司
eventpersonal
2021年の夏に兵庫県の私立白陵高等学校において、代表櫻井による特別講演会を開催いたしました。今振り返って高校の頃の自分に伝えたいことについてお話しました。
Nuxtで動的ページを随時追加する場合にNot Foundとなる
櫻井 裕司
2021-05-31 櫻井 裕司
tech
Nuxtで動的ページを登録する方法はありますが、登録後に随時コンテンツが追加される際はNot Foundとなってしまうので、そう言った際の対処方法について
GKEをやめてCloud Runを始めてみました
櫻井 裕司
2021-04-19 櫻井 裕司
tech
firebaseで構築したシステムの裏で動かすバッチの負荷が大きく、cloud functionsで終わらなかったためCloud Runを利用してみました。動作確認までの知見等を雑多にまとめてみました。
AWSをやめてfirebaseを使い始めて感じたメリットやデメリットとそれの対応策(LT登壇内容)
櫻井 裕司
2021-03-26 櫻井 裕司
techeventpersonal
みそかつウェブ・GDG Nagoya主催の「around firebase」とCloud Native Nagoya主演の「Cloud Native Nagoya」にてfirebaseのLTをさせていただきました。そこで会話させていただいたfirebaseを使い始めて感じたメリット・デメリットについてまとめています。
PWA+SPAのwebアプリ作成にnuxtjs+firebaseがめちゃ便利だった
櫻井 裕司
2021-01-16 櫻井 裕司
tech
PWA+SPAのwebアプリを作る際にnuxt.js+firebaseを合わせて利用すると便利だったので知見を書き留めています
s3のhostingでPWAを導入する方法
櫻井 裕司
2020-12-19 櫻井 裕司
tech
アプリ作成時にpwaが比較されることが多かったですが、実際にpwaを実装した経験がなかったため今回自社サイトをPWA化してみました。
dockerでseleniumを動かしてみる(chrome_headless)
櫻井 裕司
2020-12-06 櫻井 裕司
tech
seleniumの相談をいただくことが増えたため、seleniumの勉強もかねてdockerでの実行テストを行いました
THE DECKのイベントにお邪魔させていただきました
本林 秀和
2020-12-05 本林 秀和
eventpersonal
大学コンソーシアム大阪のイベント@The DECK にお邪魔してきました
代表本林による特別講演会が滝高校で開かれました
本林 秀和
2020-11-07 本林 秀和
eventpersonal
2020年11月7日(土)愛知県の私立滝高校において、代表本林による特別講演会を開催いたしました。IT業界やデータサイエンスについてお話しました。
AWS・GCPを選ぶ際の観点
櫻井 裕司
2020-10-28 櫻井 裕司
tech
AWSかGCPを選ぶ際の観点について書き留めておこうと思います
CloudFormationとterraformの比較
櫻井 裕司
2020-10-04 櫻井 裕司
tech
AWS CloudFormationとterraformの両方を使ってみて感じた違いをまとめてみました。
iosのcallkit周りでできること
櫻井 裕司
2020-08-24 櫻井 裕司
tech
新規事業を検討する上でios(swift)の電話周りでできることを調査したため、調査結果をブログとして残しています。
総務省特定サービス産業実態調査のデータ分析
櫻井 裕司
2020-07-18 櫻井 裕司
techdataAnalytics
総務省がAPIで市場データを公開しており、分析技術向上と市場感を養うことを目的に定期的に分析を行なっていこうと思います。今回は「特定サービス産業実態調査」について見ていこうと思います。
「お絵かきつみ木バトル」をリリースしました
櫻井 裕司
2020-07-12 櫻井 裕司
techapp
タスク管理を二次元的に行うアプリ「お絵かきつみ木バトル」をリリースしました。SinkCapitalはデータコンサルですが、知見蓄積のため様々な媒体での実験的開発を行っています
総務省工業統計調査のデータ分析
櫻井 裕司
2020-07-11 櫻井 裕司
techdataAnalytics
総務省がAPIで市場データを公開しており、分析技術向上と市場感を養うことを目的に定期的に分析を行なっていこうと思います。今回は「工業統計調査」について見ていこうと思います。
総務省サービス産業動向調査のデータ分析
櫻井 裕司
2020-07-08 櫻井 裕司
techdataAnalytics
総務省がAPIで市場データを公開しており、分析技術向上と市場感を養うことを目的に定期的に分析を行なっていこうと思います。初回は「サービス産業動向調査」について見ていこうと思います。
タスク管理アプリ「タスククロス」をリリースしました
櫻井 裕司
2020-04-08 櫻井 裕司
techapp
タスク管理を二次元的に行うアプリ「タスククロス」をリリースしました。SinkCapitalはデータコンサルですが、知見蓄積のため様々な媒体での実験的開発を行っています
【terraform】gcpでcicd環境を構築する方法
櫻井 裕司
2020-01-04 櫻井 裕司
tech
企業サイトはAWSを利用しているのですが、要件によってはGCPの方が適している場合もあるため、GCPでのcicd構築も行いました。AWSと比較しつつ説明しているため是非ご参考にしてみてください。
【合格体験記】GCP_Cloud_Archtectに受かりました
櫻井 裕司
2019-12-23 櫻井 裕司
personalqualification
Google Professional Cloud Architectに合格したので、勉強法別のコスパをまとめてみました。
AWSでサブドメインなし(wwwなし)からサブドメインあり(wwwあり)へのリダイレクト設定
櫻井 裕司
2019-12-23 櫻井 裕司
tech
もともと企業サイトがサブドメインありで公開していたが、サブドメインなしでもエラーなく接続できるように設計。terraformで作成しているので是非ご参考ください。
マークダウンで記事を書けるようにしてみた
櫻井 裕司
2019-12-16 櫻井 裕司
tech
ホームページのブログをマークダウンを使用してかけるようにしました。gatsbyなどもありますが、今回はお手製cicd+pythonを使用してライトに作成しました。
Copyright © SinkCapital 2024
ご相談はこちらから 一緒に働きたい方はこちら