見出し画像

書き捨てコード・アプリを作るときのTips

はじめに

みなさんこんにちは、ALH開発事業部のREIYAです。また会いましたね。
みなさんは今まで

  • とりあえずちょっとコードかきたい!

  • 軽くアプリ作ってみたい!2分くらいで!

  • 雰囲気こんな感じ、なhtml画面をパッと人に渡したい

と思ったけど、地味に面倒でやめた、みたいな経験はありませんか?
そんなお悩みを解決するため、今回は書き捨てコードを作る際のTipsをまとめました。




スニペットを貯めておこう

あーこんな感じの処理、前にも書いた!

という経験はありませんか?

スニペットといっても、エディタ中でトリガー名を入力して呼び出すだけでなく
特定の機能を持つコード断片を用意しておきましょう。もはやコピペ用のライブラリですね。

個人的なおすすめは、「この処理結構頑張って作った」や「綺麗に書けた処理」を
技術系記事として

などにまとめておくと良いと思います。
アウトプットにもなりますし、家で作っておいたスニペット記事をいつでも呼び出せます。

また、たとえばvimでは
スニペット補完機能だけでなく、よく使われるいろんな言語でのスニペット集が用意されています。

https://github.com/honza/vim-snippets

あらかじめ誰かが用意してくれている大量のスニペットを、使えれば呼び出すことも可能です。
いろんな人の記事やレポジトリを集めて、自分用リンクを作っておくと良いですね

とりあえず私が過去に作ったスニペット記事などを置いておきます


ブラウザでコード実行

こんな感じのコードで動くんじゃね?と思いついていざ書こうとしたとき
ロジック部分だけ試したいのに

  • TypeScriptの型制約でなかなか実行まで漕ぎ着けない

  • めんどうなLintエラー

  • PythonだったらこうなのにGoだとなんだっけ...

みたいな、ちゃんとしすぎてるプロジェクトだからこそのしがらみや
とりあえず得意な言語でさっと書いて試したいけど、こっちの言語の文法忘れた
のようなケースで、
いいからコード動かさせろ!」という場合、WandBoxを使いましょう。

https://wandbox.org/

ローカルストレージ保存なのでタブ閉じても再開できます。

なお、ブラウザでサクっと動かせるエディタたちは以下の記事にまとまっています。

https://note.alhinc.jp/n/n144515c7d292

また、「この言語だったら簡単なのに」なお悩みは基本的にChatGPTで解決できます。
コードを貼り付けて、「〇〇言語になおしてください」と書けばOK。むちゃくちゃしっかり描き直してくれます。

jsで軽く文法チェック

ブラウザで動くといえばJavaScriptですよね。
Chrome内蔵のJS実行環境がV8エンジンといって、Node.jsと同じものになりますので

node xxx.mjs

のように、ローカルでmjsファイルを作ってコマンドで実行、などしなくても
Chromeで開発者ツールを開き、console上でJSを書いて実行できます。
ちなみにブラウザに関わらずだいたいconsoleでJSかけるので、Chromeに限った話でもないです。

もちろんWandBoxでJSを動かしても良いですが
軽く文法を確かめたい程度であれば、適当なChromeタブを開いてconsoleに行く方が
気が楽なんじゃないでしょうか。

いいからとりあえずWebAPIをつくる

さて、ちょっとしたコード実行はWandBoxで標準入出力を用いて動かせました。フロントのためのJSはブラウザがあれば動かせます。
では、WebAPIのように常駐したホストを建てたい場合はどうしましょう?

さっとやる、という意味ではPostmanでモックを作ってしまうのが早いかもしれませんが、個人的なおすすめは、Pythonでローカルホストを立ててしまうことです。

python -m http.server 8000

これだけで、そのフォルダをlocalhost:8000として公開できますので、あとは適当なファイルをおけばレスポンスの完成です。

...Pythonが必要なら手軽ではないですかね?いまどきpythonくらいはPCに最初から入ってたりしないですかね??


ということで、各言語ごとにWebAPIをちゃんと作るための最小限スニペットを作ったので載せておきます。
これらをターミナルにコピペすれば一瞬でlocalhostが立ち上がりますので、動く言語でお試しください。
ほぼ全て、以下コマンドで呼び出しを確認できます

curl -X POST \
    -H "Content-Type: application/json" \
    -d '{"key":"value"}' \
    localhost:8000/echo

なお、Java、PHP、Rubyについて筆者の環境問題で動作確認できておりませんが
その他は全てちゃんと動くはずです。

言語ごとWebAPIスニペット

基本的にフォルダ作って必要なものを入れた後で
ヒアドキュメントでファイルに書き込み、起動という流れのshellです。

Python (flask)

必要: python

コードが短くていいですね

WORK_DIR_NAME=mock_python_flask
mkdir $WORK_DIR_NAME && cd $WORK_DIR_NAME
python -m venv . && . bin/activate
pip install flask
cat << "EOF" > app.py
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/echo', methods=['POST'])
def index():
    req = request.json
    print(req)
    return jsonify({"hello": "world"})
app.run(port=8000, debug=True)
EOF
python app.py

JavaScript (express)

必要: node

型ないとコードは短く済みます

WORK_DIR_NAME=mock_nodejs_express
mkdir $WORK_DIR_NAME && cd $WORK_DIR_NAME
npm init --yes && npm install express body-parse
cat << "EOF" > index.js
const express = require('express');
const bodyParser = require('body-parser')
const app = express();
const port = 8000;
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.post('/echo', (req, res) => {
    console.log(req.body);
    res.send({"hello": "world"});
});
app.listen(port, () => console.log(`http://localhost:${port}`));
EOF
node index.js

C++ (Oat++)

必要: gcc make cmake

WebAPIには向いてない言語だと思ってます。
これだけ他と違い、ヒアドキュメントでAPI作成でなくテンプレートをgitから落としてきていますので
src/controller/MyController.cpp を適宜修正してください。

WORK_DIR_NAME=mock_cpp_oatpp
mkdir $WORK_DIR_NAME && cd $WORK_DIR_NAME
git clone --depth 1 https://github.com/oatpp/oatpp.git \
    && cd oatpp \
    && mkdir build \
    && cd build \
    && cmake .. \
    && sudo make install \
    && cd ../.. \
    && rm -rf oatpp
git clone --depth 1 https://github.com/oatpp/oatpp-starter.git \
    && cd oatpp-starter \
    && mkdir build \
    && cd build \
    && cmake .. \
    && make \
    && ./my-project-exe

Java (SprintBoot)

必要: java

内蔵Tomcatは起動が楽で便利ですが、プロジェクト作成にSpring Initializerが必要で、エディタ立ち上げるの面倒なのでgitからテンプレートを持ってきます。
また、Javaのバージョンがmavenのpox.xmlではデフォルトで17指定なので適宜修正してください。
(なお筆者の環境ではxzutil脆弱性対応のためにバージョンを固定しており、java17について動作確認していません)
公式を参考

WORK_DIR_NAME=mock_java_sprintboot
mkdir $WORK_DIR_NAME && cd $WORK_DIR_NAME
git clone --depth 1 https://github.com/spring-guides/gs-rest-service.git \
    && cd gs-rest-service/initial
cat << "EOF" > src/main/java/com/example/restservice/EchoController.java
package com.example.restservice;

import java.util.concurrent.atomic.AtomicLong;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {

	private static final String template = "Hello, %s!";
	private final AtomicLong counter = new AtomicLong();

	@GetMapping("/greeting")
	public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
		return new Greeting(counter.incrementAndGet(), String.format(template, name));
	}
}
EOF
./mvnw spring-boot:run

Rust (axum)

必要: rust

こいつはCにとって変われるのでしょうか。期待です

WORK_DIR_NAME=mock_rust_axum
cargo new $WORK_DIR_NAME
cd $WORK_DIR_NAME
cat << "EOF" >> Cargo.toml
axum = "0.7.4"
tokio = { version = "1.36.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.89"
EOF
cat << "EOF" > src/main.rs
use axum::{response::Json, routing::post, response::IntoResponse, http::StatusCode, Router};
use serde::{Deserialize, Serialize};
use serde_json::json;

#[derive(Clone, Deserialize, Serialize)]
pub struct Request {
    key: String
}

#[tokio::main]
async fn main() {
    pub async fn echo(Json(payload): Json<Request>) -> impl IntoResponse {
        println!("{}", payload.key);
        (
            StatusCode::OK,
            Json(json!({"hello": "world"}))
        )
    }

    let app = Router::new().route("/echo", post(echo));
    let listener = tokio::net::TcpListener::bind("localhost:8000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}
EOF
cargo run

PHP (Laravel)

必要: php

すみません、これも動作確認していません。xzutilめ...
こちらの記事のようにやると良いです

WORK_DIR_NAME=mock_php
mkdir $WORK_DIR_NAME && cd $WORK_DIR_NAME
cat << "EOF" > api.php
<?php
$api["status"] = "hello world";
print json_encode($api);
EOF
php -S localhost:8000

以下を実行 ブラウザのconsoleやindex.mjsとして保存しnode index.mjsでもok

fetch("localhost:8000/api.php").then(v => v.json()).then(console.log)

Ruby (Rails)

必要: ruby

これもバージョン問題で動作確認していません。こちらを参考

WORK_DIR_NAME=mock_ruby_rails
mkdir $WORK_DIR_NAME && cd $WORK_DIR_NAME
sudo gem install grape rack
cat << "EOF" > api.rb
require 'grape'

class EchoAPI < Grape::API
  format :json
  post '/echo' do
    body = env['api.request.body']
    puts body
    { 'hello': 'world' }
  end
end
EOF
cat << "EOF" > config.ru
require './api'
run Rack::Cascade.new [EchoAPI]
EOF
rackup

Go (gin)

必要: go

最近主流になりつつある気がします。

WORK_DIR_NAME=mock_go_gin
mkdir $WORK_DIR_NAME && cd $WORK_DIR_NAME
go mod init $WORK_DIR_NAME
go get -u github.com/gin-gonic/gin
cat << "EOF" > main.go
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
)

type JsonRequest struct {
	Key           string `json:"key"`
	Somefieldname int    `json:"some_fieldname"`
	Testfieldname string `json:"test_fieldname"`
}

func main() {
	r := gin.Default()
	r.POST("/echo", func(c *gin.Context) {
		var json JsonRequest
		if err := c.ShouldBindJSON(&json); err != nil {
			c.JSON(400, gin.H{"error": err.Error()})
			return
		}
		fmt.Println(json.Key)
		c.JSON(200, gin.H{
			"hello": "world",
		})
	})
	r.Run(":8000")
}
EOF
go run main.go

shell

shellのみでWebサーバ建てた記事を見つけましたので置いておきます。
最終的に1枚のshellファイル実行するだけになっていそう。

簡易的に画面を作る

ライブラリのインストールなんて環境が汚れるだけで、入れていない人の環境では動かないというのは、ちゃんとした規模の開発でならまだしも
性能なんか考慮してない書き捨てアプリ作成においてはただ面倒なだけです。

そこで、htmlにはCDNでjsを引っ張ってこれる機能があります。
最も有名なのはjQueryでしょうか。最近トロイの木馬が乗ったそうなのでご注意いただきたいですが

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

このように記載することで、Network経由でContentをDeliveryできます。
なお、Reactもただのjsライブラリなので

<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<div id="root"></div>
<script type="text/babel">
    const App = () => {
        return (
            <div>This is React test.</div>
        );
    };
    ReactDOM.createRoot(document.getElementById("root"))
        .render(<App />);
</script>

とすれば使えます。古いので非推奨ですが書き捨てならOK。
このファイルを保存してブラウザで開くなり

python -m http.server 8000

するなりで画面が開きます。

他にもおすすめなCDNとして以下を載せておきます。

  • マークダウンパーサー

  • 言語のシンタックスハイライトつけられるやつ

  • jsでファイルを圧縮できるやつ

  • html中にExcel埋め込めるやつ

    <!-- MarkDown -->
    <script src="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.css">

    <!-- syntax highlit -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/styles/default.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/highlight.min.js"></script>

    <!-- zip -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.0/jszip.min.js"></script>

    <!-- jexcel (with jsuites) -->
    <script src="https://bossanova.uk/jexcel/v4/jexcel.js"></script>
    <script src="https://bossanova.uk/jsuites/v2/jsuites.js"></script>
    <script src="https://jsuites.net/v4/jsuites.js"></script>
    <link rel="stylesheet" href="https://bossanova.uk/jspreadsheet/v4/jexcel.css" type="text/css" />
    <link rel="stylesheet" href="https://bossanova.uk/jspreadsheet/v4/jexcel.themes.css" type="text/css" />
    <link rel="stylesheet" href="https://jsuites.net/v4/jsuites.css" type="text/css" />

あとは、最近流行りのhtmxもCDN版があるそう。

念の為注意ですが、基本的にCDNは
ツリーシェイキングやトポロジカルソートでの依存関係解決をしないうえ
キャッシュサーバとはいえ毎度取得しに行くので、本番稼働には向いておらずあくまで書捨てや開発中ならバンバン使おうということをお忘れなく。


さて、みなさんはesm.shをご存知でしょうか?
npm installが必要なヤツらをCDN的に使えるものなのですが
これを用いるとnpm installが不要のままにnpm系を使ったjsが動かせるため、nodeを入れていない人の環境でも動く便利なフロントになります。

import React from "https://esm.sh/react@18.2.0";

このようにJSでimportすることでCDNするわけですね。
なお、こちらの記事がとても参考になります。

余談ですが似たようなサービスで、cheat.shというものもあります。
ターミナルで

curl cheat.sh/ls

とすれば、そのコマンドのチートシートを表示できます。

できればコンテナを使おう

さて、筆者も環境依存でいろいろ動かなかったので
やっぱりDocker最強ということで、Dev Containerを積極的に使うべきです。

まぁいつものツールが使えなくなる(主にエディタ)ので逆にやだという意見も私から出ています。
dotfilesのinstallまで込みでやってしまえばよいのかとか、未だ模索中なのですが
とにかくコンテナを用いて快適な開発体験(書き捨て)を追求したいですね

おわりに

今回は書き捨てでサクっとコード実行したり、APIホストたてたり、アプリを作ったりするための
ちょっとしたTipsをまとめました。
この記事自体がスニペットをはらんでますので、修正リクエストや追加したい項目ありましたらお気軽にお知らせください。

ALHについて知る



↓ ↓ ↓ 採用サイトはこちら ↓ ↓ ↓


↓ ↓ ↓ コーポレートサイトはこちら ↓ ↓ ↓


↓ ↓ ↓ もっとALHについて知りたい? ↓ ↓ ↓