Chromium版EdgeのmacOS版がリリースされました。
アメリカにあるMicrosoft社が5月20日にmacOSに対応したChromium版Edgeをリリースしました。
こちらのページでダウンロードもできます。 https://www.microsoftedgeinsider.com/en-us/?form=MO12FS&OCID=MO12FS
mac版のedgeが出てきたことによって何が起こるか
まず、利用者にとっては利用するブラウザは何でもよく、言ってしまえば検索ができれば問題ないでしょう。
問題となるのは、開発者にとってどうなるかです。
これまでフロントエンドの開発者が対応しなければならないブラウザが少なくとも5つありました。
これらのブラウザに対応するために多大な苦労がありました。 あるブラウザではバグがいつまでも残っていて、いつまでも対応し続けなければならなかったり。どのブラウザとは言いませんが、苦労がありました。
そこにmac版のEdgeが追加されます。
中身はChromiumで動いているのでスタイルはGoogle Crome
と同じように開発が可能でしょう。
ただし、mac版と言っていることから分かる通り、Touch Bar
に対応しています。
これによって、ブラウザ上での操作が可能で、もしかするとそれに対応する必要が出てくるのではないかと考えています。
例えば、Electron
を利用したデスクトップアプリケーションではTouchBar Api
が提供されています。
https://electronjs.org/docs/api/touch-bar
これと同じように対応する必要が出てくるかもしれません。
(´・∀・`)
┐(´д`)┌
まぁ、頑張るしかないですよね。
現在のトレンドを比較してみました
Google Trendを利用してすべての国でフィルタリングしてトレンドを比較しました。
検索には以下の単語を利用しています。
- Google Chrome
- Firefox
- Edge
- IE
- Safari
それぞれの色に対応させるとこのようになります。
- Google Chrome (青)
- Firefox (赤)
- Edge (黄)
- IE (緑)
- Safari (紫)
結果を見ると、IEが一番低い値となっています。 順番にするとこのようになります。
chromeが1番で、IEが最下位なのは予想通りですが、edgeが2番なのはびっくりしました。
別の単語での検索も入っているのでこれが正しいとは限りませんが、Chromium Edge
という検索が2050%上昇していたのがわかります。
世界的にも注目されているようです。
これからの動向にも注目したいです。
最後に
mac版でedgeを出してもChromium
ベースなら、Google Chrome
を使えばいいのでは?と思ってしまいます。
macにはSafariも入っていますし、わざわざ出す理由は無いと思うのですが。。。
macで利用可能なmicrosoft製ブラウザはなかったので出したのでしょうか。
これによって何が変わっていくのか。これからの動きに注目したいです。
エンジニアになるためには何をすればよいか
概要
プログラミングを勉強する場合どのように勉強すると良いか、自分の経験から記事にしました。 これから勉強する方の一つの道標として役立てればと思います。
※ この記事は過去ブログを作った際に載せていた内容を書き直しています。
最初に
この記事ではプログラミングを学ぼうと考えている人たちで、最初に「何から勉強すれば良いか」迷っている方の役に立てれたらと考えて書いています。 私自身のプログラミングを勉強してきた流れをもとにして、それを参考にしていただけたら幸いです。
少なくとも一人はこの方法でエンジニアになって、画像のようなブログを手作りできるぐらいにはなれると思います。
(維持コストがかかるのでブログは廃止しています。)
少々見苦しくあるのですが、このようなモノを作りました。
本題ですが、以下の流れでどのように勉強してきたのかを書いていきたいと思います。 1. 最初にプログラミングを勉強し始めたのは? 2. どのような勉強をしたのか 3. 次にやったこと 4. 社会に出てから 5. まとめ
最初にプログラミングを勉強し始めたのはいつ?
私が最初にプログラムに触ったのは大学1年の頃でした。
記事を書いている段階で25歳なので、今から7年ぐらい前の18歳ぐらいの頃です。
当時の私は高校のときにhtml
やcss
に触って、「わけわからん」と理解できずに手放したぐらいの知識量です。
おそらく、今始めて勉強を始めようと考えている方と同じぐらいの知識量と経験だと思います。
java
とjavascript
の違いがわからないぐらいのレベルと言えばわかるでしょうか?
始めたばかりの人は皆そのくらいです。
どのような勉強をしたのか
初めて触った言語は大学1年生のときに講義で勉強したjava
です。
そのときはjava
の基礎構文を勉強しました。
はっきり言ってしまえば、本の内容をそのままやるだけの講義でした。 本は「やさしいjava」シリーズを使って勉強していました。
初めてやることなので、全然わかりませんでした。 プログラムを上から下に読むということもわかっていないレベルです。(冗談抜きです)
for文
がどのように動くのかわからなかったですし、以下のような2重のfor文なんて意味不明でした。
i++
って何?とか聞いていたと思います。
for (var i = 0; i < 3; i++) { for (var j = 0; j < 3; j++) { System.out.println("i=" + i + ". j=" + j); } }
その時、「わからないです」と聞いたら笑われたので自分で解決する癖がついたのだと思います。
そんな未熟者の私が一番つらかったことがあります。 講義の終わり頃に課題を出されて完成できなかった場合に帰れなかったことです。 あれはいい経験でした。
今になって思えば、エンジニアとしての本質なのでしょう。 社会でも締め切りが決められていて、それに遵守しなければならなくて、終わらないと帰れないですから。
次にやったこと
そこからは講義はほとんど変わりませんでした。
学ぶ言語がjava
からC言語
に変わったり、java
を使ってコンパイラを作ったりと現状を考えるとなんの役にも立たない知識です。
こういったことを勉強して私が思ったことは「将来が詰む」です。
業務的な知識がなく、他と同じ知識量と未経験の若造ではどの企業にも雇ってもらえないと考えたからです。
なので最低でも自分自身で課題を解決することができ、なにか作って実績を作ろうと考えました。
まずは落ちものパズルの大定番である「テトリス」と「ぷよ○よ」作って、その後に「オセロ」を作りました。
これらで得られた経験は、html
、css
、javascript
を使ってアプリケーションを作れたということです。
サーバを絡めた経験はなかったのですが、「自分は作れる」という自信を得ることができました。
当時は同じような行動をしている人が周りにはいなくて、研究室に入ってから自分以上のレベルの人に会ってますます焦ったのを覚えています。
そこからは遊びに行くとかすることはなく、ひたすらプログラムを書いていました。
社会に出てから
大学時代にいくつかの実績を作って、それを面接時に見せるということをやっていたら入社できました。
早めに内定がでたので、そこで決めてのんびりしていたのを覚えています。
やはり、客観的にみてわかるだけの実績があるとわかりやすいのだと思います。 実績がない場合はコミュニケーション能力をアピールしたり、スケジュール管理ができるといったことをアピールすると良いでしょう。
業務を行うことになってから、社内のエンジニアとして課題解決を行っていました。 詳細は書けないのですが、「問題点」を挙げて、その「解決方法」を考えて、「実行」するという業務です。
最初は「勉強するため」や、「経験を得るため」という理由から働いていたのですが、今は違います。
会社で得られる経験なんて、たかが知れています。 得られるのものは「人脈」と「給料」です。
なにか実装したりすれば、その実装についての知識は得られるでしょうが、それは個人でやっても同じです。 むしろ、個人でやったほうが最初から最後までできるのですべての経験を得られるでしょう。
まとめ
エンジニアになった流れは、その他多くの方と同じだと思います。
なんの特徴も無いのですが、私の場合は以下の流れでエンジニアになりました。 1. 大学に入る 2. javaを勉強する 3. C言語を勉強する 4. ひたすら勉強して目に見える実績を作る
このとき、プログラミングスクールとか行かなかったですし、人に聞いたときに笑われた経験から自分で解決していました。 個人的には高いスクール料を払うより、公式ドキュメントを読んだり、お金を出してノウハウ買うのが良いと思います。
61.DjangoBasicAppsのCommentsを読んでみる
urls.pyには目新しいものがなかったのでスルーします。
urlを使ってbooksと同じように作成されていたのでスルーします。
1つだけわかったことは、view
の引数にはviews.py内のメソッドを入れるということ。
views.pyを確認する
コメント時の日付をバリデーションする方法を見つけました。
get_object_or_404
というショートカットが用意されていることにも気が付きました。
このショートカットは便利そうですね。request.userは認証していない場合にNoneになるはずですから、404になる。
djangorestframeworkを使う場合は、serializerを使ったり、IsAuthenticatedを使うことで対応ができると思います。
認証に関しても
DELTA = datetime.datetime.now() - datetime.timedelta( minutes=getattr(settings, 'COMMENT_ALTERATION_TIME_LIMIT', 15) ) def comment_edit(request, object_id, template_name='comments/edit.html'): comment = get_object_or_404(Comment, pk=object_id, user=request.user) if DELTA > comment.submit_date: return comment_error(request)
フォームを使ったバリデーションです。
if request.method == 'POST': form = CommentForm(request.POST, instance=comment) if form.is_valid(): form.save() return redirect(request, comment.content_object)
CommentFormは↓のようになっています
class CommentForm(ModelForm): class Meta: model = Comment exclude = ('content_type', 'object_pk', 'site', 'user', 'is_public', 'user_name', 'user_email', 'user_url', 'submit_date', 'ip_address', 'is_removed',)
個人的には、formは最終的に見た目をカスタマイズすることになるので、Formからタグは作成しないようにしています。
バリデーション目的のみ使うのが良いと思います。
バリデーションのみ行う場合、↓cerberusというライブラリがあるので参考にしてみてください。
http://docs.python-cerberus.org/en/stable/
load i18nという翻訳tag
template内に↓のような記述がありました。
{% load i18n %}
このタグを使うと、翻訳タグを使うことができます。
{% trans "Text" %}
実際に使う際は↓のドキュメントを参考にするとよい
60.DjangoBasicAppsという数年前のプロジェクトのBooksを読んでみる
DjangoBasicAppsのリポジトリは↓です。
https://github.com/nathanborror/django-basic-apps
その中にあるBooksを読んで、Djangoの書き方を確認したいと思いました。
https://github.com/nathanborror/django-basic-apps/tree/master/basic/books
views.pyが見当たらない
見当たらないです。
views.pyが見つからないとか…なんででしょうか。
views.pyがないので、urls.pyを確認してみる
object_detail
というのがどこにあるのかみつかりませんでした。
url(r'^genres/(?P<slug>[-\w]+)/$', view='object_detail', kwargs=genre_list, name='book_genre_detail', ),
genre_list自体は↓のように作成されていた。
genre_list = { 'queryset': Genre.objects.all(), }
この書き方はあまり使わないですね。
これだとページング処理が入らないし、データを固定にするならtemplateにそのまま書いてもよいです。
views.pyがないので拡張しづらいですね。
それから、as_viewがなくてなぜ大丈夫なのかわかりません。
templateを確認する
templateの書き方を見れるのは嬉しいですね。
これまでどうやって書けばよいのか手探りだったのでわかった気がします。
baseとなるtemplateは↓です。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>{% block title %}{% endblock %}</title> </head> <body id="{% block body_id %}{% endblock %}" class="{% block body_class %}{% endblock %}"> <div id="body"> {% block body %} <div class="content_title"> {% block content_title %}{% endblock %} </div> <div class="content"> {% block content %}{% endblock %} </div> {% endblock %} </div> </body> </html>
blockは4つ定義されています。
- title
- body
- content_title
- content
bookのbaseは↓です
{% extends "base.html" %} {% block body_class %}books{% endblock %}
book_list.htmlは↓です
{% extends "books/base_books.html" %} {% block title %}Books{% endblock %} {% block content_title %} <h2>Books</h2> {% include "books/_nav.html" %} {% endblock %} {% block content %} <table class="book_table"> <tr> <th>Title</th> <th>Authors</th> <th>Progress</th> </tr> {% for book in object_list %} <tr> <td class="title"><a href="{{ book.get_absolute_url }}">{{ book.title }}{% if book.prefix %}, {{ book.prefix }}{% endif %}</a></td> <td class="authors">{% for author in book.authors.all %}<a href="{{ author.get_absolute_url }}">{{ author.full_name }}</a>{% if not forloop.last %}, {% endif %}{% endfor %}</td> <td class="publisher"><a href="{{ book.publisher.get_absolute_url }}">{{ book.publisher.full_title }}</a></td> </tr> {% endfor %} </table> {% endblock %}
content_titleの中にincludeがあります。
includeが使えるのは初めて知りました。
jinja2でもincludeを使えるので当たり前といえば当たり前なんですが。。。
_nav.htmlは↓のようになっていました。
<div id="section_nav"> <ul> <li class="music"><a href="{% url music_index %}">Music</a></li> <li class="movies"><a href="{% url movie_list %}">Movies</a></li> <li class="books"><a href="{% url book_list %}">Books</a> <ul> <li class="genres"><a href="{% url book_genre_list %}">Genres</a></li> <li class="publishers"><a href="{% url book_publisher_list %}">Publishers</a></li> </ul> </li> </ul> </div>
階層構造でtemplateを表現するとこのようになります。
- base.html
- book_list.html
- _nav.html
- book_list.html
こうやって見るとずいぶんと効率的に書けるとわかります。
ただし、htmlのデザインを書いて、共通化できる箇所を考え、コーディングする技術が必要です。
頻繁にデザインが変わる際は共通化せずに実装し、最終的にリファクタリングする段階で共通化するのが良いでしょう。
headやfooter部分、ナビゲーション部分を共通化するのが良いと思いました。
59.DjangoのでTwythonを使ったOAuthのサンプルを読んでみた。
参考にしたプロジェクトは↓です。
https://github.com/ryanmcgrath/twython-django
Twythonを使ってTwitterのAPIを利用することができるようです。
An example Django application to showcase how to use OAuth with Twitter in Django using Twython.
と書かれていたので、OAuthの実装がわかるかな?と思って読んでみようと思いました。
それから、自分で実装できるようになると応用が効くと考えたからです。googleの認証にも使えそうですし。
requirements.txtがリポジトリ内に見当たらなかったので不満です。
なんで用意されていないのでしょうか。
setup.pyを見てみると↓のように書かれていました。
install_requires=['twython>=3.1.0', 'django'],
小さなプロジェクトというこのがわかります。
ちなみに、twythonのリンクは↓です。
https://twython.readthedocs.io/en/latest/usage/install.html
views.py
クラスベースの書き方ではないのですが、どうなのでしょうか。
良いか悪いかわかりませんが、こういうやり方もあるっていうのはドキュメントを読んで理解しているので良しとします。
https://github.com/ryanmcgrath/twython-django/blob/master/twython_django_oauth/views.py
OAuthの開始時に必要なcallbackや、認証後のurlを設定している箇所です。
# Request an authorization url to send the user to... callback_url = request.build_absolute_uri(reverse('twython_django_oauth.views.thanks')) auth_props = twitter.get_authentication_tokens(callback_url) # Then send them over there, durh. request.session['request_token'] = auth_props request.session['next_url'] = request.GET.get('next',None) return HttpResponseRedirect(auth_props['auth_url'])
認証後にTwitterApiを使うところまで
コードを読んだ感じだと↓の順番で処理をすると良いみたいです。
- sessionからoauth_token, oauth_token_secretを取得する。
- twythonを使ってTwitterAPIを利用するための準備をする
- authorized_tokenをtwitterAPIを使って取得する
oauth_token = request.session['request_token']['oauth_token'] oauth_token_secret = request.session['request_token']['oauth_token_secret'] twitter = Twython(settings.TWITTER_KEY, settings.TWITTER_SECRET, oauth_token, oauth_token_secret) # Retrieve the tokens we want... authorized_tokens = twitter.get_authorized_tokens(request.GET['oauth_verifier'])
- authorized_tokenからscreen_nameを取得して、テーブル上にユーザーが登録されているか確認する
- 登録されている場合はuserオブジェクトを取得する
- 登録されていないなら、データを追加する
try: user = User.objects.get(username=authorized_tokens['screen_name']) except User.DoesNotExist: # We mock a creation here; no email, password is just the token, etc. user = User.objects.create_user(authorized_tokens['screen_name'], "fjdsfn@jfndjfn.com", authorized_tokens['oauth_token_secret'])
DBに保存するのはoauth_token_secretで良いみたいです。
social-auth-app-django
を使ったときは以下のデータがDB上に保存されます。
(一部マスキングしています)
{ "auth_time": 1542545735, "id": 97379597xxxxxxxx620, "access_token": { "oauth_token": "97379597xxxxxxxx620-Kn5iKEyyyyyyybzfc1QuFmyKt", "oauth_token_secret": "0TBySf6hjiSKqHnog4Qm6xZyyyyyyyyykmDaaos3CPxkLcn", "user_id": "kdkdiem9597xxxxxxxx620", "screen_name": "xxxxxxxxx" } }
サンプルではoauth_tokenは保存していなかったので、どちらが正なのか判断できません。
Twythonのインスタンスを作成する際にoauth_tokenが必要かなと思うのですが、、、
ログイン時のsessionに含まれていると考えると必須ではないのかもしれません。
もしかすると、↓のコードでsaveとあるので、oauth_tokenが保存されているのかもしれません。(動かしていないのでわからないです)
profile = TwitterProfile() profile.user = user profile.oauth_token = authorized_tokens['oauth_token'] profile.oauth_secret = authorized_tokens['oauth_token_secret'] profile.save()
タイムラインを表示する
タイムラインを表示します。
def user_timeline(request): """An example view with Twython/OAuth hooks/calls to fetch data about the user in question.""" user = request.user.twitterprofile twitter = Twython(settings.TWITTER_KEY, settings.TWITTER_SECRET, user.oauth_token, user.oauth_secret) user_tweets = twitter.get_home_timeline() return render_to_response('tweets.html', {'tweets': user_tweets})
でもこれって、ログインしてない場合どうなるのでしょうか。
request.user.twitterprofileがNoneになるとエラーになるのですが、、、
ちなみに、htmlはこのようになっていました。
{% for tweet in tweets %} {{ tweet.text }} {% endfor %}
Djangoのサンプルを覗いて使い方を勉強してみたときのメモ
django-realworld-example-appを参考にする
このプロジェクトは一番最初に参考にしたものです。
Djangoのバージョンが1.10.0と古い(記事を書いている段階での最新は2.1.5が最新)です。
https://github.com/gothinkster/django-realworld-example-app
このプロジェクトで学べること
- ForeignKeyフィールドの作り方
author = models.ForeignKey( 'profiles.Profile', on_delete=models.CASCADE, related_name='articles' )
- serializerクラスの使い方
- method_nameというのを知りました。
- SerializerMethodFieldを使ったget_xxxの方法を知りました。
updatedAt = serializers.SerializerMethodField(method_name='get_updated_at')
favorited = serializers.SerializerMethodField() def get_favorited(self, instance): request = self.context.get('request', None) if request is None: return False if not request.user.is_authenticated(): return False return request.user.profile.has_favorited(instance) # ↓が実行されます # def has_favorited(self, article): # """Returns True if we have favorited `article`; else False.""" # return self.favorites.filter(pk=article.pk).exists()
- models.pyの作り方
- 多対多のリレーションの書き方. xxx_by
- orderingを指定したデフォルトのソード方法
favorites = models.ManyToManyField( 'articles.Article', related_name='favorited_by' )
ordering = ['-created_at', '-updated_at']
- urls.pyの階層構造
url(r'^api/', include('conduit.apps.profiles.urls', namespace='profiles')),
- jsonレスポンスの拡張方法
- ページネーションを想定したレスポンス
class ConduitJSONRenderer(JSONRenderer): charset = 'utf-8' object_label = 'object' pagination_object_label = 'objects' pagination_object_count = 'count' def render(self, data, media_type=None, renderer_context=None): if data.get('results', None) is not None: return json.dumps({ self.pagination_object_label: data['results'], self.pagination_count_label: data['count'] }) # If the view throws an error (such as the user can't be authenticated # or something similar), `data` will contain an `errors` key. We want # the default JSONRenderer to handle rendering errors, so we need to # check for this case. elif data.get('errors', None) is not None: return super(ConduitJSONRenderer, self).render(data) else: return json.dumps({ self.object_label: data })
Djangoの管理画面でBootStrap臭がひどいので消すことにした。
管理画面のBootStrap臭がひどいので消すことにしました。
アドミン機能はとても便利です。
DB内のデータをモデルを使ってCRUD操作できるので、編集が簡単です。
でも、個人的にはDB内のデータを操作する際は、専用のクライアントツールを使いたい派です。
postgresqlならPSequelを使うし、mysqlならworkbenchを使っています。
このどちらも管理画面を使用するよりも便利なので、あまり管理画面を使用しないのです。
あと、リリースしたあとに/adminを開いたときの残念感が嫌いです。
(urls.pyを修正すれば分からなくできるかもしれませんが、、、)
Bootstrap臭がすごいですよね、あのページ。あれはいらないです。
初期設定から管理画面に関する箇所を消す
settings.pyを編集します。
このページを見てみると、django.contrib.adminが管理画面に関するappというのがわかります。
https://docs.djangoproject.com/es/2.0/ref/contrib/admin/
また、管理画面は4つほど依存性を持っているようです。
この4つは管理画面で使用されているぐらいなので、アプリケーション開発に役立つ機能があると予想できます。
(実際使えます。)
というわけで、↓が修正するpythonファイルです。
INSTALLED_APPS = [ # 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ]
# from django.contrib import admin from django.urls import path urlpatterns = [ # path('admin/', admin.site.urls), ]
migrateを実行します。
django.contrib.adminをコメントアウトしてmigrateを実行した結果です。
List of relations Schema | Name | Type | Owner --------+-----------------------------------+----------+-------- public | auth_group | table | xxxxxx public | auth_group_id_seq | sequence | xxxxxx public | auth_group_permissions | table | xxxxxx public | auth_group_permissions_id_seq | sequence | xxxxxx public | auth_permission | table | xxxxxx public | auth_permission_id_seq | sequence | xxxxxx public | auth_user | table | xxxxxx public | auth_user_groups | table | xxxxxx public | auth_user_groups_id_seq | sequence | xxxxxx public | auth_user_id_seq | sequence | xxxxxx public | auth_user_user_permissions | table | xxxxxx public | auth_user_user_permissions_id_seq | sequence | xxxxxx public | django_content_type | table | xxxxxx public | django_content_type_id_seq | sequence | xxxxxx public | django_migrations | table | xxxxxx public | django_migrations_id_seq | sequence | xxxxxx public | django_session | table | xxxxxx
django.contrib.adminをコメントアウトしないでmigrateした結果です。
django_admin_logが消えているのが確認できます。
というかこれぐらいしか消えません。
List of relations Schema | Name | Type | Owner --------+-----------------------------------+----------+-------- public | auth_group | table | xxxxxx public | auth_group_id_seq | sequence | xxxxxx public | auth_group_permissions | table | xxxxxx public | auth_group_permissions_id_seq | sequence | xxxxxx public | auth_permission | table | xxxxxx public | auth_permission_id_seq | sequence | xxxxxx public | auth_user | table | xxxxxx public | auth_user_groups | table | xxxxxx public | auth_user_groups_id_seq | sequence | xxxxxx public | auth_user_id_seq | sequence | xxxxxx public | auth_user_user_permissions | table | xxxxxx public | auth_user_user_permissions_id_seq | sequence | xxxxxx public | django_admin_log | table | xxxxxx public | django_admin_log_id_seq | sequence | xxxxxx public | django_content_type | table | xxxxxx public | django_content_type_id_seq | sequence | xxxxxx public | django_migrations | table | xxxxxx public | django_migrations_id_seq | sequence | xxxxxx public | django_session | table | xxxxxx
admin以外はすべて便利に使えるものなので、残すのが良いと思いました。