Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/Objective-Arts/lens-dist --skill functional명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
SOC 직업 분류 기준
| name | functional |
| description | Functional JS elegance |
Applying the design philosophy of Jeremy Ashkenas (Backbone.js, Underscore.js, CoffeeScript) to JavaScript library and utility development. Use this when writing JavaScript utilities, designing APIs, building small libraries, or refactoring code toward functional elegance. Auto-invokes for .js files involving utility functions, library design, collection manipulation, or API surface design. Not for framework-heavy code (React, Angular), build tooling, or Node.js server infrastructure.
Readable over clever. Code is read far more than written. Optimize for the reader who encounters your code six months from now.
Small, focused functions. Each function does one thing. Name it for what it does. If the name is awkward, the function does too much.
Functional foundations. Prefer map, filter, reduce over loops. Treat data as immutable. Return new values rather than mutating.
Minimal API surface. The best library is the smallest one that solves the problem. Every public method is a promise to maintain.
Convention over configuration. Establish sensible defaults. Let users override when needed, not require configuration upfront.
// Transform collections, not items
const getActiveUserEmails = (users) =>
users
.filter(user => user.active)
.map(user => user.email);
// Not this - imperative, mutable
const getActiveUserEmails = (users) => {
const emails = [];
for (let i = 0; i < users.length; i++) {
if (users[i].active) {
emails.push(users[i].email);
}
}
return emails;
};
// Loose coupling through events
class Model {
constructor() {
this._events = {};
this._attributes = {};
}
set(key, value) {
const prev = this._attributes[key];
this._attributes[key] = value;
if (prev !== value) {
this.trigger('change', key, value, prev);
this.trigger(`change:${key}`, value, prev);
}
return this;
}
on(event, callback) {
(this._events[event] ||= []).push(callback);
return this;
}
trigger(event, ...args) {
(this._events[event] || []).forEach(cb => cb(...args));
return this;
}
}
// Everything returns a value
const classify = (score) =>
score >= 90 ? 'A' :
score >= 80 ? 'B' :
score >= 70 ? 'C' :
score >= 60 ? 'D' : 'F';
// Destructuring for clarity
const formatUser = ({ name, email, role = 'member' }) =>
`${name} <${email}> (${role})`;
// Default parameters over conditionals
const paginate = (items, page = 1, perPage = 10) =>
items.slice((page - 1) * perPage, page * perPage);
class Query {
constructor(data) {
this._data = data;
this._filters = [];
this._sort = null;
this._limit = null;
}
where(predicate) {
this._filters.push(predicate);
return this; // Always return this for chaining
}
sortBy(key, direction = 'asc') {
this._sort = { key, direction };
return this;
}
limit(n) {
this._limit = n;
return this;
}
value() {
let result = this._data;
for (const filter of this._filters) {
result = result.filter(filter);
}
if (this._sort) {
const { key, direction } = .;
mult = direction === ? : -;
result = [...result].( a[key] > b[key] ? mult : -mult);
}
(.) {
result = result.(, .);
}
result;
}
}
topUsers = (users)
.( u.)
.( u. > )
.(, )
.()
.();
// Good: defaults that work, options that customize
const fetch = (url, options = {}) => {
const config = {
method: 'GET',
headers: { 'Content-Type': 'application/json' },
timeout: 5000,
retries: 3,
...options
};
// ...
};
// Most calls are simple
fetch('/api/users');
// Complex when needed
fetch('/api/users', { method: 'POST', body: data });
// Predicates start with is/has/can
const isEmpty = (arr) => arr.length === 0;
const hasChildren = (node) => node.children?.length > 0;
const canEdit = (user, doc) => doc.ownerId === user.id;
// Transformers are verbs or "to" + noun
const slugify = (str) => str.toLowerCase().replace(/\s+/g, '-');
const toArray = (value) => Array.isArray(value) ? value : [value];
// Getters match property names
const getName = (obj) => obj.name;
const getById = (id) => (arr) => arr.find(x => x.id === id);
// Pipe: left-to-right composition
const pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x);
// Usage
const processUser = pipe(
validateEmail,
normalizePhone,
hashPassword,
saveToDatabase
);
// Compose: right-to-left (mathematical order)
const compose = (...fns) => (x) => fns.reduceRight((v, f) => f(v), x);
const memoize = (fn) => {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (!cache.has(key)) {
cache.set(key, fn(...args));
}
return cache.get(key);
};
};
const debounce = (fn, wait) => {
let timeout;
return (...args) => {
clearTimeout(timeout);
timeout = setTimeout(() => fn(...args), wait);
};
};
const throttle = (fn, wait) => {
let lastCall = 0;
return (...args) => {
const now = Date.now();
if (now - lastCall >= wait) {
lastCall = now;
fn(...args);
}
};
};
const partial = (fn, ...presetArgs) =>
(...laterArgs) => fn(...presetArgs, ...laterArgs);
// Usage
const greet = (greeting, name) => `${greeting}, ${name}!`;
const sayHello = partial(greet, 'Hello');
sayHello('World'); // "Hello, World!"
When reviewing JavaScript utilities and libraries:
thismap/filter/reduce over imperative loopsfind/some/every when appropriatethis or arguments needed?.) and nullish coalescing (??)// Bad: AbstractFactoryProviderManager
class UserServiceFactoryProvider {
createUserServiceFactory() {
return new UserServiceFactory();
}
}
// Good: just a function
const createUser = (data) => ({ id: uuid(), ...data, createdAt: Date.now() });
// Bad: abstracting on first use
const makeAdder = (x) => (y) => x + y;
const add5 = makeAdder(5);
add5(3); // Just use 5 + 3
// Good: abstract when you see the pattern repeated
// (wait until you need it in 3+ places)
// Bad: over-configured
fetch({ url: '/users', method: 'GET', format: 'json' });
// Good: simple API, options when needed
fetch('/users');
fetch('/users', { method: 'POST' });
Use for:
Skip for: