上京エンジニアの葛藤

都会に染まる日々

失敗談投稿・共有サービス「しくじり」をリリースした話

はろー。こんにちは。
すっかり更新サボってしまいました。
サボってしまった理由(言い訳)は、あるサービスの開発に注力をしていたからです。。

そう、表題にもある通り、、
「しくじり」という失敗談投稿・共有サービスをリリースしました。

shi9jiri.net

サイトはこちらです
一応簡単に説明するとジャンル問わず「失敗談」を投稿し、共有し合おうというゆるーいサービス

なぜつくったのか

作った理由は大きく分けて二つ

1. 失敗談を集めて皆で共有し、防げるもの未然に防げたらいいな
生きていく中で失敗は不可欠なもので、大小毎日何かしらの失敗を繰り返している
もちろん僕自身もたくさんの失敗をしている

全ての失敗を無駄とは考えていないが、未然に防げるのであれば防いだ方がいいといった類のものもあると思う
そんな時に皆さんの様々な失敗談を集めたプラットフォームがあれば有効活用できそうと思った

2. 単純に面白いコンテンツ
失敗談の中には面白いものがたくさんある

例えば中学生、高校生の頃に「初めて彼女ができた時にやってしまった失敗談」とか皆なにかしら面白い失敗談を持っていそうだなと思った

そんな今となったら笑えるような話を集めたら単純に面白いと思った

ユーザーといっしょに眺めてニヤニヤしながらコメントしていきたい

今後どのようにしていきたいか

  • まずは、コンテンツを集めたい
    リリースから1週間経過するがまだまだコンテンツが少ないので、もっと投稿数を増やしていきたい

    開発期間は約2週間で平日の深夜、週末にコソコソと作っていたため
    デザイン面がまだまだ未完成だなと思っているので、どんどんブラッシュアップしていきたい

    機能面では、SNS 連携などのログイン機能も増やして「匿名」、「非匿名」を洗濯できるようにしたいなと考えている

  • 新しい技術をどんどん取り入れたい
    サーバーサイドは Perl で作っており、そのまま VPS にのせているだけなので特段新しいことをしていない
    強いて言えば、MySQL は 8.0 を採用しているぐらいだ

    ユーザー数の増加に伴ってクラウドに移行もしていきたいなと考えている

  • ネイティブアプリ化したい Web アプリでのユーザー数をある程度獲得できたら、ネイティブアプリ化したい

まとめ

Web サービスを作るのが趣味でいくつもサービスをリリースをしては、盛り上がらず閉鎖するということを繰り返しているが、やっぱりサービスを作るのは楽しいなと思う

自分ではイケてる、流行ると思ったサービスが全然流行らなかったり、またその逆もしかり

リリース直後でコンテンツ(ユーザー)も少なく全然盛り上がってないですが、頑張って開発していくので「しくじり」をよろしくお願いします!

VS Code で Perl を書くときに関数ジャンプできるようにする方法

はろー。こんにちは。

みなさん五月病ですか?はい、僕は患ってます。

ところで、Perl 書く時のエディタは Vim 派ですか?
それとも Emacs 派ですか?まあだいたい二手に別れますよね。
そんな僕は Vim 派でしたが、最近は VS Code を使っています。
理由は・・・なんとなくです。

VS Code 自体はデフォルトの設定でもわりかし便利なんですが、どうせなら拡張して関数ジャンプとかできるようにしたいなと思ったので、その方法をここに残します。(めっちゃ簡単)

導入手順

  1. 拡張機能 Perl を入れよう
    marketplace.visualstudio.com
  2. ローカルに ctags を入れよう Mac の人は以下
    brew install ctags
    ※Command Line Tools を入れてない人はインストールできないので、以下のコマンドで入れましょう
    xcode-select --install
  3. VS Code 再起動をして完了

簡単ですね。これで対象の関数にカーソルを当てて F12 で関数ジャンプ!!!
※導入の際はくれぐれも自己責任でお願いします!

react.js で keydown イベントで DOM を更新する方法

はろー。こんにちは。

react.js を最近ちょこちょこ触り始めたので、忘れんうちに書きます!

前提としてそもそもライフサイクルとか正しく理解していないし、redux ってなに???っていう状況なのですが、力技でごりごり前に進んでいきます。
書いてるうちに理解深まるやろ!!!って信じてます。

やりたいこと

「特定のキーを押下したタイミングでイベントを発火させて DOM を更新したい」

button タグを onClick で DOM を変更させるなどは、サンプルがたくさん転がっておりなんとなくでできました。
しかし単純に「→」を押下して DOM を変更させるのはどのライフサイクルで実行すればいいか悩みました。

悩んだ末の実装が以下です。

var React            = require('react');
var ReactDOM         = require('react-dom');
var createReactClass = require('create-react-class');

class SlideComponent extends React.Component {
  constructor(props, context, updater) {
    super(props, context, updater);
    this.state = { word : 'hoge' };
  }

  handleKeyDown(e) {
    if (e.keyCode == 39) {
      this.setState({word: 'foo'});
    }
  }

  componentDidMount() {
    window.addEventListener('keydown', this.handleKeyDown.bind(this));
  }

  render() {
    return (
      <h1>{this.state.word}</h1>
    )
  }
}

ReactDOM.render(
  React.createElement(SlideComponent),
  document.getElementById('content')
);

ポイントは window のリサイズなどのイベントを扱いたい場合は componentDidMount() でイベントを登録して使うそうで、今回は keydown のイベントを登録しそれがトリガーで発火させるようにしました。
とても簡単ですね。

おまけ

かの有名なコナミコマンドでイベントを発火させ DOM を更新する
コナミコマンド「↑↑↓↓←→←→BA」

var React            = require('react');
var ReactDOM         = require('react-dom');
var createReactClass = require('create-react-class');

var konamiCommand = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65];
var input = [];  

class SlideComponent extends React.Component {
  constructor(props, context, updater) {
    super(props, context, updater);
    this.state = { word : 'hoge' };
  }

  handleKeyDown(e) {
    input.push(e.keyCode);
    if (input.toString().indexOf(konamiCommand) >= 0) {
      this.setState({word: 'KONAMI success!!!'});
      input = [];
    }
  }

  componentDidMount() {
    window.addEventListener('keydown', this.handleKeyDown.bind(this));
  }

  render() {
    return (
      <h1>{this.state.word}</h1>
    )
  }
}

ReactDOM.render(
  React.createElement(SlideComponent),
  document.getElementById('content')
);

Perl でバブルソートをしてみる

はろー。こんにちは。

今更ながらソートアルゴリズムを改めて復習しているので、バブルソートPerl でしてみたいと思います。

バブルソートとは

ソートのアルゴリズムの一つ。隣り合う要素の大小を比較しながら整列させること。最悪計算時間がO(n2)と遅いが、アルゴリズムが単純で実装が容易なため、また並列処理との親和性が高いことから、しばしば用いられる。安定な内部ソート。基本交換法、隣接交換法ともいう。(単に交換法と言う場合もある)
Wikipedia : https://ja.wikipedia.org/wiki/%E3%83%90%E3%83%96%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88

上記のように Wikipedia では解説されているのでわからない人は読んでください。

実際のコード

#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;

my $array = [13, 5, 41, 20, 1];

for (my $i = 0; $i < scalar @$array - 1; $i++) {
    for (my $n = 1; $n < scalar @$array; $n++) {
        if (@$array[$n] < @$array[$n-1]) {
            my $tmp       = @$array[$n-1];
            @$array[$n-1] = @$array[$n];
            @$array[$n]   = $tmp;
        }
    }
}

warn Dumper $array;

1;

しんぷるにできました。

Perl スクリプトで usage を書いてみた

はろー。こんにちは。
最近暖かくなったり寒くなったりよくわからん毎日ですね
しかし体調を崩すことは全くありません。丈夫なもんです

ところで今回は簡単なスクリプトPerl で書いて、コマンドラインから扱いやすいように usage を出力されるようにしてみました

$ grep --help
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
    [-e pattern] [-f file] [--binary-files=value] [--color=when]
    [--context[=num]] [--directories=action] [--label] [--line-buffered]
    [--null] [pattern] [file ...]

具体的にこんなやつです
Linux コマンドを使う時確認するやつですよね

そこで実装する実際のスクリプトは、Twitter で該当のツイートをリツイートしているユーザーの情報を標準出力するスクリプトを書きました
実装は以下です

実装

#!/usr/bin/perl
use strict;
use warnings;
use feature qw( say state );

use Net::Twitter;
use Getopt::Long qw(:config posix_default no_ignore_case gnu_compat);
use Data::Validator;
use Encode qw ( encode_utf8 );

my $tweet_id;
my $print_key;
my $help;
GetOptions('i=i' => \$tweet_id, 'p=s' => \$print_key, h => \$help);
if ($help) {
    die show_help();
}
validate( tweet_id => $tweet_id, print_key => $print_key );

my $account = {
    consumer_key        => '%CONSUMER_KEY%',
    consumer_secret     => '%CONSUMER_SECRET%',
    access_token        => '%ACCESS_TOKEN%',
    access_token_secret => '%ACCESS_TOKEN_SECRET%',
};

my $nt = Net::Twitter->new({
    traits   => [qw/API::RESTv1_1/],
    consumer_key        => $account->{consumer_key},
    consumer_secret     => $account->{consumer_secret},
    access_token        => $account->{access_token},
    access_token_secret => $account->{access_token_secret},
});

my $retweet_user_ids = $nt->retweeters_ids({
    id            => $tweet_id,
    stringify_ids => 'true',
});

my $user;
my $retweet_user_list = [];
map { 
    $user = $nt->show_user({ user_id => $_}); 
    push @$retweet_user_list, $user
} @{ $retweet_user_ids->{ids} };

map { say encode_utf8 $_->{$print_key} } @$retweet_user_list;

sub validate {
    eval {
        state $rule = Data::Validator->new(
            tweet_id  => { isa => 'Int' },
            print_key => { isa => 'Str' },
        );
        my $args = $rule->validate(@_);
    };
    if ($@) {
        die show_help();
        exit;
    }
}

sub show_help {
    my $help_doc = <<EOF;
    get retweet info script
    Usage:
        perl $0 [options]
    Options:
        -i : tweet_id (Int)
        -p : print_key (Str)
            ex )
                id, screen_name, location
                https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-show            
        -h : help
    Author
        okkun_sh <okkun.sh\@gmail.com> (\@okkun_sh on Twitter)
EOF
    return $help_doc;
}

使用方法

$ perl get_retweet_info.pl -h

    get retweet info script

    Usage:
        perl get_retweet_info.pl [options]

    Options:
        -i : tweet_id (Int)

        -p : print_key (Str)
            ex )
                id, screen_name, location
                https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-show

        -h : help


    Author
        okkun_sh <okkun.sh@gmail.com> (@okkun_sh on Twitter)


$perl get_retweet_info.pl -i 1111111111 -p screen_name

-h をすることで usage が出力されるようになります
これでoption -i でツイート id の指定、
-p でリツイートしているユーザーの情報の指定をすればよいということがわかりますね

コードのポイントは、この部分です
GetOptions でオプションの引数の指定をしており、引数に対してバリデーションをかけてエラー時は usage が出力されるようにハンドリングしています
また -h を指定時は usage が出力されるようにもしています

use Getopt::Long;
use Data::Validator;

my $tweet_id;
my $print_key;
my $help;
GetOptions('i=i' => \$tweet_id, 'p=s' => \$print_key, h => \$help);
if ($help) {
    die show_help();
}
validate( tweet_id => $tweet_id, print_key => $print_key );

sub validate {
    eval {
        state $rule = Data::Validator->new(
            tweet_id  => { isa => 'Int' },
            print_key => { isa => 'Str' },
        );
        my $args = $rule->validate(@_);
    };
    if ($@) {
        die show_help();
        exit;
    }
}

sub show_help {
    my $help_doc = <<EOF;
    get retweet info script
    Usage:
        perl $0 [options]
    Options:
        -i : tweet_id (Int)
        -p : print_key (Str)
            ex )
                id, screen_name, location
                https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-show            
        -h : help
    Author
        okkun_sh <okkun.sh\@gmail.com> (\@okkun_sh on Twitter)
EOF
    return $help_doc;
}

スクリプト自体はさくっと作ったので動作は怪しいですが、usage の書き方自体は参考になると思います!
完成してから知りましたが、Twitter API ではリツイート情報の取得上限が最大100件らしく全てを取得しきれませんでした。。

もっとシンプルに書ける方法などあれば、コメントください!

Parallel::ForkManager を使って並列処理してみた

ひょんなことから、並列処理が必要とされる場面があったので Parallel::ForkManager とやらを使ってみた

このモジュールを選定した理由は、threads か Parallel::ForkManager で迷ったが、使っている perlbrew では threads が使えなかったため今回は、Parallel::ForkManager を使用しました

ちなみに threads とは、いい感じにマルチスレッドを扱えるクラスです

perldoc.jp

では、Parallel::ForkManager の使い方を書いていきます

導入

cpanm Parallel::ForkManager
いつも通り cpanmコマンドでモジュールを入れちゃいましょう

実装

サンプルコードを載せておきます

#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';

use Parallel::ForkManager;

my $methods = [
    'hoge',
    'foo',
    'bar',
];

my $pm = new Parallel::ForkManager->new(3);
# 子プロセスの最大値を指定し、オブジェクトを生成する

for my $method (@$methods) {
    $pm->start and next;
    # forkする

    if ($method eq 'hoge') {
        &hoge;
    }
    elsif ($method eq 'bar') {
        &bar;
    }
    elsif ($method eq 'foo') {
        &foo;
    }
    $pm->finish;
    # 子プロセスを kill する
}

$pm->wait_all_children;
# 子プロセスの終了を待つ
say "finish";

sub hoge {
    sleep(3);
    say "hoge";
}

sub bar {
    say "bar";
}

sub foo {
    sleep(5);
    say "foo";
}

結果

期待される出力順は、bar → hoge → foo の順ですが・・・

$ perl test.pl
bar
hoge
foo
finish

期待通りの動作でした
こんな感じで簡単にプロセスを fork し並列処理をすることが可能です

metacpan.org

今回は基本的なことしかしていませんが、今後もっと触っていきたいですねー