The Art of Writing Code that Looks Good
Brujo Benavides, @elbrujohalcon
Insufferable Code Reviewer
Macro Hater
Amateur AST Interpreter
Already Too Old for AI
OH, MY GOD!! Who wrote this utterly incomprehensible piece of…
…code??!?!.
– Brujo Benavides,
many times each month
Of course! It was me!
– Brujo Benavides,
many times each month, too
up_to(I, Top) when Top >= I ->
I rem 3 == 0 andalso io:format("fizz"),
[io:format("buzz") || I rem 5 == 0],
catch if I rem 3 /= 0 andalso I rem 5 /= 0 ->
io:format("~p", [I])
end,
io:format(" "),
up_to(I + 1, Top);
up_to(I, Top) when Top < I ->
io:format("~n").up_to(I, Top) when Top >= I ->
case I of
I when I rem 3 == 0 -> io:format("fizz");
_ -> noop
end,
case I of
I when I rem 5 == 0 ->
io:format("buzz");
_ -> noop
end,
case I of
I when I rem 3 /= 0 andalso I rem 5 /= 0 ->
io:format("~p", [I]);
_ -> noop
end,
io:format(" "),
up_to(I + 1, Top);
up_to(I, Top) when Top < I ->
io:format("~n").up_to(I, Top) when Top >= I ->
case {I rem 3, I rem 5} of
{0, 0} -> io:format("fizzbuzz");
{0, _} -> io:format("fizz");
{_, 0} -> io:format("buzz");
{_, _} -> io:format("~p", [I])
end,
io:format(" "),
up_to(I + 1, Top);
up_to(I, Top) when Top < I ->
io:format("~n").up_to(I, Top) when Top >= I ->
print(I),
io:format(" "),
up_to(I + 1, Top);
up_to(I, Top) when Top < I ->
io:format("~n").
print(I) when I rem 3 == 0, I rem 5 == 0 ->
io:format("fizzbuzz");
print(I) when I rem 3 == 0 ->
io:format("fizz");
print(I) when I rem 5 == 0 ->
io:format("buzz");
print(I) ->
io:format("~p", [I]).-export([one/1, two/1, three/1, four/1, …]).
-export([all/0]).
-export([init_per_suite/1, end_per_suite/1, …]).
…
all() -> [one, two, three, four, …].
…
one(_) -> ….-compile([export_all]).
…
all() -> [one, two, three, four, …].
…
one(_) -> ….-define(EXCLUDED_FUNS,
[module_info, all, init_per_suite,
end_per_suite, an_auxiliary_function]).
…
all() ->
Exports = ?MODULE:module_info(exports),
[F || {F, _} <- Exports
, not lists:member(F, ?EXCLUDED_FUNS)].
all() ->
lists:filtermap(
fun ({module_info,_}) -> false;
({all,_}) -> false;
({init_per_suite,1}) -> false;
({end_per_suite,1}) -> false;
%% …many many more… %%
({FName,1}) -> {true, FName};
({_,_}) -> false
end, ?MODULE:module_info(exports)).-compile({parse_transform, my_ct_helper}).-module(my_ct_helper).
…
parse_transform(Forms,_Options) ->
FormsInfo =
erl_syntax_lib:analyze_forms(Forms),
Functions =
proplists:get_value(
functions, FormsInfo, []),
OrigExports =
proplists:get_value(exports, FormsInfo, []),
% …a lot more cryptic code that adds all/0… %
Out.define Beauty {
...
}Examples:
Not much to explain here, right? 😎
Not much to explain here, right? 😎
According to our coding guidelines (Particularly #123), we don't use
parse_transforms to inject new functions in our modules. Please just write theall/0function explicitly. Thanks.
– A Reviewer,
from A Place with Guidelines
To create code that's as beautiful as possible…
To create code that's as beautiful as possible…
@elbrujohalcon - about.me/elbrujohalcon
As an open-source maintainer of many developer tools, let me talk about my recent experiences in this area…
Over the last 10 years (or more), working at different companies (like Inaka, ESL, and NextRoll), with multiple friends and colleagues, we've built a linter, a formatter, a better XRef runner, an oxbow code detector, a spellchecker, a dependency updater, a better interface for TypER, a comprehensive public set of guidelines, …
As an open-source maintainer of many developer tools, let me talk about my recent experiences in this area…
Over the last 10 years (or more), working at different companies (like Inaka, ESL, and NextRoll), with multiple friends and colleagues, we've built a linter, a formatter, a better XRef runner, an oxbow code detector, a spellchecker, a dependency updater, a better interface for TypER, a comprehensive public set of guidelines, …
Recently, WhatsApp is building all of these tools from scratch, again…
I found two main reasons…
I found two main reasons…
Development tools should be actively maintained by the OTP Team and using them should be proactively recommended to all developers.
Development tools should be actively maintained by the OTP Team and using them should be proactively recommended to all developers.
Development tools should be actively maintained by the OTP Team and using them should be proactively recommended to all developers.