20
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

AIでコードを書くことが当たり前になってきている現代において、コードの動きや意図を理解して責任を持てるかどうか重要になっています。

実際にあらゆる開発現場においてAIが必須になってきていますが、AIの生成したコードが分からない状態は危険だと思われます。

この記事では、私が過去のAI依存から抜け出せなかった自分への戒めと似たような境遇の方に向けて、注意喚起とコンピューターサイエンスの学習をオススメする理由をまとめています。

私自身、コンピューターサイエンスを学び始めて、自分で1からコードを書ける面白さを実感し、瞬時にいろんなコードの書き方が思い浮かぶようになりました。

今更ながら自分でコードを書けることの喜びと面白さを実感しています。

この記事を読んで、コンピューターサイエンスに興味を持ってくれたり、AI依存への危機感を持っていただければ幸いです。

筆者の苦い思い出

スクールを経て未経験からエンジニアになったものの失敗しました。
与えられたタスクに対して、自分でコードを考えることができず、AIに頼り切りの状態でした。

AIでその場のタスクを乗り切っても会社や自分の成長につながらないため、AIは使わないようにしたい、けれども自力で実装すらできないため、抜け出すことができませんでした。

結果、業務についていけず自己嫌悪となってメンタルを病んでしまい、エンジニアから離れる決断をいたしました。

当時の考えや状態は、下記の動画で語られている内容とほとんど同じ状態でした。

この経験から「自分で考えることの重要性」を理解して、また1からやり直すことにしました。

一度AI依存にハマると抜け出すのが難しく、未経験から学習するときはAIの使い方に気をつける必要があります。

なぜコンピューターサイエンスが必要か

AIでコードを書く時代だからこそ、基礎を理解していることが重要です。
AIを使う人とAIに使われる人で差が広がると考えています。

基礎が理解できてなければ、コードを自力で書くことができません。
業務を進めるためにAIでコードを生成しても内容がわからないため、コードに責任が持てません。

もし基礎を理解できていれば、コードの内容がわかっているから、生成されたコードが適切か判断して、修正・改善を行って、会社への貢献と自己成長に繋げていけます。

基礎を理解していてコードを書ける人がAIを使い、そうでない人はまず基礎の理解に徹する必要があると思います。

ここからコンピューターサイエンスが重要な理由を3選お伝えします。

1:AIに依存せず自分でコードを考える力がつく

与えられたタスクや課題へ適切なアプローチを考え、自分でコードが書けるようになり、解決方法の引き出しが増えます。

複雑な問題をシンプルなものに分解(抽象化)したり、やり方を変えることだってできます。

下記はhogeで適当に考えた、複雑な関数の中にあるfor文処理です。

TypeScript
// for文でhogeを数えて結合するプログラム
function Hoge(hoge: string[], n: number): string{
    // hogeの数を数える
    let count: number = 0;
    for(let i = 0; i < hoge.length; i++){
        if(hoge[i] === "hoge") count++;
    }
    
    // hogeをn回繰り返して結合
    let hogeCounter: string = "";
    for(let i = 0; i < n; i++){
        hogeCounter = hogeCounter + "hoge";
    }
    
    const result = `hogeの数は${count}です。\n${hogeCounter}`;
    return result;
}

const hogeList: string[] = ["hoge", "Hoge", "HOGE", "hoge", "hoge", "hoGe"];
console.log(Hoge(hogeList, 3));

// 出力結果
hogeの数は3です
hogehogehoge

これを抽象化(関数分解)し、再帰処理にしてみたやり方です。

TypeScript
function Hoge(hoge: string[], n: number): string{
    const count: number = hogeCount(hoge, 0);
    const counter: string = hogeCounter("hoge", n);
    const result = `hogeの数は${count}です。\n${counter}`;
    return result;
}

// hogeの数を数える
function hogeCount(hoge: string[], n: number): number{
    // ベースケース(終了条件)
    if(hoge.length === 0) return n;
    
    if(hoge[0] === "hoge") {
        hoge.shift();
        return hogeCount(hoge, n + 1);
    }
    hoge.shift();
    return hogeCount(hoge, n);
}

// hogeをn回繰り返して結合
function hogeCounter(hoge: string ,n: number): string{
    // ベースケース(終了条件)
    if(n === 0) return "";
    
    return hoge + hogeCounter(hoge, n-1);
}


const hogeList: string[] = ["hoge", "Hoge", "HOGE", "hoge", "hoge", "hoGe"];
console.log(Hoge(hogeList, 3));

// 出力結果
hogeの数は3です
hogehogehoge

コード量が多くなってきたので、ラムダ関数(reduce)、三項演算子などを用いてシンプルにします。

TypeScript
function Hoge(hoge: string[], n: number): string {
    // hogeの数を数える
    const count = hoge.reduce((count: number, current: string): number => {
        if (current === "hoge") count++;
        return count;
    }, 0);

    // hogeをn回繰り返して結合
    const counter = (n: number): string => n === 0 ? "" : "hoge" + counter(n - 1);

    const result: string = `hogeの数は${count}です。\n${counter(n)}`;
    return result;
}

const hogeList: string[] = ["hoge", "Hoge", "HOGE", "hoge", "hoge", "hoGe"];
console.log(Hoge(hogeList, 3));

// 出力結果
hogeの数は3です
hogehogehoge

一つの関数・複数の関数に分けるのか、繰り返し処理で「for文」「再帰処理」「ラムダ関数」といった複数のアプローチを考えることができますが、得られる答えは同じです。

問題に対して、自分でコードを考えて、複数のアプローチができると問題解決するのが楽しくなりますし、より良いコードを書くための引き出しも増えていきます。自信がつき、成長につながります。

2:効率性を意識したコードが書けるようになる

いろんなコードの書き方がある中で、「計算量」を減らして、メモリ消費の少ないアプローチを意識できるようになります。

計算量には、「時間計算量」と「空間計算量」の考え方があり、どちらも短く、少なければ良しとされます。「$O$ 記法」で表します。

計算量
アルゴリズムや問題を解くのにどれくらい手間を要したか表したもの。

時間計算量
手順に従って問題を解くために必要な実行の回数のこと。

空間計算量
実行するのに必要な記憶領域の容量のこと。

計算量を意識することができれば、サーバー負荷を減らすことを意識したコードを書けるようになります。

下記はfor文で名前を探して番号を返すコードです。計算量は「O(n)」です。

TypeScript
function foundNames(name: string): number{
    const members: string[] = [
      "あい",
      "あおい",
      "あかね",
      "いおり",
      "かえで",
      "さくら",
      "すず",
      "たくみ",
      "はる",
      "みお"
    ];
    
    for(let i = 0; i < members.length; i++){
        if(members[i] === name){
            return i + 1; // 配列のインデックスは0から始まるため
        }
    }
    
    return -1;
}

console.log(foundNames("さくら"));

// 出力結果
6

しかし、これだと配列を増やした時や別の値を追加で探索しようとした時に、また配列の最初から最後まで探索する必要があり、メモリ消費量が増えます。

より効率的に探索するためにハッシュマップを使って、計算量を「O(1)」にします。

TypeScript
function foundNames(name: string): number{
    const members: string[] = [
      "あい",
      "あおい",
      "あかね",
      "いおり",
      "かえで",
      "さくら",
      "すず",
      "たくみ",
      "はる",
      "みお"
    ];
    
    // ハッシュマップを作成
    let hashMap: { [keys: number]: number } = {};
    for(let i = 0; i < members.length; i++){
        hashMap[members[i]] = i + 1;
    }
    
    return hashMap[name];
}

console.log(foundNames("さくら"));
console.log(foundNames("たくみ"));

// 出力結果
6
8

大規模なシステムやアクセス量の多いシステムにおいて、これらの知識があると重宝されます。
ただコードを書くだけでなく、サーバー負荷やメモリ消費量を減らすという付加価値をつけられるようになります。

3:フレームワーク・言語の壁がなくなる

型、制御フローなどの内容はどの言語においても共通しており、オブジェクト指向が理解できれば、ブラックボックスに感じるフレームワークの構造理解にもつながります。

下記は適当に考えたTypeScriptのクラスです。人間をイメージしています。

TypeScript
class Human{
    firstname: string;
    lastname: string;
    gender: string;
    age: number;
    job: string;
    hobby: string;
    
    constructor(firstname: string, lastname: string, gender: string, age: number, job: string, hobby: string){
        this.firstname = firstname;
        this.lastname = lastname;
        this.gender = gender;
        this.age = age;
        this.job = job;
        this.hobby = hobby;
    }
    
    produce(){
        console.log(`初めまして、私は${this.firstname}${this.lastname}です。性別は${this.gender}${this.age}歳です。趣味は${this.hobby}です。よろしくお願いします。`);
    }
}

const man = new Human("デプロイ", "はるき", "", 20, "つよつよエンジニア", "プログラミング");
const woman = new Human("オブジェクト", "えみ", "", 20, "天使エンジニア", "スイーツ食べ歩き");

man.produce();
woman.produce();

// 出力結果
初めまして私はデプロイはるきです性別は男の20歳です趣味はプログラミングですよろしくお願いします
初めまして私はオブジェクトえみです性別は女の20歳です趣味はスイーツ食べ歩きですよろしくお願いします

このTypeScriptクラスをRubyで書くと次のようになります。

Ruby
class Human
    def initialize(firstname, lastname, gender, age, job, hobby)
        @firstname = firstname
        @lastname = lastname
        @gender = gender
        @age = age
        @job = job
        @hobby = hobby
    end
    
    def produce
        puts "初めまして、私は#{@firstname} #{@lastname}です。性別は#{@gender}#{@age}歳です。趣味は#{@hobby}です。よろしくお願いします。";
    end
end

man = Human.new("デプロイ", "はるき", "男", 20, "つよつよエンジニア", "プログラミング");
woman = Human.new("オブジェクト", "えみ", "女", 20, "天使エンジニア", "スイーツ食べ歩き");

man.produce();
woman.produce();

# 出力結果
初めまして私はデプロイ はるきです性別は男の20歳です趣味はプログラミングですよろしくお願いします
初めまして私はオブジェクト えみです性別は女の20歳です趣味はスイーツ食べ歩きですよろしくお願いします

書き方が少し変わるくらいでほぼ変わりないことがわかります。

変数や型、オブジェクト指向といった基礎は、プログラミング言語において共通の概念です。

これらを理解できていれば、異なるプログラミング言語・フレームワークへの理解と素早いキャッチアップにつながります。

おすすめの学習方法

私は現在、「Recursion」というサービスを利用して、AIを使用せずにひたすら問題を解いて学習しています。

問題を解くという観点においては、「Paiza」や「Atcoder」が良いと思いますが、基礎概念を徹底的に磨いて上位エンジニアを目指すなら「Recursion」が最適だと思います。

どの学習媒体においても、たくさん問題を解いてアウトプットし、AI抜きにいろんなアプローチを考えられる状態に持っていくべきだと考えています。

おわりに

この記事を読んでくださった方には、私と同じような失敗をして欲しくないです。

コンピューターサイエンスの重要性、そしてAIとの向き合い方を今一度考えていただき、目先の年収や技術だけにとらわれないでいただきたいです。

私もまだコンピューターサイエンスを学んでいる途中です。またチャンスがあればエンジニアになるつもりですので、共に頑張りましょう。

コンピューターサイエンス及びプログラミングは、人生の柱になるスキルと信じています。

この記事が良かったと感じたり、面白いと思っていただければ幸いです。

20
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?