この記事は 42 Tokyo Advent Calendar 2023 の 18日目の記事です。
自分のプログラミング歴
私は、大学の合格発表直後にMacBookをポチり、次の日にAppleStoreに取りにいった日からプログラミングをスタートしました。
大学では数学を専攻していて、情報の世界に触れる機会はほとんどないので、独学で勉強を進めていきました。Progateでの基礎学習から始め、YouTubeを見てとりあえずできることを増やすということやTSUTAYAで立ち読みしたキーワードを手がかりに帰宅後にそれらを検索し実装を試みるということをしていました。
そんなこんなで色々なアプリの開発に触れてきて、そろそろ多くの人の手に触れられるアプリが作りたいと、大学2年生の1月に2年間の集大成として自大学生専用の時間割アプリとして「がんコマ」をリリースしました。学内10%,新入生30%にダウンロードして貰えました。そのアプリの上では、ユーザー間でのコミュニケーションは一切なし、メモなども外部のクラウドデータベースなどではなくローカルデータベースに保存し、シラバスなどの時間割データさえもアプリにデータとしてそのままjsonで保存していて、外部通信が一切ないアプリになっています。なぜなら、セキュリティに対する知識が全くなかったからです。2023年前期東京のとあるコワーキングスペースに通い詰め、そこにいたNauNauの開発者さんに触発される中で、とりあえず動くアプリからちゃんと動くアプリを作れるエンジニアになるために私は42Tokyoに来ました。
独学だったので、常識を完全に知っているわけではないけれど、早く知っといたほうがよかったまあこういうアプリをやりたいんだったらこういう風にスタートできるということをまとめました。
この記事を読まないとどうなるか
一番最初に作ったアプリケーションはHTML1ファイルで作った人狼です。その1ファイルはパソコンには当たり前に残っていないし、その時には一応登録はしていたけれど使い方もわかっていなかったのでGithubにも残っていませんが、サークルの先輩繋がりで繋いでもらった同大学情報科の先輩のツヨツヨさんから教えてもらったfirebaseのrealtimedatabaseという現在では非推奨なデータベースを使って構築していました。html1ファイルのみでもちろんフレームワークも使っていないので、鬼のようにネストが深く構成されていまして、realtimeのlistenを死ぬほど走らせて、どんなサーバ(ユーザーが所属しているグループ)が建てられているか、自分が所属したサーバーのゲームが継続中か、どんな状態かなどをwhile文、if文で書いたのを覚えています。その時には、サーバーサイドという概念を知らなかったので、ユーザがサーバーに入室した順番と時間をなんとかして一意にランダムな役職が割り振られるアルゴリズムを考案して喜んでいたのを覚えています。
まずSOLID原則について
初めて聞く人も多いかもしれない「SOLID原則」とは、ソフトウェア開発における5つの原則を指す用語です。これらは、効果的なオブジェクト指向設計のためのガイドラインとして広く認識されています。42 Tokyoでの25行ルール、いわゆる「Norminette」は、「とにかく短く書け」という方法で間接的にこれらの原則に沿う書き方を促進する方法の一つと考えられます。また、「意味のあるところで関数を切ったほうがいいよ」など言われたことがある人もいるのではないでしょうか。では、SOLID原則を知らないとどうなるのでしょうか?
SOLID原則を知らないとどうなるのか
コードの再利用が困難:単一責任の原則を無視すると、1つのクラスや関数が複数の責任を負うことになり、再利用が難しくなります。
拡張性の欠如:開放/閉鎖の原則に反する設計では、新しい機能を追加するために既存のコードを頻繁に変更する必要があります。
不安定な継承関係:リスコフの置換原則を無視した場合、サブクラスが基底クラスと適切に相互作用しない不安定な継承関係が生まれる可能性があります。
過剰な依存:インターフェース分離の原則に従わない場合、クライアントは不必要な依存関係に縛られることになります。
複雑な依存関係:依存関係逆転の原則を無視すると、高レベルのビジネスロジックが低レベルの実装詳細に依存し、コードが複雑に絡み合うことがあります。
つまり、SOLID原則を知らずに人狼を作った自分は、一つ管理したい情報が生まれた時にコードのほぼ全文を書き換える必要があって非常に苦労しました。
SOLID原則の概要
SOLID原則は、オブジェクト指向プログラミングをより効果的にするための一連の設計原則ですが、オブジェクト指向言語でないC言語や、オブジェクト指向言語であるTypeScriptでの適用方法についても解説します。(リスコフを勝手に省く)
単一責任の原則(Single Responsibility Principle,細かく分けろ):
一つのクラス(または関数)は一つの機能や責任のみを持つべきです。これにより、コードが読みやすく、メンテナンスしやすくなります。
開放/閉鎖の原則(Open/Closed Principle,書いたコードの変更はいらない(はず)):
ソフトウェアのエンティティは、新しい機能に対して開かれている(拡張可能)でありながら、既存のコードに対しては閉じている(変更不要)であるべきです。
インターフェース分離の原則(Interface Segregation Principle,細かくしたいのにいらん要素入れるな):
クライアントは、使用しないメソッドに依存強制されるべきではありません。必要なメソッドのみを持つ小さなインターフェースが望ましいです。
依存関係逆転の原則(Dependency Inversion Principle,使う側と使われる側):
抽象モジュールは詳細モジュールに依存するべきではなく、両者は抽象の方に依存すべきです。
C言語での適用
C言語はオブジェクト指向言語ではありませんが、関数を用いてSOLID原則をある程度適用することが可能です。たとえば、単一責任の原則に従って、各関数が一つの具体的なタスクのみを実行するようにすることができます。また、モジュラーな設計を通じて、コードの拡張性や再利用性を高めることが可能です。
TypeScriptでの適用
TypeScriptはオブジェクト指向言語であり、クラス、インターフェース、継承などの特徴を持っています。これにより、SOLID原則を直接的に適用することが容易です。例えば、クラスを用いて単一責任の原則を実現したり、インターフェースや抽象クラスを使って依存関係逆転の原則を適用することができます。
SOLID原則を念頭に入れておくだけで、とりあえず修正しやすいコードを書けるようになります。ただ、42のNorminetteの中では、5関数しか使ってはいけないというルールもあります。細かく分けたいのに分けれない。GNLでは、それに苦労したと思います。それはもうどうしようもないので頑張りましょう。
とりあえずアプリ入門s
既に2年半、挑戦も含めていろんなアプリを作ってきたので、それらの入門方法についてまとめてみました。SOLID原則も意識しながら、一つのアプリを構築するという経験はとても良いものとなると思います。アプリ作りに挑戦してみたい人や、作りたいアプリがある人、ハッカソンに出てみたい人、42のモチベ下がり始めた人はとりあえずアプリを作ってみるところから42が何を伝えたいのか、42の優良性に気づくのもいいかなと思います。
以下についてまとめました。
Web開発: ReactとNext.js
Webアプリ開発のために、ReactとそのフレームワークであるNext.jsを紹介します。これらは、現代のウェブ開発において非常に重要なツールです。
スマートフォンアプリ: Flutter
クロスプラットフォーム開発のフロントランナー、Flutterについても掘り下げます。これにより、iOSとAndroidの両方のプラットフォームで動作するアプリを一つのコードベースで構築できます。
ゲーム開発: Unity
ゲーム開発に興味があるなら、Unityがその答え。Unityであれば、初心者からプロまで幅広い開発者が利用できる強力なゲームエンジンです。
サーバーサイド・バックエンド: GoとFlask
サーバーサイドの開発には、Go言語とPythonのFlaskを取り上げます。これらはサーバーサイドの開発において効率的かつパワフルなオプションです。
クラウドサービス: FirebaseとSupabase
最後に、FirebaseとSupabaseについて説明します。これらのクラウドサービスは、認証、データベース、ストレージ、ホスティングなど、アプリ開発に必要な様々な機能を提供します。
Webアプリ開発: ReactとNext.js
Reactの登場前のウェブ開発
Reactが登場する前のウェブ開発の世界は、今とはかなり異なっていました。その時代のウェブアプリケーションは、主にjQueryや純粋なJavaScript(Vanilla JS)によって動かされていました。ウェブページはしばしばサーバーサイドで全面的にレンダリングされ、クライアントサイドでは限定的な動的操作のみが行われていました。このアプローチは、ウェブアプリケーションの拡大に伴い、次第に限界に直面し始めました。ページを更新するためには、しばしば全ページの再読み込みが必要であり、これはユーザーエクスペリエンスの低下に繋がっていました。
Reactの革命
Reactの登場は、このウェブ開発のパラダイムに革命をもたらしました。Reactはコンポーネントベースのアーキテクチャを導入し、再利用可能で保守が容易なUI部品を構築することを可能にしました。これにより、開発者はウェブアプリケーションの各部分を独立したコンポーネントとして考え、それぞれを個別に管理・更新できるようになりました。また、Reactの仮想DOM(Virtual DOM)は、実際のDOMに直接触れることなくUIの変更を効率的に行うことを可能にし、パフォーマンスとユーザーエクスペリエンスを大幅に向上させました。
Next.jsのすごさ
Reactがフロントエンド開発を変革したのと同様に、Next.jsはReactベースのウェブ開発をさらに前進させました。Next.jsは、Reactのコンポーネントモデルを踏襲しつつ、サーバーサイドレンダリング(SSR)や静的サイト生成(SSG)といった機能を提供します。これにより、ウェブアプリケーションの初回読み込み速度が向上し、SEO(検索エンジン最適化)にも有利に働きます。さらに、Next.jsはルーティングやデータフェッチングを簡単に行えるよう設計されており、Reactだけでウェブアプリケーションを構築する際に直面する多くの課題を解消します。
Next.jsの別の重要な機能は、APIルートのサポートです。これにより、開発者は同じNext.jsプロジェクト内でAPIエンドポイントを簡単に作成し、管理することができます。これは、バックエンドのロジックを直接ウェブアプリケーションと統合することを可能にし、別個のサーバーやバックエンドシステムを設定する手間を省きます。
これらの技術の組み合わせにより、フロントエンドもバックエンドも現代のウェブ開発ではJavascriptという言語一つで、より高速で、スケーラブルで、ユーザーフレンドリーなアプリケーションを構築することができるようになりました。ReactとNext.jsは、ウェブ開発の現代的な要求を満たす強力なツールキットを提供します。 デジタル庁のウェブサイトにもNext.jsが導入されています これらの技術だけでなく、歴史も少し知っておくことでその有用性にさらに迫ることができ、意識した開発でより良いプロダクトを作ることができるでしょう。
Tailwind CSSについて
Web開発をする上で知っといたほうがいいもう一つがTailwindについてです。
近年、ウェブ開発の世界で注目を集めているのが、Tailwind CSSです。紹介したNext.jsにも標準搭載されています。このユーティリティファーストのCSSフレームワークは、従来のCSSのアプローチとは一線を画し、効率的で直感的なウェブデザインを可能にしています。具体的には、Tailwind指定の文言をHTMLの class(オブジェクト指向のそれとは異なる)に書き込むだけで、CSSが適応されるのです。これにより、慣れたらcssファイルなしで一瞬で小綺麗なWebページが作れます。
Wappalyzerについて
Wappalyzerは、ウェブサイトが使用しているテクノロジを識別するブラウザ拡張機能です。このツールは、サイトがどのようなコンテンツ管理システム(CMS)、eコマースプラットフォーム、決済プロセッサーなどを使用しているかを教えてくれます。
import { useEffect, useState } from 'react';
export default function Home() {
const [message, setMessage] = useState('');
useEffect(() => {
fetch('/api/hello')
.then(response => response.json())
.then(data => setMessage(data.message));
}, []);
return (
<div className="bg-gray-100 p-4 rounded-lg shadow-lg">
<p className="text-blue-500 text-lg font-semibold">{message}</p>
</div>
);
}
import { NextResponse } from 'next/server';
export async function GET() {
return NextResponse.json({ message: "hello" });
}
フロントエンドとバックエンドを同じJavascript内で分離して記述することができる。ChatGPTとハンズオンで開発を進めているとNextjs13,14以前のApprouterとは違う記述方法で書かれてしまうので注意!
スマホアプリ開発: Flutter
Flutterは、Googleによって開発されたオープンソースのUIソフトウェア開発キットです。このツールは、iOSとAndroidの両方のプラットフォームで動作するアプリケーションを、単一のコードベースから開発することを可能にします。Flutterの最大の魅力は、その高いパフォーマンスと、美しいUIを簡単に作成できる点にあります。
環境構築の難しさとVSCodeでの開発
Flutter開発を始めるための最初のステップは、環境構築です。これは他の多くの開発環境よりも少し複雑であると言えます。Flutterの開発環境をセットアップするには、Flutter SDKのインストール、適切なIDEの設定、そしてエミュレーターまたは実際のデバイスでのテスト環境の構築が必要です。このプロセスは、特に新しい開発者にとってはやや挑戦的な部分があります。
しかし、一度環境が整えば、VSCodeなどの人気のある開発環境を使用して快適に開発を進めることができます。VSCodeはFlutter開発者にとって強力なツールであり、豊富な拡張機能、デバッグツール、そして直感的なコードエディターにより、開発プロセスを大幅に効率化します。
クロスプラットフォーム開発の利点
Flutterのもう一つの大きな利点は、クロスプラットフォーム開発が可能であることです。同じコードベースでiOSとAndroidのアプリを構築できるため、開発時間とコストを大幅に削減できます。また、Flutterは独自のウィジェットセットを提供しており、一貫性のある美しいUIを実現することができます。
Flutterは、その使いやすさ、高性能、そして美しいデザインの可能性により、多くの開発者にとって魅力的な選択肢となっています。環境構築がすごい難しいです。なお、自分の作った時間割アプリは、Androidでのリリースにつまづいて諦めました。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Hello World'),
),
body: Center(
child: Text('Hello, world!'),
),
),
);
}
}
ゲーム開発:Unity
Unityは、ゲーム開発において最も人気のあるプラットフォームの一つです。C#言語を使用して、あらゆる種類のゲームを開発することができます。このツールは、特に3Dゲームの開発において高い評価を受けていますが、2Dゲームの開発にも対応しています。特に、ゲーム開発では考慮すべきデザインのポイントが多すぎて骨が折れる作業が続きます。自分は、学生のレベルで言ったら好きでやってて、すごい多くの細かい点まで考慮しないといけないゲームプログラマーが最高のプログラマーだと思ってます。自分の周りにいたゲームプログラマーでは、子供の時からプログラミングやってきた人が多かった印象があるのもその一つかもしれません。
無料アセットとその利点
Unityの特徴の一つは、豊富な無料アセットの存在です。Unityのアセットストアには、無料で利用可能なモデル、テクスチャ、サウンド、スクリプトなどがあります。これにより、開発者はゲームのあらゆる側面を一から作り出す必要がなく、開発プロセスを大幅に短縮できます。また、インターネット上にも多くの無料アセットが存在し、これらを活用することで、より迅速かつ効率的にゲーム開発を進めることが可能です。
パフォーマンスとハードウェア要件
Unityでの開発には、比較的高いハードウェア性能が要求される場合があります。特に3Dゲームの場合、高いCPU性能と十分なメモリが必要となります。自分は、MacBook Proのような高性能なハードウェアでもパフォーマンスの問題に直面しました。具体的には、Unityが突然落ちて置いていたパーツなんかが全部消えたりします。コードは自動保存されているから助かったんですけどね。このため、Unityでの開発を行う際には、ハードウェアの選定にも注意が必要です。
using UnityEngine;
public class SimpleRotation : MonoBehaviour
{
// 回転速度を設定する変数(単位は度/秒)
public float rotationSpeed = 90.0f;
void Update()
{
// 毎フレームごとにオブジェクトをY軸周りに回転させる
transform.Rotate(0, rotationSpeed * Time.deltaTime, 0);
}
}
物を回転させる(向きを変える)のも全部コードで記述されているわけなので、いかに滑らかに自然に動かすかを意識すると頭がオーバーフローします。
基本的には、作りたいゲームを思い浮かべながらスクリーンショットとコード、エラー文をChatGPTに投げながらやればいいんですが、一人で一つのゲームを作ろうと思うと要素が多すぎて、考慮できていない点などが出てくるので、導入にも常識を知るにもYoutubeは必須だと思いました。このチャンネルでは、Unityに関する様々なチュートリアルやヒントが提供されており、初心者から上級者まで幅広いユーザーに対応しています。特に、実践的なアプローチと具体的な例を通して、Unityの機能を理解しやすく解説しています。
Unityは、その多機能性、高いカスタマイズ性、そして豊富なリソースにより、ゲーム開発者にとって魅力的な選択肢となっています。無料アセットの利用、ハードウェア要件への注意、そして有用なリソースの活用により、Unityでのゲーム開発は、想像力の限界を超える可能性を秘めています。
サーバーサイド・バックエンド:GoとFlask
Go(Golang)
Go言語(またはGolang)は、Googleによって開発されたプログラミング言語で、特にサーバーサイドの開発において人気があります。Goは、シンプルさ、効率の良い並行処理、高速なパフォーマンスが特徴です。型付けがありながら、:=を用いた簡潔な変数宣言が可能で、これがコードの読みやすさと高速な処理を両立させています。
基本的なGoサーバーのコード例
Goで最も基本的なHTTPサーバーを立て、GETリクエストで{"message": "hello"}というJSONを返すコードは以下の通りです。
package main
import (
"encoding/json"
"net/http"
)
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
func handler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
response := map[string]string{"message": "hello"}
json.NewEncoder(w).Encode(response)
}
このコードは、8080ポートでサーバーを起動し、ルートパスにアクセスがあった場合にJSON形式のレスポンスを返します。
Flask(Python)
Flaskは、Pythonで書かれた軽量なWebフレームワークです。初心者から上級者まで幅広いユーザーが使用でき、特に小規模なアプリケーションやプロトタイプの開発に適しています。Flaskは拡張性が高く、必要な機能を簡単に追加できるのが特徴です。Pythonは文法的にも、豊富なライブラリ的にもとても描きやすい言語なので、とりあえず思った作りたいものを作る時には大体これで行えるのかどうかを調べてから行います。PythonにおけるWebフレームワークとしてもう一つDjangoというものがあるのですが、そちらからは学習コストが高すぎて逃げています。
基本的なFlaskサーバーのコード例
Flaskで最も基本的なHTTPサーバーを立て、GETリクエストで{"message": "hello"}というJSONを返すコードは以下の通りです。
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/')
def hello():
return jsonify({"message": "hello"})
if __name__ == '__main__':
app.run(debug=True)
このコードは、デフォルトの5000ポートでサーバーを起動し、ルートパスにアクセスがあった場合にJSON形式のレスポンスを返します。
GoとFlaskは、それぞれ異なる特性を持ちながらも、サーバーサイド開発において非常に強力なツールです。Goの高速処理能力と型付けの柔軟性、Flaskのシンプルさと拡張性の高さは、サーバーサイド開発を行う際の重要な要素です。これらの言語を活用することで、効率的かつ効果的にバックエンドシステムを構築することが可能です。
クラウドサービス: FirebaseとSupabase
FirebaseとSupabaseは、アプリ開発を簡単にするためのクラウドベースのサービスです。これらは、アプリの「バックエンド」と呼ばれる部分を構築し、管理するのに役立ちます。バックエンドとは、アプリのデータ処理や保存、認証(ユーザーログインなど)などを行うサーバー側のことを指します。アプリ外部でデータベースを用意したいときや、ユーザー間でデータを共有したい時にはローカルのデータベースではなく、これらクラウドサービスを使う必要があると思います。
Firebase
FirebaseはGoogleが提供するサービスで、次のような特徴があります:
認証機能: ユーザーがアプリにログインするためのサポート(例えば、メールアドレスとパスワード、Googleアカウントを使用したログインなど)。
データベース: FirebaseのFirestoreは、データを保存し、アプリと同期させるためのNoSQLデータベースサービスです。
ストレージ: 写真や動画などのメディアファイルを保存できます。
Firebaseは初期段階や小規模プロジェクトには無料で使用でき、プロジェクトが成長するにつれて料金が発生します。
Supabase
SupabaseはFirebaseのオープンソースの代替品で、以下の特徴があります:
PostgreSQLデータベース: より伝統的な関係データベースを使用し、構造化されたデータの管理に適しています。
認証機能: SupabaseでもFirebaseと同様に、ユーザー認証のための機能を提供します。
ストレージ: ユーザーが生成したコンテンツの保存と管理に対応し、S3バックエンドを使用します。
Supabaseも初期段階には無料で利用できますが、より多くのリソースが必要になると料金がかかります。
どちらを選ぶべきか
どちらのサービスもアプリ開発において強力なバックエンド機能を提供しますが、選択はプロジェクトのニーズによります。FirebaseはGoogleの他のサービスとの統合が容易で、より成熟した環境を提供します。Firebaseが提供するFirestore(NoSQL)は基本的にidごとに違ったデータ構造でも許容されているデータベースで、Pythonで言う辞書型をそのままアップロードできるっていう形のデータベースです。一方、Supabaseはオープンソースで、伝統的なSQLベースのデータベースとの親和性が高いです。
最終的な選択は、アプリの要件、データベースの種類(NoSQLかSQLか)、予算、および自由度(オープンソースかプロプライエタリか)などを考慮して決定します。これらクラウドサービスのドキュメントは言語のドキュメントなどよりもわかりやすくまとまっているというのが個人的な感想です。なので、ドキュメントを見ながらプログラミングをする練習にもなると思います。
以上です。疲れた。