【ベンダー資格】Salesforce Certified Javascript Developer Ⅰ挑戦記
Salesforce認定Javascriptデベロッパーの資格を取得しました!
はじめに
この資格は、「テストで合格点以上とったら資格取得」というものではなく、Javascriptの試験とSuperbadgeというTrailheadの2つをクリアすることで晴れて資格取得となるもので(ここの受験ガイドにそう書いてある)、試験に合格さえすれば認定されるような今までとってきた資格とは様相が少し異なる。基本的にはここではJavascriptの試験の話を中心に語っていく。
JavaScript デベロッパー多肢選択試験 について
そのまんまの名前すぎるが、受験ガイドでそう記載されているのでそのまま拝借させてもらう。いろんなところで紹介されているが、この試験自体はSalesforceの知識は全く問われない、純粋にJavascriptの知識だけが問われる試験である。というかまさにその特徴が、今回この資格を取得しようと思った動機なのだが。実際、試験勉強や受験してみた感じ、その点ーつまり「Javascriptの知識・スキルを有している」という内容を証明するという目的-だけでも十分通用する内容の試験だと思っていて、独立した資格試験として活用できるレベルのものだと思う。(個人の意見です)JavaやらPHPやらに関しては、プログラム言語の公式な資格試験があるのは有名な話だと思われるが、Javascriptの資格試験って(個人的には)あまり耳にしたことがないので、「Javacriptの知識・スキルを有している」ということの対外的な証明において、この試験は良いんじゃないかと思った。まあ資格はSuperbadgeこなさないとゲットできないんだけど。
ただ、実際この資格を取って振り返ってみてわかったが、この「JavaScript デベロッパー多肢選択試験」は、後述するSuperbadgeのTrailに対してある程度最適化されている(少なくともその側面がある)と思われる。Superbadgeの、特にその前提条件となるいくつかのTrailでは、この試験対策で学んだ知識を生かす場面が結構ちょいちょい出てきた。この試験で扱っている範囲にはSuperbadgeの範疇を超えている部分もあるが、試験の目的の半分くらいは多分Superbadge向けになっている。と思う。個人の意見です。
結果
非同期プログラミングがカスすぎてワロタww はい、実際苦手ですここ。いつも感覚で書いてるところあるからな…他はまあそんなもんかなあって感じではある。ただ、Debugging and Error handlingがなぜか100%だが、これは正直こんなに出来ていた実感がない。運が良かったのかもしれない。それと、普段使いの範囲では、Server sideでJavascript使う機会(Node.js)の方が圧倒的に多いので、Server side Javascriptはもう少し取りたかったところだが、サーバーサイドの中でも普段あまり触れないような範囲が出題されたので、まあ仕方ないかもしれない。そもそも基本的にはJavascriptじゃなくてTypescriptで書いちゃうことのほうが多いしな…
合格ラインは65%で、%の数値を合算して単純平均すると69%なので、ギリギリ合格ラインに乗ったという感じのようだ。大体いつも資格試験はそんな感じである。ギリギリでいつも生きていたいのだ。
感想
難しかった。 一言でいうならこれに尽きる。というかCertified Heroku ArchitectもそうだがSalesforceの資格試験はほかのベンダー資格と比べても頭1つ2つ抜けて難易度が高い印象がある。挑戦するまでは、正直「Javascriptならまぁまぁ知ってるし今でもちょいちょい使ってるからなんとかなるんじゃねww」みたいに、正直ナメた態度だったが、実際に勉強・受験してみて、そういうナメた態度では絶対合格できなかっただろうと思い直している。
一つ言い訳させてもらうなら、試験で問われるようなJavascriptのコードは、個人的な感覚では、少なくとも昨今の流行の最先端ではないと思われ、そういう「よく見る使われ方」から離れた部分がメインの出題範囲になっているため、「Javascriptを書いたことがある」という人でも、見慣れない・知らない内容が多くあり、それがこの試験を難しくしているように思う。ブラウザ上で動かす(クライアントサイドの)Javascriptって、今やもういろんな素敵フレームワークがいい感じにカバーしている範囲が圧倒的に多く、現代においてそのコアな部分をいちいち集中して学ぼうとする人は、正直あんまりいないのではないか、というのが個人的な感覚である。令和の時代になってわざわざdocument.getElementById
とか進んで書こうとしなくないッスか??(とか言いながら俺はちょっと前に止むを得ず書いてしまったことはあるが…)まぁ逆に言うとそういう普段「いい感じにカバーされてる範囲」を改めて勉強する必要があることを考えると良い機会かもしれないが…
あとJavascriptのクラスとか、then()
やcatch()
使った非同期処理とか、ブラウザの機能(DOM検査やデバッグのツール名、できること等)とか、hoisting(巻き上げ)とか、「薄っすら知ってるんだけどそれほどガチって使ったことはないもの」があって、それらが出題範囲にまんべんなく散りばめられていて、上とは少し背景が違うが、これらも(仮にJavascriptを書くことになっても)「わざわざ進んで書こうとはしない/使おうとしない」ような内容だと個人的に思っており、これも総合的に試験の難しさを後押ししていると思う。俺のような表面的な理解で勢いでコード書いちゃう人からするとこういう基本的・体系的な知識は問われると結構つらい部分が多く、なかなか苦戦した。
試験対策
資格取得のためのSuperbadgeとは別に、この試験用にTraillheadがいくつか用意されているので、これらをやった。
特に前者のTrailheadにあるテストは参考になった。これで学んだ知識もいくつかある。扱ってるのは基本的な内容が多いが、いかんせんそういう部分が抜け落ちてる人間なので、こういう形で学習の場が提供されるのは助かる。いかに普段から「基本」を無視して雰囲気でコーディングしてるかを思い知らされた。。
あと体験記としては以下のサイト。
- Salesforce 認定 JavaScript デベロッパー の勉強メモ
- 【Salesforce】認定JavaScriptデベロッパー試験対策
- Salesforce 認定 JavaScript デベロッパー合格記
試験で出題される一部のトピックに関して、(おそらく筆者ご自身の勉強を踏まえて書いたであろう)具体的なコード例などを交えて解説がされており、わかりやすい。試験範囲を網羅するようなものではないが、扱っている内容に関しては参考にさせてもらった。
模擬試験・練習問題としては以下の2点。
前者(Focus on Force)は有料である($24)。一応2つともやってみたが、ことこの試験対策だけを目的とするなら、正直後者だけでも十分な気はする。このテのやつの常で、Focus on Forceにしても実試験にしても、内容に関しては詳細に言えないのだが、前者(Forcus on force)の模擬試験は、問題文および解説が英語だし、それも相まって実試験に比べると難易度が+1~2段階上をいってる印象がある。一方、後者の難易度は、実試験と同じか逆に少し下回る感じ。なので実試験に挑むならどっちかだけだと過不足出そうだが、無料で出来る点を踏まえても後者の方が使い勝手がいいという印象。あくまで個人の意見ですが。
TOPIC
勉強途中のメモ群。
-
Javascriptのクラスはコンストラクタを2つ持てない。2つ目定義すると
SyntaxError: A class may only have one constructor
になる。class A { constructor(a) { this.a = a; } constructor(a,b) { this.a = a; this.b = b; } }
↓
# node double-constructor.js constructor(a,b) { ^^^^^^^^^^^ /double-constructor.js SyntaxError: A class may only have one constructor
Javaとは違うらしい。まあシンプルでわかりやすい、、、といえばそうかもしれない。
-
function
で定義した関数ブロック内でthis
書くとそのfunctionはclassのconstructorとして機能するようになる。なのでnew
でインスタンス生成できる。function A() { this.a = 'aaa'; } const a = new A(); console.log(a.a);
↓
# node this-test.js aaa
-
↑の性質はアロー関数にはない。なので
new
でインスタンス生成しようとするとエラーになる。const B = () => { this.b = 'bbb'; }; const x = new B();
↓
# node this-test.js const x = new B(); ^ TypeError: B is not a constructor
-
一方、アロー関数内で
this
が使えないかというとそうでもなく、この場合アロー関数の「外」のブロックのthis
を指すようになる。なので以下のようなコードは一応動く。let b = 'b'; const B = () => { this.b = 'bbb'; }; const x = B(); console.log('this.b',this.b);
↓
# node this-test.js this.b bbb
let b = 'b';
の初期値がconst x = B();
でB()
がコールされたときにその関数ブロック内のthis.b = 'bbb';
で上書きされて、最終的に"this.b bbb"
と出力されていることが分かる。しかしわかりづらい動きだ。。。 -
空文字(
''
)はfalse
扱いになる。console.log(''?'true':'false');
↓
# node empty-string.js false
へぇ~。知らなかった。正直
if
の条件文でたまに使っちゃうけど、こういうこともあるので、三項演算子やif
の判定にboolean
以外の値を渡すのはできればやめたほうがいいね。。 -
JSON.parse
はプロパティ名に当たる文字列をシングルクォートで囲っているとエラーになって落ちる。プロパティ名に当たる文字列は必ずダブルクォートで囲う必要がある。const j1 = '{"id":1,"name":"a"}'; const j2 = "{'id':2,'name':'b'}"; JSON.parse(j1); JSON.parse(j2);
↓
# node json-parse-test.js {'id':2,'name':'b'} ^ SyntaxError: Unexpected token ' in JSON at position 1
へ~、そうなんだっていう学び。
curl
で-d
でJSON形式のパラメータ書く場合ってどっちもOKじゃなかったっけ?? -
数値+文字は文字になるが、文字×数値は数値になる。
> console.log(typeof (1+'2')); string
> console.log(typeof ('2'*2)); number
そうなんだ。。こんなナメたコードは実運用でお目にかかる機会はまずない(と思いたい)ので、豆知識って感じではあるが。。
-
setTimeout
は第二引数(待ち時間)に0
を指定していても直後のコードに実行可能なコードがあればそっちの実行が優先され、setTimeout
の第一引数の関数の実行は(結果的には)後回しになる。これはsetInterval
でも同様。console.log('check-1'); setTimeout(()=>{ console.log('check-t') },0); console.log('check-2');
↓
# node settimeout-test.js check-1 check-2 check-t
-
parseXxx系のメソッド、例えば
parseInt
とか、は、Number.parseInt
という風にNumber
から指定しても動くし、Number
の指定がなくても動く。> console.log(Number.parseInt("1")); 1 undefined > console.log(parseInt("1")); 1 undefined
-
javascriptにおける数値型は
number
しかない。1
みたいな整数でもMath.PI
みたいな無理数(浮動小数点)でもぜんぶnumber
。参考> console.log(typeof 1.2); number > console.log(typeof Math.PI); number
-
export default
したやつは読み込み側で任意の名前でimport
できる。例えばexport-test.js
に以下のような内容が定義されていたとして、function E() { return 'e'; } export default E;
これを読み込んで使う側の
import-test.js
でこんなふうに読み込んでいても、import X from './export-test.js'; console.log(X());
実行するとちゃんと動く。。
# node import-test.js e
そうなんだ…知らなかった。でもわざわざ
export
元で定義している名前から意図的に変えてまでimport
したくない気がするけどな。。わかりづらくない??たまたま同じ名前の変数や関数がすでに定義がある場合に衝突避けるために…みたいなときには有用そうだけどそもそもそんな衝突起きるような名前の付け方してる時点で何かおかしい気もするし。個人の意見ですが。 -
「巻き上げ(hoisting)」について。変数や関数をその定義よりも前に使用することをこういうらしい。公式ドキュメントはここ
import
は巻き上げの対象なので、コードの最下部にimport
書いてimportした変数なり関数をコードの最上部で使っても動作する。以下のようなコードは想定通り動作する。console.log('hogehoge',hogehoge()); import hogehoge from './export-test.js';
- 関数定義も同様に巻き上げの対象である。関数の実行を関数定義よりも先に書いても想定通り動作する。
console.log(hugahuga()); function hugahuga() { console.log('hugahuga'); }
- 変数宣言のうち、
let
とconst
は巻き上げられない。このため定義より前に参照するとエラーになる。↓console.log('x',x); let x=1;
console.log('x',x); ReferenceError: Cannot access 'x' before initialization
- 変数宣言の中で唯一例外的に
var
だけは巻き上げられる(let
とconst
で同じことするとエラーになるが、var
ではエラーは起きない)。ただし初期化前なので値はundefined
になる。↓console.log('y',y); var y=2;
y undefined
-
then()
が受け取る引数は前のthen()
がreturnした値である。途中でcatch()
やfinally()
を挟んでそれらが何かをreturnしていたとしても、直後のthen()
はそれを受け取らない。例えば{"msg":"hello"}
というJSONを返すAPIがあったとしてそれをコールしてthen()
でchainする場合、const r = fetch(url) .then((d)=>{ console.log('then1',typeof d,d); return d.text(); }) .then((dt)=>{ console.log('then2',typeof dt,dt); return dt; }) .catch((e)=>{ console.log('error',typeof e,e); return e; }) .then((e)=>{ console.log('then3',typeof e,e); return e; }) .finally(()=>{ console.log('finally'); return 'FINAL'; }) .then((f)=>{ console.log('then4',typeof f,f); return f; }) ;
この実行結果は以下↓のようになる
then1 object Response { [Symbol(realm)]: null, ... then2 string {"msg":"hello"} then3 string {"msg":"hello"} finally undefined undefined then4 string {"msg":"hello"}
この場合はthen4の前に
finally()
がいてそいつが"FINAL"
という文字列をreturnしているが、then4はそれを受け取っておらず、直前のthen()
であるthen3がretunしたものをそのまま引き継いでいる。 -
finally()
のコールバック関数は引数を受け取らない。定義してもいいが何も渡されないのでundefined
になる。fetch(url).then(d=>d).finally(f=>console.log('finally',f));
↓
finally undefined
-
path.parse
っていうメソッドがある。戻り値はParsedPath
というオブジェクトになる。要するに与えられたパス文字列を"/"
でsplitしていい感じにしてくれるメソッドのようだ。JavaのPathに似てる。気がする。const path = require('path'); const pathStr = '/tmp/work/hogehoge/hugahuga/hagahaga.txt'; const parsed = path.parse(pathStr); console.log('base',parsed.base); console.log('dir',parsed.dir); console.log('ext',parsed.ext); console.log('name',parsed.name); console.log('root',parsed.root);
↓
# node path-parse.js base hagahaga.txt dir /tmp/work/hogehoge/hugahuga ext .txt name hagahaga root /
-
モジュールを
import
で使う場合、package.json
に"type": "module"
の記述が必要である。これがないとrequre
で読み込むことになる。
Superbadge について
Superbadgeはこれだが、前段に5つのTrailheadがあり、まずこれらをクリアしないとSuperbadgeに挑戦できない。また、特にSuperbadgeに関しては、ここに書かれている通り、ソリューションの共有が禁止されているので、ここでは何も言えない。頑張りましょう。って感じです。ひとついうなら、これは正直、上で取り上げている「JavaScript デベロッパー多肢選択試験」より 遥かに難易度が高かった。 個人的にSalesforceの開発に慣れていないこと、全編英語だということ(※終わってから気づいたんだけど有志による日本語訳が提供されている。)もあって、実際に「こういう要件を満たすようにコードを書け」「そうやってつくったLightning Web Componentを使ってLightning Appをつくれ」というのが非常に難しい。Superbadge前提条件のTrailheadでLightning Web ComponentやApex Class、Lightning App Page等の「基礎」は学べるが、Superbadgeで求められるコードの実装スキルやLightning App構築のスキルレベルは、その「基礎」のレベルをはるかに凌駕しており、Javascriptは趣味でちょっと開発で使うくらい・Web Componentの知識ほぼ皆無・Salesforceはガチド素人・という人には大分つらいものがあった。正直試験さえクリアしたらあとはTrailheadだしなんとかなるっしょwwとかナメてかかってたのは本当に反省している。体感、 これは試験の100倍ヤバイ。 当社比。個人の意見ともいう。
なお、Superbadge自体とは直接的になんの関係もない部分でちょっと詰まったところがあったので、それは後学のために書いておきたい。
- そもそもの話として、PlaygroundのSalesforceにどうやってログインするんだ??っていうところで詰まったのだが(Salesforceに関してはド素人なのでこういうところをまるで知らないのだ)、これはApp Launcherから「Playground Starter」っていうのを選択すると「Get Your Login Credential」というタブがあるので、そこでログインに必要なユーザー名(矢印のところ)が確認できる。パスワードは不明なので「Reset My Password」ボタンを押してリセット用のメールを送信して、自分で設定する。これでユーザー名とパスワードをまず把握する。
加えて、「Setup」から「My Domain」に遷移し、ログイン先のドメインを把握する。これはMy Domainの画面の矢印の部分で確認できる。
- Trailの途中でLightning App Builderというのを探すことになるが、これは「Setup」側にある。Setupに遷移後Quick Filterで「Lightning App Builder」と入力すれば出てくる。(常識??)
おわりに
というわけでSalesforce Certified Javascript Developerになったようだ。ただし冒頭書いた通りで、Javascriptのプログラミング言語としての技能を確かめたかったという目的が大きく、それをSalesforceの開発に活用する部分は、 一応クリアはしたものの やはり専門ではないということで全然ダメダメである。機会と時間があればここはもう少し深堀していきたいところだ。(って言ってると大体やんないんだけどね)