astamuse Lab

astamuse Labとは、アスタミューゼのエンジニアとデザイナーのブログです。アスタミューゼの事業・サービスを支えている知識と舞台裏の今を発信しています。

PM としてアスタミューゼに転職して

はじめまして、PM として入社しました Gyopi です。
アスタミューゼでは複数の Webサービスや社内サービスを持ちながら、
Product Manager を専業でやっている人間がいませんでした。

そんな中入社した一人 PM からみたアスタミューゼと最近やったことのお話です。
(以下、PM は全て Product Manager のことを指します)

(経歴)Webエンジニアの経験を PM に

「Product Manager」とはどいういう役割かプロダクトやフェーズにより異なるかなと思いますが、

Product の魅力によりユーザーに得をさせる。
そのために、メンバーが魅力を作り上げやすい状況を作り出す。

というのがざっくりとした役目だと思っています。

私はキャリアの最初から PM だったわけではなく、
最初は Ruby on Rails で BtoB のサービス開発を行うエンジニアでした。

PM は直接的に開発者の領域を侵してはならないと思いますが、
少なからず開発知識があることは議論において役に立っている実感があります。
エンジニア時代の周囲の人々には今も感謝が絶えません。


また、前職にて新規サービスを立ち上げて拡大していく中で
Growth Hack の試みを行ったり大口顧客に法人営業を行ったり、
ユーザーのことを考え・ユーザーに直に接する機会も得られました。

事業の目線で物事を考える上では新規サービスでの Product Owner(PO)を務めた経験も大きいです。
サービスを拡大させる中で複数の立場を経験できたこと、
その中でもユーザーに直に接した経験は「ユーザーに得をさせる」の発想に至る原体験だと思います。

転職理由)プロダクトとの向き合い方を磨くために

幸いにも新規サービスは成長し、
事業側も開発側もアグレッシブなメンバーに恵まれていましたが、
最終的には5年ほど務めた前職からの転職を決断しました。

法人向けのサービスにやりがいを感じながら、事業として1つだけの領域で試行錯誤をすることに限界を感じていました。
携わっていたサービスが Google などのビッグプレイヤーが競合となるドメインにいたこともあり、より独自性の強いサービスに携わりたかったです。
とはいえ、やりきった達成感が故の転職でもあったように思います。


アスタミューゼへ決めた理由は、採用面接で今の上司から受けた会社やデータの説明が興味深かったから、というのが大きいです。
ロジックで考える条件もありますが、こういう人たちと働くのは面白いだろうと、面接を楽しく感じさせてもらえたことは確実にプラスに作用しました。
最初は別の職種で応募していながら、適性を踏まえて PM を推奨してくださったことも嬉しかったです。


また、以前から Scala で開発していることを知っていたので開発者目線でも以前から知っている会社でした。
転職してから全然プログラミングできてないな、という自戒も込めて敢えて初心を記しておきます。

転職してみて)アスタミューゼで自分に何ができそうか

流れの速い事業・プロダクトに携わっているということでもあるのですが、最初のキャッチアップが何より大変でした。
社内の打ち合わせで「アグリー」とか「ケイパビリティ」とネタではなく口にする人がいて、転職の実感を感じた次第です。
とはいえ総じて周りの方は優しくて、聞いたらなんでも教えてくれるし、ご飯にも誘ってくれるし、お陰様で慣れるのは早かった気がします。


専門用語が飛び交って会話が進むので「これはドメイン知識を得るのが大変だ」ということで少しずつ社内用語集を作りました。
用語集はたまに近くの部署の人に今でも共有することがあり、フットワーク軽く作ってよかったなと思っています。
その後、同じタイミングで入社した池田 (@yukung)が社内 Wiki を整備してくれたので情報共有はかなり前進しています。


アスタミューゼには開発面やインフラ、新規事業コンサルなど様々な経験・スキルを持つメンバーがいて本当に多種多様です。
プロダクトも人数の割に多いですし、何より新規も運用中のものもデータがとにかく多いです。
その中で都合よく一人 PM という立場を利用してフットワーク軽く様々な面に顔を出すことで、意外と気づきづらいチームやプロジェクトの滞りを解消できたらなと思っています。


これまでアスタミューゼのプロダクト設計はどちらかといえば解決策ドリブンのものが多かったようです。
データや社内の専門的知見が多種多様なことを考えると、それにも納得がいきます。
それを新しい Web サービスとしてソリューションだけでなく価値を試行錯誤し、チームみんなで成長していければいいなと考えています。

最近やったこと)サービスについてみんなで議論を

最近やったことの中から、Lean Canvas を書いてみたというエピソードを少し。
Lean Canvas はサービスを「誰のどんな課題を解決するためにどういった機能を届けるか」を固めるものですが、
やったことがないと書いてみることに高いハードルを感じてしまいがちです。

今までにメンバーを少し入れ替えながら何度かトライしてみました。
その中でも一番初めは少し見切り発車気味に進めましたが、
「意外にみんなで埋められる!」という実感を得ることができたのではないかと思っています。


検討を重ねる中で、サービスの何に着目していくかという次の分類を気にしながら取り組みました。
・CPF (Customer Problem Fit)
・PSF (Problem Solution Fit)
・PMF (Product Market Fit)
とはいえ、まだ CPF がひと段落という段階です。
各フェーズなどについてはまた別の記事でお話しできればと思います!


実装する機能や、KPI 達成の施作には日常の中で確実に注目していますが、
「どうしてこういった KPI に落としこまれるのか」は定期的に振り返らないといけないなと改めて感じました。
また、メンバーによってどれくらい詳しく言語化することで判断材料として納得がいくのか、などの特徴も出てきたかと思います。


他にもこの数カ月で開発スタイルがアジャイル・スクラム化されたり、
機能要件を User Story 形式にしはじめたり、
開発チームでモブプロとかはじめたり、
チームの成長がすごいので今から未来が楽しみです!

おわりに

私は Web サービスの PM というところをメインに働いていますが、
社内システムを刷新したり、持つべきデータの企画をおこなったり、事業と技術を繋げていくべき役割が社内にたくさんあります。


決まり文句になりますが、We’re hiring!! ということで
エンジニアやデザイナーだけでなく PM も募集中です!
アスタミューゼに、Product Manager に、興味を持っていただければお気軽に採用情報をご覧になってください!





Blog を一回分飛ばしてしまったので、次回は締め切りにコミットできるようにしたいと思います。

Scalaから始めるRust入門

お久しぶりでございます。Scalaでバックエンドを開発しているaxtstar(@axtstart)です。

みなさまゴールデンウィークはいかがお過ごしだったでしょうか?

我が家はあまり旅行に行くということもなく、近場のドライブや、ちょい大き目の公園などで過ごすことが多かったです。

さて、そのおかげというわけではありませんが、この連休を利用して、 新たにRustとWebAssemblyに入門してきたので今回はそのあたりの話を、書きたいと思います。

f:id:astamuse:20190508020532j:plain

Image by prettysleepy1 from Pixabay

前書き

遅ればせながら、前々から気になっていた、Rust Programming Languageの勉強をGWを利用して初めて見ました。

随分昔ですが、Visual C++でDLLを作ってそれをフロントのVisual Basicで呼び出すのが最強と思っていた時があります。

それと似た世界が、JavascriptとRust(WebAssembly)なのではないかと、最近考えていました。

少々遅い気もしますが、何事もはじめないよりは、はじめた方が面白いし何かの役に立つことがあればいいなと。

普段はScalaで開発する事が多いので、そのScalaとの比較として書いていきたいと思います。

Rust、Scala比較

さて、早速RustとScalaを比較してみます。

◎RustはScalaとは違ってガーベージコレクションを持たない

→自分でメモリ管理をする必要がある*1

とは言え、強力な言語システムのサポートがあるため、昔のように、メモリの解放もれを気にすることはかなり減っているようです。

Scopeを抜けると確保したメモリは解放される*2などなど

→OwnershipメカニズムやScopeメカニズムによって、極力バグをcompile時に発見できる仕組みがある。

 ・stackとheapを常に意識できるような書き方になる

例えば、これはダメ

//Stringはstructであるため、その実体はheap領域に確保される
let s1 = String::from("hello");
//s2はs1をディープコピーするのではなく、参照をコピーしている(シャローコピー)
let s2 = s1;
//memory safetyの観点から、Rustはこの時点でs1をOut of Scopeにする

println!("{}, world!", s1);//<---コンパイルエラー(既にOut of Scopeのため)
println!("{}, world!", s2);//OK

関数に渡しても、Out of Scopeになる

fn bollow(c:String){
}
let s1 = String::from("hello");
bollow(s1);
println!("{}, world!", s1);//<---コンパイルエラー(既にOut of Scopeのため)

これはOK

// 固定文字列はstack上に確保される
let s1 = "hello!";
//これはスタック上の操作
let s2 = s1;

println!("{}, world!", s1);

これもOK

fn bollow(c:&str) {
}
// 固定文字列はstack上に確保される
let s1 = "hello!";
bollow(s1);

println!("{}, world!", s1);

参照渡しにした場合はこの限りではありません。

fn calculate_length(s: &String) -> usize { 
    s.len()
}

let s1 = String::from("hello");

let len = calculate_length(&s1);
// 参照渡しの場合、ここでOwnereshipの変更は無い

println!("{}", s1); //OK

もちろん上記のようなことはScalaではおこらず、コンパイルは通ります*3

◎StatementとExpressionが異なる概念として扱われる

Scalaだとあまり意識しない*4セミコロン(「;」)の有る無しによって、StatementなのかExpressionなのかが決まります。

これはダメ

fn add(x:i32, y:i32) -> i32 {
  // これはStatement
  x + y; // <--i32を戻り値として指定しているので、戻り値=()は、コンパイルエラー
}

これはOK

fn add(x:i32, y:i32) -> i32 {
  // これはExpression
  x + y //ここが戻り値になる
}

◎immutable、mutableはScalaと非常に似ている

immutable

let x = 5;
x = 10; // <-- コンパイルエラー
let x = 6; // <-- これはOK(シャードーイング)※ScalaはScopeで実現

mutable

let mut x = 5;
x = 10; // OK
let x = 6; // <-- OK(シャードーイング)※ScalaはScopeで実現

◎enumが非常に強力

 ・Optionがenumとして実装できる*5

enum Option<T> {
    Some(T),
    None,
}

◎nullが無い

その発明者自身*6が10億ドルの過ちといった「null」がRustには存在しません。

Scalaはnullそのものを消去することはできていません。極力使わないようにプログラミングすることはもちろん可能ではあります。

◎match文はScalaと非常に似ている

Rust

fn fib(n: u32) -> u32 {
    match n {
        0 => 0,
        1 => 1,
        _ => fib(n-2) + fib(n-1),
    }
}

順序と case、「,」以外同じように見える

Scala

def fib(n:Int):Int= {
  n match {
    case 0 => 0
    case 1 => 1
    case _ => fib(n-2) + fib(n-1)
  }
}

◎文字の取り扱いはそこそこ大変

let h = String::from("hello");
let w = String::from(", world!");

let hw = h + &w;
println!("{}", w);// OK
println!("{}", h);// コンパイルエラー、hはStringのadd関数、演算子オーバロード(+)により、Out of Scopeになっている

◎Cargoという、パッケージ管理ツールがある

→Scalaのsbt、gradle、mavenのような存在。

tomlという形式で、設定ファイルを記述します。

ここで紹介した機能以外にも、似た機能や全然似てない機能はたくさんあります。

私も今回はこの*7チュートリアルで学習しました。

WebAssembly

MDN Web Docsによると、WebAssemblyとは、

以前ではできなかったようなウェブ上で動作するクライアントアプリケーションのために、複数の言語で記述されたコードをウェブ上でネイティブに近いスピードで実行する方法を提供します。

というもので、IEを除くだいたいの最新ブラウザなら動き、今回Hello, world!した、Rustとも相性の良いものです。

Hello, world! for WebAssembly

RustでWebAssemblyでHello, world!するには今は、wasm-bindgenを使用するのが一番簡単なようですね。

Cargo.toml

[package]
name = "hello-world"
version = "0.1.0"
authors = ["axt <axt_star@hotmail.com>"]
edition = "2018"

[lib]
path = "src/lib.rs"
crate-type = ["cdylib", "rlib"]

[dependencies]
wasm-bindgen = "0.2"
wee_alloc = { version = "0.4.2", optional = true }

src/lib.rs

use wasm_bindgen::prelude::*;

// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

// Rust側からJavascriptのalertを呼べるようにする。
#[wasm_bindgen]
extern {
    fn alert(s: &str);
}

// JavascriptからRustの関数を呼び出せるようにする。
#[wasm_bindgen]
pub fn greet() {
    alert("Hello, hello-world!");
}

上記の2ファイルの状態で、下記を実行すると、しばらくかかりますが、target、pkgというフォルダができて、そこにJavascript*8からRust側を呼び出す、glueスクリプト*9みたいなものを吐き出してくれます。

wasm-pack build

さらに下記で、wwwディレクトリを作成してそこに、webの開発に必要なwebpackなど一式を作成してくれます。

npm init wasm-app www

www配下でnpm installして必要なライブラリを取得します。

cd www && npm install & cd ..

pkgをlinkします。

cd pkg/ && npm link && cd ..

pkgを利用したい側でリンクを呼び出します。

cd www && npm link hello-world && cd ..

ローカルのwebサーバを起動します。

cd www && npm run start ; cd ..

ブラウザでhttp://127.0.0.1:8080/にアクセスすると、alertのダイアログでhello, world!が表示されます。

ここまでここの内容だいたい、そのままです。

RustからのDomアクセスなど

WebのDocumentやElementなどにアクセスしたい場合は、Cargo.tomlにfeatureを追加する必要があります。

[dependencies.web-sys]
version = "0.3.4"
features = [
  'console',
  'CanvasRenderingContext2d',
  'Document',
  'Element',
  'HtmlElement',
  'HtmlBodyElement',
  'HtmlButtonElement',
  'HtmlCanvasElement',
  'EventTarget',
  'Node',
  'Window',
]

bodyの最後にpタグでHello from Rust!の追加

#[wasm_bindgen]
pub fn hello_p() -> Result<(), JsValue> {
    let window = web_sys::window().expect("no global `window` exists");
    let document = window.document().expect("should have a document on window");
    let body = document.body().expect("document should have a body");

    // Manufacture the element we're gonna append
    let val = document.create_element("p")?;
    val.set_inner_html("Hello from Rust!");

    body.append_child(&val)?;

    Ok(())
}

速度を比較してみる

あまりいい例ではないのですが、(スタックオーバフローになるような何も考えてない方法の)フィボナッチ数列による速度比較をして見ました。

Javascript版

function fib(n) {
    return n < 2 ? n : fib(n - 2) + fib(n - 1);
}

WebAssembly(Rust)版

#[wasm_bindgen]
pub fn fib(n: u32) -> u32 {
    match n {
        0 => 0,
        1 => 1,
        _ => fib(n-2) + fib(n-1),
    }
}

3回実施した平均です。

fib(n)

n Javascript(ms) Rust(ms) 割合(R/J)
10 0 0 -
30 17 14 1.2
40 1138 910 1.25
41 1842 1463 1.26
42 2995 2388 1.25
43 4821 3802 1.27
43 7868 6134 1.27

Rust版の方が2割増し程度の性能が出ました。

アルゴリズムが大変悪いので比較的低いnでPageがクラッシュしました。

ただこれだけなのに、速度差を体感できます。

画像を受け渡してみる

Rust側に、canvasのイメージバイナリを渡して透過度をあげてみます。

↓こちらに置いておきます。

github.com

Rust側は比較的簡単に実装できます。

ただバイナリは直列データとして扱う必要があるようです。

線の描画などはもっと別の方法が良いかもです。

Rust側

#[wasm_bindgen]
pub fn to_tranparent(screen: & mut Screen, bytes: & mut [u8]) {
    for i in 0..screen.height {
        for j in 0..screen.width {
            let offset = 4 * (screen.width * i + j);

            bytes[offset] = bytes[offset];
            bytes[offset + 1] = bytes[offset + 1];
            bytes[offset + 2] = bytes[offset + 2];
            bytes[offset + 3] = 25;//透明度を上げる
        }
    }
}

htmlはVue.jsの読み込みと、canvas、inputを置いています。

html

    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="./bootstrap.js"></script>
        <canvas
          id="canvas"
          height="600"
          width="400">
     </canvas>
     <br />
     <input @change="uploadFile" name="image" type="file" />
      <button v-on:click="to_transparent">to_transparent</button>

glue以外の記述部分です。

javascript

var app = new Vue({
    el: '#app',
    data: {
      text: '',
      left_val: '',
      right_val: '',
      number:10,
      message: '',
      canvas: null,
      duration: ''
    },
    methods: {
      to_transparent: function() {
        // canvas取得
        const canvas = document.querySelector('canvas');

        // Rust上のScreen構造体取得
        const screen = new sample.Screen(canvas.width, canvas.height);
        // context取得
        const ctx = canvas.getContext('2d');
        // canvas
        var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
        // Rustの透過処理を呼び出し
        sample.to_transparent(screen, imageData.data);
        // 透過処理後のバイナリをimageに変換
        const image = new ImageData(imageData.data, screen.width, screen.height);
        // canvasに書き戻す
        ctx.putImageData(image, 0, 0);
      },
      uploadFile: function(e){
        // ローカルのファイルアップロード部分
        var canvas = document.querySelector('canvas');
        var ctx = canvas.getContext("2d");
    
        let files = e.target.files;
        var file = files[0];
    
        var image = new Image();
        var reader = new FileReader();
    
        reader.onload = function(evt) {    
          image.onload = function() {
            // canvasにイメージを書き込む
            ctx.drawImage(image, 0, 0);
          }
          image.src = evt.target.result;
        }
        reader.readAsDataURL(file);
      },
    }
})

上記でアップロードした画像の透明化ができます。

まとめ

Rustは非常に面白い特徴を持った言語ですね。WebAssemblyへの対応も進んでおり、比較的楽に開発を進めて行く事ができそうです。

全ての環境では動かない部分もあるので、まずは社内的なプロジェクトのフロントに採用するとか、 限定した環境をうたえるなら結構アリだなと思わせるものでした。

最後になりましたが、アスタミューゼでは現在、エンジニア・デザイナーを絶賛大大大募集中です! 興味のある方はぜひ下記バナーからご応募ください!!

*1:Scalaが全くしなくて良いという意味でも無いですが

*2:C++に見るRAIIに近いが、さらにエレガントな方法

*3:Rustのstructに近い概念はcase classでしょうか?

*4:Scalaではほぼ記述しない

*5:ScalaはOptionとEnumは別のもの

*6:https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%B3%E3%83%88%E3%83%8B%E3%83%BC%E3%83%BB%E3%83%9B%E3%83%BC%E3%82%A2

*7:日本語版:https://doc.rust-jp.rs/book/second-edition/

*8:Typescriptのglueも!

*9:なんというべきなのか?

アスタミューゼに入社して1年が経った

こんにちは、開発部のomiです。
4月といえば、出会いと別れの季節ですね。節目の月ということで新たな環境へチャレンジする方も多いのではないでしょうか。
かく言う私も昨年2018年の4月にアスタミューゼに入社してからちょうど1年が経ちました。
そこで今回はこの1年を振り返り、この1年で感じたこと・転職してよかったことなどを書き出してみようと思います。

そうだ、転職しよう

f:id:astamuse:20190420182211p:plain
私が前職から転職を考え始めたのは一昨年2017年の冬でした。
新卒で入社したSIer2年目の冬。入社してからというもの、プログラミングがしたいという思いはずっと心にありながらも開発業務に携わることはほぼなく。
内製化を進めていると言っていたような気がするけれどこの会社では開発業務はできないんだろうな、というのをじわじわ理解してきたタイミングでした。
開発を委託しているベンダーのおじさんたち(仲良し)が羨ましくて堪らなかったんです。
このままじゃ後悔する!!!そう感じて転職を思い立ちました。

そこからは衝動的に行動しだし、あっという間に転職活動を終えました。
普段の業務後に走って退社し、面接・面接・面接 ・・・
f:id:astamuse:20190420182253p:plain
全体を通し4週間で転職活動を終え、11社に出向き面接は計15回受けました。
この期間は自分にとってとても大切な時期だったと思います。自分を見つめ直す時期でした。
自分にとって何が大事なのか、何が楽しいのか、何をしたかったのか、、。
考えれば考えるほど今の環境ではだめだという思いと共に、未来へのワクワクが増すばかりでした。
そして同時に、たくさんの企業に出向き覗いてみてはじめて、外の世界にはこんなことをやっている企業があって、こんな働き方があって、こんな人たちが集まっているんだ、と世界の広さを知りました。(新卒の時には3社くらいしか行かなかった)
自分が知っている世界は本当に本当にちっぽけな一部分でしかなかった、自分に合う・自分が求めている世界は誰にでも必ずある、そう感じました。

アスタミューゼとの出会い

面接を受け始めて2回目でアスタミューゼの一次面接にあたりましたが、この時点から最後までずっと変わらずアスタミューゼが第一志望でした。
今の私の上司である、ぶちょーとの1対1でしたが、めちゃめちゃデキる人なんだろうな・・と感じさせるスマートさと同時に、相手を安心させる自然体さ・こちらの話を親身に聞いてくれる姿勢に感動したのを覚えています。
正直やっている事業の話はよくわかっていなかったのですが(ぶちょーごめんなさい)、この人が選んだ人たちは絶対良い人に決まってる!と思いました。
二次面接ではさらに上のボスと1対1でお話ししましたが、こちらも更に完璧すぎるスマートさと絶対的な安心感(お二人とも、スマートなのに柔らかい雰囲気)を感じて、自分もこの会社の一員になりたい!と思いました。
結局、内定を2社もらいその他も5社程選考が進んでおり返事を急かされている状況でしたが、アスタミューゼにお食事会に誘われた時点で、ほぼ内定デショ!(^_−)−☆とエージェントに言われたので全て辞退しました。(今考えるとやばい)

アスタミューゼに入社した

それからの1年はあっという間に過ぎて行きました。
やはりわからないことだらけでした、むしろ分からないことしかありませんでした。
でもそれが嬉しかった、これを求めていた!と感じました。
分からない = 新たな学びのチャンスであるので、壁にぶつかりまくったこの1年は前職の2年間よりは遙かに自分を成長させてくれたと感じました。

そして想像した通り、皆スーパーエンジニアではあるけれど、暖かく優しくユーモアのあるいい人しかいませんでした。
SIerからベンチャーであるアスタミューゼに転職した私にとってははじめてのことばかりでした。
はじめての自分のデスク(前職はフリーアドレスだった)、はじめてのモニタ(前職はノートonly)
はじめてのSlack、はじめてのgit、その他諸々はじめてのアプリ・ツール
はじめてのリモート会議
はじめてのフレックス勤務
はじめての外部カンファレンス参加
はじめての新規開発、はじめてのScala
はじめてのブログ、はじめての勉強会
はじめてのオフィス引っ越し
・・・
f:id:astamuse:20190420182315p:plain
どれも今となっては当たり前になりましたが、日々受ける新しい刺激は多く、楽しみながら仕事が出来ています。
開発部以外の部署の方も仲良くしてくれる方が多く、毎日を楽しく過ごさせていただいています、感謝でいっぱいです。

転職してみて

転職してみて今の気持ちとしては、
いっぱい開発できて嬉しい!学ぶべき人が周りにたくさんいて嬉しい!
周りの人はみんな優しいし、面白い!とにかくいろいろ自由で嬉しい!
勤務形態や外見(すみません私金髪にしました)もそうですが、自分で試してみたい技術などに寛容な点や、各人のやりたいこと・興味あることなどをぶちょーやボス達がとても尊重して下さっていて本当にいい会社だなと思います。
そして今まさに会社がどんどん大きくなっていっているのが見ていて嬉しいし、面白い!ワクワクする!!!!!
引き続き、開発部の皆さんと共に学びを忘れず楽しくお仕事して会社に貢献できるように励んで参ろうと思います。

そんな弊社ではエンジニア・デザイナーを募集中です!興味を持っていただけましたらバナーからよろしくお願いします!
面白楽しく一緒に働いてくださる仲間が増えるのを楽しみにしております!
以上です。読んでいただきありがとうございました。

Copyright © astamuse company, ltd. all rights reserved.