よしたく blog

ほぼ週刊で記事を書いています

登壇の技術を勉強する会#1 に参加してきた!

登壇の技術を勉強する会 #1 に参加してきました

engineers.connpass.com

サブタイトルに「エンジニアの登壇を応援する会 登壇準備編」とあり、まだ登壇をしたことのない自分としては興味深いものとなりました。

今回のテーマは『過去にカンファレンスや勉強会に登壇してきた先人たちが、登壇テクニックを伝授する』です。 たくさんの#激つよエンジニアたちが、自らの登壇テクニックを語り尽くします。 普段は絶対に聞けないような面白い話がたくさん聞けますので是非ご参加ください╭( ・ㅂ・)و

謎の日本酒枠

参加枠が少し変わっているので触れておかなければいけない気がしました。結論から言うと、一般参加者枠と日本酒枠がありました。自由でいいなぁと思いました。ズラッと並んだ日本酒を参加費500円で飲み比べていいなんて贅沢すぎて、持ち込んでいただいた方に頭が上がりません。お酒呑むけど詳しくない自分にとっては、勉強になることがたくさんありました。皆さん思い思いの日本酒を持ってきていて、熱弁する様子は酒蔵の人と話しているような気分でした。

なぜか、勉強会当日に提供された日本酒についてまとめてあるレポートがあるので、詳細はこちら…

kawahara-ci.hatenablog.com

発表資料

プロットと笑い

The things to be careful when making slides

人見知りでコミュ障かつ口下手な激よわエンジニアが気づいたら登壇を重ねていた件

アウトプットを継続するためにやっている 10 のこと

スライドを武器に。

余談

やっぱり、感想ツイートを残しておくのいいですね。まとめるときに楽だ。これからも継続していこう。

感想

全体的にとても満足いく内容でした! 個人的には最後のスライドを武器に。が非常に良かったです。理由は、自分自身が学生時代に教え込まれたスライドの作り方について言語化されていたからです。

1スライド1メッセージとか

捨てる勇気とか

ストーリーについてとか

整列の話とか

プレゼンは、このあたりがちゃんとされていないと聞く耳ならぬ、見る目が保たないので大切だと思います。少なくとも自分は話が全く入ってこなくなってしまう。自分も気をつけたいところです。

自分に足りないと感じたところ

自分にないと感じたものについては、配色です。いつもテーマカラーをえいやっと決めて、あとは適当…違うと思ったら変えて…の繰り返しです。色についても大切に扱っていきたい。

あとは、プレゼンの内容となる技術テーマだなぁ。難しいことを発表しなきゃ満足してもらえないと思って、なかなか踏み出せないしなぁ。聞く側に回りすぎて、頭でっかちになっているのが原因かもしれないけど…

まとめ

  • 登壇の技術を勉強する会 #1 に参加した!
  • 自分に足りないことを気付けたいい会だった!
  • 日本酒は美味しい

第10回 Raspberry pi もくもく会 に参加してきた

都合が合わずに久々の参加となりました、Raspberry pi もくもく会

raspberry-pi-moku.connpass.com

最近触っていなかったこともあって、心機一転Raspberry Pi Model B+を購入して参加しました

https://twitter.com/yoshitaku_jp/status/1043365520043438082

久々にお会いする方も多く、楽しい会でした。

自分はrasbianのインストールで終わってしまいました。

途中うまくいかないタイミングが合ったのですが、原因はOSの書き込みが上手くいっていなくて、カーネルパニックを起こしていました。 ネットワークに繋がらないと嘆いていたのですが、原因は別のところにありました。 早めにモニターに繋いでいなかったら、終わるまでやっていたでしょう…

成果発表では、出せる成果もないのでみなさんの完成品をすごいなぁと眺めていました。


自分は当日何やりたかったかというと、

donkeycar というものの触りを作りたかったです。

www.sroboto.com

docs.donkeycar.com

機械学習させて、そのルートを自動走行する感じかな。 TAMIYA製の車の土台(カーシャーシ?)とかが必要なので費用が結構掛かりそう。

名古屋電子工作の会さんがQiitaにまとめてくださっているものを参考にちょこちょこと進めていきます

qiita.com

感謝です。

DevOps Hands-on vol.2 〜CI/CD 環境構築ハンズオン〜 に参加してきた!

f:id:yoshitaku_jp:20180920170925p:plain

DevOps Hands-on vol.2 〜CI/CD 環境構築ハンズオン〜 に参加してきました!

classmethod.connpass.com

DevOps Hands-onとは

クラスメソッド株式会社が主催する、DevOps の勉強会です。 参加者自身で AWS CodePipeline, AWS CodeBuild を使ったCI / CD パイプラインを構築し、継続的インテグレーション、継続的デリバリーのメリットを実際に体感して頂けるハンズオンとなっています。

今回のハンズオンでは、AWS CodePipeline, AWS CodeBuildを使って、デプロイをすることを学びました。 CI/CDは聞いたことあったし、CI/CDもどきのようなことはプライベート学習で実践していましたが、AWSの機能を使ってということなので興味があり参加してみました。

今回の内容です。

  1. ハンズオンで構築する構成の簡単な紹介
  2. サンプルアプリケーションのフォーク及びクローン
  3. ハンズオン用環境構築用の CloudFormation の実行
  4. 手動デプロイしてみる(講師が実演します)
  5. CodePipeline によるパイプラインの構築および自動デプロイの実行
  6. テストが失敗すると自動デプロイが止まるのを確認
  7. 再度正しいコードに戻して自動デプロイ

上記の流れでハンズオンが進んでいきました。

個人的によかったのは4. 手動デプロイしてみる(講師が実演します)です。講師の方が手動でデプロイすることで手作業のリスクや面倒さを丁寧に教えてくれます。この作業が自動化されたら楽だなぁなんて思いながら見ていました。

構成は画像のとおりです。

f:id:yoshitaku_jp:20180920170928p:plain
ハンズオンで扱うもの

ハンズオンでは設定値をポチポチと設定していきましたが、これだけでビルドからデプロイまでやってくれるなんて便利だなぁと思いました。

ハンズオンは資料も公開されているので、当日の雰囲気について。参加者も普段からAWSを触っている人が多めでした。クラスメソッドさんの社員さんも参加していて、ハンズオンが終わったあとの質疑応答では活発にやり取りしていました。個人的にはこれがすごく好印象で、みんなでワイワイ技術について検証していくっていう雰囲気が最高でした。講師の方の「個人的に気になってしまうので、やってみます」という発言はクスクスきました。デプロイの前に手動での承認ボタンを設置でき、承認ボタンの待ちが複数できたときはどうなるのかとか、複数のプッシュが来たときはどうなるのかとか、みんなで疑問を共有し、すぐ実行する。全員が参加者って言う感じ。またクラスメソッドさん主催で別のハンズオンがあればぜひとも参加してみたいと思いました。

ハンズオン資料はGitHubにて公開されているので、気になる方は自分の手で動かして見るのもいいと思います!自分のAWSでやっても1$かからないそうです。

github.com

まとめ - CI/CD 環境構築ハンズオン〜 に参加した - AWS CodePipelineとAWS CodeBuildを使うと簡単にデプロイすることができる - 自分でもCI/CD 環境構築を構築してみたい

第2回 モグモグDjango に参加してきた!

f:id:yoshitaku_jp:20180711100334p:plain

1週間ほど経ってしまいましたが…

第2回 モグモグDjangoに参加してきました!

mogumogu-django.connpass.com

もぐもぐしながらDjangoについてもくもくと作業をする会です!

1人で静かに開発に打ち込みたい,という方には,ガヤガヤしていて集中できないかもしれませんのでご了承下さい

とありますが、個人的には周りの参加者の人に相談しやすいので良い会だと思います!

会の始めに参加者同士で持ち寄ったお菓子などを広げ、自己紹介や今日やることを発表するアイスブレイクタイムも好きです。

主催者の中に、現場で使えるDjangoの教科書を執筆したakiyokoさんがいらっしゃり、気さくに質問にも答えてくださいます。

twitter.com

自分はDjango-allauthの使い方について質問しまくっていました。

Installation — django-allauth 0.32.0 documentation

技術書典5では、応用編を出す予定のようですので、気になる人は行ってみましょう。

この日は集中できる環境と、気軽に質問できたこともあり、問題が一つ解決できて帰ることができました!

第3回 モグモグDjangoがありましたら、また参加したいと思います!

コードの修正がめんどくさいなら、autopep8で自動修正

f:id:yoshitaku_jp:20180728144033p:plain

前回PythonのコードがPEP8に準拠しているか確認するツールをブログに書きました!

yoshitaku-jp.hatenablog.com

準拠してないところがわかったのはいいんですけど、修正する箇所が沢山あったら直すのめんどくさいなぁなんて思います。気をつけるのはもちろんですが、だめなところがあったなら自動で直しておいて欲しいです。

と思ったら、これまた便利なツールが…

github.com

さっそくためしてみました。

インストール

pip install autopep8

pycodestyleが必要なので入ってなかったら、こちらもインストール

pip install pycodestyle

使う

autopep8 --in-place <filename>

結果

f:id:yoshitaku_jp:20180915132902p:plain
空白が適切に扱われる

f:id:yoshitaku_jp:20180915132639p:plain
Trueも削除される

最高!!

いっぺんにたくさんのファイルを修正するとき

たくさんのファイルをいっぺんに修正したいなと調べていたら、すでにワンライナーでやっているかたがいらっしゃいました

http://momijiame.tumblr.com/post/42168625947/python-のソースコードを自動で-pep8-に準拠させるツール-autopep8
momijiame.tumblr.com

今はpep8ではなく、pycodestyleを使うので先頭だけ修正して pycodestyle <dirctory> | cut -d: -f1 | sort | uniq | xargs autopep8 -i

pycodestyle . | cut -d: -f1 | sort | uniq | xargs autopep8 -i

ありがたい

まとめ

  • pycodestyleとautopep8の力を借りて、適切なプログラムコードを書こう
  • testを回したときに修正されるようにするのもやりたい

コードをきれいにするため、pycodestyleを使ってみた

f:id:yoshitaku_jp:20180728144033p:plain

プログラムコードはきれいにしておきたいですよね。そのために様々な言語で規約もあるかと思います。 Pythonを独学で書いている自分としてはサンプルコードを見て真似して感覚的に覚えていったりもしました。正しいものがあるなら、それを見て正しく書いていきたいし、自分の目視じゃなくてチェックもして欲しい!そんなときに便利なのがpycodestyleです!

github.com

これを使えば、自分が今書いてるコードがPEP8にそって書かれているかチェックしてくれます!

インストール

pip install pycodestyle

使い方

対象のhoge.pyファイルをチェックするときは下のように実行します!

pycodestyle hoge.py

試しに自分で作っているスクレイピングのツールを実行してみると…

yoshitaku$ pycodestyle scraping_netkeiba/getHtml.py 
scraping_netkeiba/getHtml.py:16:1: E302 expected 2 blank lines, found 1
scraping_netkeiba/getHtml.py:24:1: E302 expected 2 blank lines, found 1
scraping_netkeiba/getHtml.py:28:80: E501 line too long (107 > 79 characters)
scraping_netkeiba/getHtml.py:31:1: E302 expected 2 blank lines, found 1
scraping_netkeiba/getHtml.py:31:23: E231 missing whitespace after ','
scraping_netkeiba/getHtml.py:38:1: E302 expected 2 blank lines, found 1
scraping_netkeiba/getHtml.py:38:22: E231 missing whitespace after ','
scraping_netkeiba/getHtml.py:42:43: E712 comparison to True should be 'if cond is True:' or 'if cond:'
scraping_netkeiba/getHtml.py:44:33: E221 multiple spaces before operator
scraping_netkeiba/getHtml.py:44:46: E712 comparison to False should be 'if cond is False:' or 'if not cond:'
scraping_netkeiba/getHtml.py:59:38: E251 unexpected spaces around keyword / parameter equals
scraping_netkeiba/getHtml.py:59:80: E501 line too long (87 > 79 characters)
scraping_netkeiba/getHtml.py:61:80: E501 line too long (81 > 79 characters)
scraping_netkeiba/getHtml.py:73:38: E231 missing whitespace after ','
scraping_netkeiba/getHtml.py:75:53: E231 missing whitespace after ','
scraping_netkeiba/getHtml.py:80:44: E231 missing whitespace after ','
scraping_netkeiba/getHtml.py:80:55: E712 comparison to False should be 'if cond is False:' or 'if not cond:'
scraping_netkeiba/getHtml.py:80:80: E501 line too long (114 > 79 characters)
scraping_netkeiba/getHtml.py:80:95: E231 missing whitespace after ','
scraping_netkeiba/getHtml.py:83:48: E221 multiple spaces before operator
scraping_netkeiba/getHtml.py:89:48: E221 multiple spaces before operator
scraping_netkeiba/getHtml.py:92:49: E712 comparison to True should be 'if cond is True:' or 'if cond:'
scraping_netkeiba/getHtml.py:100:16: E221 multiple spaces before operator
scraping_netkeiba/getHtml.py:102:34: E231 missing whitespace after ','
scraping_netkeiba/getHtml.py:103:38: E231 missing whitespace after ','
scraping_netkeiba/getHtml.py:104:42: E231 missing whitespace after ','
scraping_netkeiba/getHtml.py:106:80: E501 line too long (81 > 79 characters)
scraping_netkeiba/getHtml.py:108:56: E231 missing whitespace after ','
scraping_netkeiba/getHtml.py:109:35: E712 comparison to False should be 'if cond is False:' or 'if not cond:'
scraping_netkeiba/getHtml.py:111:53: E221 multiple spaces before operator
scraping_netkeiba/getHtml.py:114:56: E221 multiple spaces before operator
scraping_netkeiba/getHtml.py:114:80: E501 line too long (81 > 79 characters)
scraping_netkeiba/getHtml.py:121:5: E722 do not use bare 'except'

辛い。 まぁ一つ一つ地道に直していこう。

なんとなく怒られている内容もわかりますが、エラー内容の一覧もあるのでご参照ください

Introduction — pycodestyle 2.4.0 documentation

DjangoでトップページにアプリのViewを表示する方法

f:id:yoshitaku_jp:20180711100334p:plain


はじめに

urls.pyの書き方を調整していたらハマったのでメモ。 DjangoでトップページにアプリのViewを表示したかったのに、設定値が足りなかったのかうまくいかず四苦八苦していました。正解パターンをブログに記しておこう。なんでできなかったんだ…

hoge_project/config/urls.pyの記述

プロジェクト全体のurls.pyでは、様々なurlを読み込んでいると思います。今回はfugaアプリのurlsを読み込む設定だけ追加で記述します。

urlpatterns = [
    path('admin/', admin.site.urls), #デフォルトで存在
    path('', include('fuga_app.urls')), #作成したアプリケーションを追加
]

hoge_project/fuga_app/urls.pyの記述

hoge_project/config/urls.pyで読み込んだファイルの設定です。

from django.conf.urls import include, url
from . import views

urlpatterns = [
    url('', views.index, name='index'),
]

これで、viewのindexに紐付いているやつが表示されるぞ。

おわり

Djangoの設定をHerokuの環境とローカルの環境で分ける方法

f:id:yoshitaku_jp:20180711100334p:plain

はじめに

Djangoで作ったWebアプリケーションをHerokuにアップロードしようとしたとき、Herokuの環境とローカルの環境で使っているDBが違ったので、設定を使い分けられたらいいなと思っていました。環境ごとに差異を出さず開発していくほうがいいと思いますが、今回はHerokuの環境とローカルの環境で設定をわける方法を知ったのでメモしておきます。

Herokuの環境へのデプロイ方法はこちら

yoshitaku-jp.hatenablog.com

local_setting.pyの作成

settings.pyがあるディレクトリにlocal_setting.pyを作成し、ローカルだけで使う設定を記述しておきます。HerokuではPostgreSQLが使われているので、settings.pyがいろいろ変更されているかと思います。ここではDjangoのプロジェクトを作った際のデフォルト設定をlocal_setting.pyに書いておきます。

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'SECRET_KEY'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ['*']

# Application definition
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'ownercard',

    'django.contrib.auth',
    'django.contrib.sites',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.twitter',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'config.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'config.wsgi.application'


# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# Password validation
# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/2.1/topics/i18n/

LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/

STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), 'static')
STATIC_URL = '/static/'

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)
AUTHENTICATION_BACKENDS = (
    # Needed to login by username in Django admin, regardless of `allauth`
    'django.contrib.auth.backends.ModelBackend',

    # `allauth` specific authentication methods, such as login by e-mail
    'allauth.account.auth_backends.AuthenticationBackend',
)

settings.pyの修正

末尾にlocal_setting.pyを読み込む設定を追加します。try exceptの形にし、ファイルがなくても処理が進むようにしておくのが通例のようです。これは他の分野にも応用できそうなので覚えておこう。

#settings.pyの末尾に追加
try:
    from local_settings import *
except ImportError:
    pass

.gitignoreにlocal_setting.pyの追加

config/local_setting.py.gitignoreに追加しておかないと、ローカルの設定がアップロードされてしまいます。

これで、Herokuの環境とローカルの環境で設定の使い分けができます。

ローカル環境でのサーバ実行コマンド

実際にローカルサーバを起動するためにpython manage.py runserverコマンドを実行し、サーバを起動させます。

明示的に起動させるには下記のようにするといいようです。

python manage.py runserver --settings config.local_settings

#100DaysOfCode の60/100が過ぎました

f:id:yoshitaku_jp:20180730014526p:plain

目次

  1. はじめに
  2. 履歴
  3. まとめ

はじめに

無事にサボることなく60日目を迎えました。作業はやってるんだけど、つぶやくのは忘れている傾向にあるので気をつけていきたい。最近はコード書かないと気持ち悪くなってきたのでいい意味で習慣化できているなぁ

前回

yoshitaku-jp.hatenablog.com

履歴

まとめ

他にもポジティブに継続できる企画無いかなぁ

Pythonでunittestする

f:id:yoshitaku_jp:20180728144033p:plain

はじめに

Pythonはずっと独学でやってきたのですが、最近はどこに行っても恥ずかしくないようにお作法を学び始めています。 その一つがテストのやり方を抑えておこうというものです。 もちろん普段の業務ではテストしていますが、 個人的にPythonでガチャガチャ遊んでいるプログラムでもテストをやってソースコードをきれいに保ちたいと思いました。 今回はその過程で学んだことをまとめておきます。

Pythonでは最初からユニットテストフレームワークが組み込まれているのでunittestを使います。

26.4. unittest — ユニットテストフレームワーク — Python 3.6.5 ドキュメント

ディレクトリ構成

Pythonでは下記のようなテストディレクトリ構成にするのが一般的なようです。

.
├─dir
│ └─sample.py
└─tests
  └─test_sample.py

作成したプログラムとテスト用プログラムの2つを見ていきます。 しかし、ここで足し算プログラムなどやっても面白くないので、自分が実際に使ったプログラムで見てみます。

#dir/getHtml.pyの中身

def rtnBS(url):
    """
    htmlを引き渡し、bsObjを返す
    """
    html = urllib.request.urlopen(url)
    bsObj = BeautifulSoup(html, "html.parser")
    return bsObj

テスト実行のコマンド

#tests/test_getHtml.pyの中身

import unittest
from bs4 import BeautifulSoup

from dir.getHtml import rtnBS

class TestSample(unittest.TestCase):
    def test_rtnBS(self):
        url = 'https://www.yahoo.co.jp/'
        bsObj = rtnBS(url)
        beautifulsoup = BeautifulSoup()
        self.assertEqual(type(bsObj),type(beautifulsoup))

これはself.assertEqualで、取得したオブジェクトがbeautifulsoupかどうかをチェックしています。

実行する際のコマンドはtests/test_getHtml.pyです。

python -m unittest tests/test_getHtml.py

補足ですがdiscover testsに変更するとtestsディレクトリ配下のすべてのテストを実行できます。多くのテストケースを作った際はこちらに切り替えるべきでしょう

python -m unittest discover tests