30
趣味でやる Smalltalk Webアプリ開発 2014/12/25 南谷千城

趣味でやるSmalltalk Webアプリ開発

Embed Size (px)

Citation preview

Page 1: 趣味でやるSmalltalk Webアプリ開発

趣味でやるSmalltalk Webアプリ開発

2014/12/25 南谷千城

Page 2: 趣味でやるSmalltalk Webアプリ開発

片手間の開発

• 勢いのあるうちに

• 短期間でやりたい

ガッと取り掛かって、パッと終わらせたい

Page 3: 趣味でやるSmalltalk Webアプリ開発

もたもたしていると

• 忙しい、飽きる

• 中断、放置

• 忘れる

• 上手く終わらせてもメンテは必要

Page 4: 趣味でやるSmalltalk Webアプリ開発

Webアプリのリプレース

• 2013年• 趣味のRSSアグリゲータ• Grails 2.2

– Groovy– Spring– Hibernate– GORM– GSP– H2 (in-memory)– Rome– Twitter4j

Page 5: 趣味でやるSmalltalk Webアプリ開発

何かと問題はある

• Herokuにタダ乗りするための割り切った設計

–一枚岩

– DB揮発

• 実際はVPSで運用

• TwitterからIPでブロック

– タイムラインにアクセスし過ぎた?

Page 6: 趣味でやるSmalltalk Webアプリ開発

メンテするにも

• 忘れてる

– Grails

• コマンド

• Springが差し込んでくれる部分の約束事

• GORM

• HQL

• フレームワークのアップデートについて行けない

– フルスタックなフレームワークを採用したら一蓮托生• Grails 2.2 -> 2.3 -> 2.4 -> 3.x

Page 7: 趣味でやるSmalltalk Webアプリ開発

Grails以外のフレームワーク

• モデル部分だけでもGroovyの資産を使いたかったが...– GORMにSpringがついてくる

• 候補– Ratpack

• Sinatra like

– Gaelyk• GAE

– Vert.x• Node.js like

Page 8: 趣味でやるSmalltalk Webアプリ開発

じゃあSmalltalkで

• Smalltalkの定番

–大きい、独特

• Seaside (+ GLORP)

–向いてない

• Amber Smalltalk

–開発停滞

• Iliad

–なんとなく敬遠

• AIDA

Page 9: 趣味でやるSmalltalk Webアプリ開発

欲しいもの

• 薄い

• 小さい

• メタメタしない

• 忘れても大丈夫–見ればわかる

–読めばわかる

「バカでも乗れるくらい操縦が簡単で、バカでも扱えるマニュアルつき」なヤツ

Page 10: 趣味でやるSmalltalk Webアプリ開発

趣味なので、観念して自分でやる

Pharo3.0

Zinc Http PostgresV3

SoupTeapot

XML Parser/XPath

Kobati

SoupStock FeedStore

App

Zinc SSO

Twitter

Page 11: 趣味でやるSmalltalk Webアプリ開発

PharoはWeb開発にもそこそこ使える

• ターンアラウンドは速い– 普通のSmalltalk環境– GUI周りはバグ多め

• 標準ライブラリに同梱– HTTP

• Zinc

– 正規表現• Regex

– 暗号化• Zodiac (SqueakSSL)

– VisualWorks NC...

Page 12: 趣味でやるSmalltalk Webアプリ開発

マルチバイト環境用のパッチは必要

• マルチバイト文字列の操作が遅い

1. String >> at:put:

2. primitive error

3. WideString >> at:put:

• パッチをあてる

– 100倍程度の速度改善• キリがない

String >> convertFromWithConverter: converter

| readStream c |readStream := self readStream.^ WideString new: self size streamContents: [ :writeStream|

converter ifNil: [^ self].[readStream atEnd] whileFalse: [

c := converter nextFromStream: readStream.c

ifNotNil: [writeStream nextPut: c] ifNil: [^ writeStream contents]]].

Page 13: 趣味でやるSmalltalk Webアプリ開発

Teapot

Pharo3.0

Zinc Http PostgresV3

SoupTeapot

XML Parser/XPath

Kobati

SoupStock FeedStore

App

Zinc SSO

Twitter

Page 14: 趣味でやるSmalltalk Webアプリ開発

Teapothttp://smalltalkhub.com/#!/~zeroflag/Teapot

• マイクロWebフレームワーク– Sinatra(Ruby)、Flask(Python)、Ratpack(Groovy)

• HTTP method

– GET、POST、PUT、DELETE、etc...

• URL pattern

– ルーティング

• Action

– レスポンスの組み立て

| teapot | teapot := Teapot configure: { #port -> 8080. }. teapot

GET: '/cat/<who>/<name>‘ -> [:req | (req at: #who) , ' は ' , (req at: #name) , ' である']; start.

Page 15: 趣味でやるSmalltalk Webアプリ開発

Soup

Pharo3.0

Zinc Http PostgresV3

SoupTeapot

XML Parser/XPath

Kobati

SoupStock FeedStore

App

Zinc SSO

Twitter

Page 16: 趣味でやるSmalltalk Webアプリ開発

Souphttp://smalltalkhub.com/#!/~PharoExtras/Soup

• HTMLをDOMで扱うためのライブラリ

–どちらかと言えば、スクレイピング向け

– Beautiful Soup(Python)、JSoup(Java)

• .htmlをそのままテンプレートとして使用

– Thymeleaf(Java)、Mixer2(Java)、Kwartz(Ruby)

–見えている通り

–デザイナとの連携容易

Page 17: 趣味でやるSmalltalk Webアプリ開発

SoupStock

Pharo3.0

Zinc Http PostgresV3

SoupTeapot

XML Parser/XPath

Kobati

SoupStock FeedStore

App

Zinc SSO

Twitter

Page 18: 趣味でやるSmalltalk Webアプリ開発

SoupStockhttp://smalltalkhub.com/#!/~kaminami/SoupStock

| server |SsServer stopAll.server := SsServer configure: {

(#port -> 8080).(#debugMode -> true).(#templateRoot -> './stock/template/').(#staticRoot -> './stock/static/').

}.

server registerStaticFileServer. "GET: '/static/*' -> [ :req | handle static file request ]. "server GET: '/example01' -> [ :handler | handler simpleReplace ] handler: #SsExample.server GET: '/example02/<a>/<b>' -> [ :handler :a :b | handler replaceA: a andB: b ] handler: #SsExample. server GET: '/example03' -> [ :handler | handler replaceList ] handler: #SsExample.

server start.^ server

• Teapot + Soup + Fuel

– htmlの断片をストック、切り貼り

Page 19: 趣味でやるSmalltalk Webアプリ開発

SoupStockhttp://smalltalkhub.com/#!/~kaminami/SoupStock

SsExample>>simpleReplace| soup |soup := self soupAt: 'example01/simpleReplace'.

(soup findTagById: 'title') replaceContents: thisContext printString.(soup findTagById: 'willBeReplaced') replaceContents: 'Replaced!!!'.

^ soup

<!-- ./stock/template/example01/simpleReplace.html --><html><head>

<title id="title">title</title><link href="/static/css/sample.css" rel="stylesheet" type="text/css" />

</head><body>

<span id="willBeReplaced">willBeReplaced</span></body>

</html>

Page 20: 趣味でやるSmalltalk Webアプリ開発

Kobati

Pharo3.0

Zinc Http PostgresV3

SoupTeapot

XML Parser/XPath

Kobati

SoupStock FeedStore

App

Zinc SSO

Twitter

Page 21: 趣味でやるSmalltalk Webアプリ開発

Kobatihttp://smalltalkhub.com/#!/~kaminami/Kobati

• ORマッパー

– SQL文とオブジェクトのマッピング

– SQL! SQL! SQL!

–モデルクラスはプレーンなままで良い

• Mutatorメソッドだけは必要

• MyBatis (Java, .NET)

• PostgreSQL専用

– PostgresV3

Page 22: 趣味でやるSmalltalk Webアプリ開発

<mapper id="feedstore-mapper">

<select id="selectEntriesByTag" selector="selectEntriesByTag:limit:" resultMap="entryWithFeedMap" arguments="tag, limit">SELECT

e.id AS entry_id, e.title AS entry_title, e.link AS entry_link, e.summary AS entry_summary, e.issued AS entry_issued, f.id AS feed_id, f.name AS feed_name, f.feed_url AS feed_url, f.site_url AS site_url, t.id AS tag_id, t.tag AS tag_tag

FROM Entry AS e

LEFT OUTER JOIN Entry_Feed AS e2f

ON e.id = e2f.entry_idLEFT OUTER JOIN

Feed AS fON f.id = e2f.feed_id

LEFT OUTER JOIN Tag_Feed AS t2f

ON f.id = t2f.feed_idLEFT OUTER JOIN

Tag AS tON t.id = t2f.tag_id

WHERE(LOWER(t.tag) IN (#{tag}))

ORDER BYe.issued DESC

LIMIT #{limit}</select>....

Page 23: 趣味でやるSmalltalk Webアプリ開発

<resultMap id="feedMap" type="FsFeed"><id property="id" column="feed_id" /><result property="name" column="feed_name" /><result property="feedUrl" column="feed_url" /><result property="siteUrl" column="site_url" /><collection property="tags" type="Set" ofType="FsTag" >

<id property="id" column="tag_id" /><result property="tag" column="tag_tag" />

</collection></resultMap>

<resultMap id="entryWithFeedMap" type="FsEntry"><id property="id" column="entry_id" /><result property="title" column="entry_title" /><result property="link" column="entry_link" /><result property="summary" column="entry_summary" /><result property="issued" column="entry_issued" /><association property="feed" resultMap="feedMap" />

</resultMap>

selectEntriesByTag: tagStr limit: limit^ FsFeedStore dbAccessor execute:

[:session || mapper |mapper := session getMapper: 'feedstore-mapper'.mapper selectEntriesByTag: tagStr limit: limit]

Page 24: 趣味でやるSmalltalk Webアプリ開発

FeedStore

Pharo3.0

Zinc Http PostgresV3

SoupTeapot

XML Parser/XPath

Kobati

SoupStock FeedStore

App

Zinc SSO

Twitter

Page 25: 趣味でやるSmalltalk Webアプリ開発

FeedStorehttp://smalltalkhub.com/#!/~kaminami/FeedStore

• フィードの取得、管理

• RSS1.0, 2.0、Atom1.0に対応

• Zinc-ZnEasyでフィードをGET

• XPathで適当にパース

• Kobatiで保存

Page 26: 趣味でやるSmalltalk Webアプリ開発

Twitter

Pharo3.0

Zinc Http PostgresV3

SoupTeapot

XML Parser/XPath

Kobati

SoupStock FeedStore

App

Zinc SSO

Twitter

Page 27: 趣味でやるSmalltalk Webアプリ開発

Twitter

• 登録済みアプリからの投稿だけなら容易

• Zinc-SSO

– Zincのアドオン

–シングルサインオン対応

• Twitter

• Facebook

• Google

Page 28: 趣味でやるSmalltalk Webアプリ開発

TwitteraccessTokenDic := Dictionary new

at: 'oauth_token' put: 'YOUR-AUTH-TOKEN';at: 'oauth_token_secret' put: 'YOUR-AUTH-TOKEN-SECRET';yourself.

accessToken := ZnOAuth1Token newFromDictionary: accessTokenDic.

data := ZnOAuth1ConsumerData newForTwitterconsumer: 'YOUR-CONSUMER'; consumerSecret: 'YOUR-CONSUMER-SECRET'; yourself.

service := ZnOAuth1Service new providerAccount: data ; yourself.

userAccess := ZnOAuth1TwitterUserAccess new oauth1Service: service; accessToken: accessToken;yourself.

userAccess statusesUpdate: 'yah!!'.

Page 29: 趣味でやるSmalltalk Webアプリ開発

それなりに使える。はず。

Pharo3.0

Zinc Http PostgresV3

SoupTeapot

XML Parser/XPath

Kobati

SoupStock FeedStore

App

Zinc SSO

Twitter

Page 30: 趣味でやるSmalltalk Webアプリ開発

おわりに

• ビジネスには怖いが、趣味ならOKな分野

– Pharo(Squeak)にはそんなものばかり

• 教育向けにはかなり良い

• 絶賛開発中

– SmalltalkHub

• http://smalltalkhub.com/#!/~kaminami